]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2008 01:43:10 +0000 (17:43 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2008 01:43:10 +0000 (17:43 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (104 commits)
  [SCSI] fcoe: fix configuration problems
  [SCSI] cxgb3i: fix select/depend problem
  [SCSI] fcoe: fix incorrect use of struct module
  [SCSI] cxgb3i: remove use of skb->sp
  [SCSI] cxgb3i: Add cxgb3i iSCSI driver.
  [SCSI] zfcp: Remove unnecessary warning message
  [SCSI] zfcp: Add support for unchained FSF requests
  [SCSI] zfcp: Remove busid macro
  [SCSI] zfcp: remove DID_DID flag
  [SCSI] zfcp: Simplify mask lookups for incoming RSCNs
  [SCSI] zfcp: Remove initial device data from zfcp_data
  [SCSI] zfcp: fix compile warning
  [SCSI] zfcp: Remove adapter list
  [SCSI] zfcp: Simplify SBAL allocation to fix sparse warnings
  [SCSI] zfcp: register with SCSI layer on ccw registration
  [SCSI] zfcp: Fix message line break
  [SCSI] qla2xxx: changes in multiq code
  [SCSI] eata: fix the data buffer accessors conversion regression
  [SCSI] ibmvfc: Improve async event handling
  [SCSI] lpfc : correct printk types on PPC compiles
  ...

1777 files changed:
Documentation/RCU/00-INDEX
Documentation/RCU/trace.txt [new file with mode: 0644]
Documentation/arm/pxa/mfp.txt [new file with mode: 0644]
Documentation/block/biodoc.txt
Documentation/dvb/technisat.txt [new file with mode: 0644]
Documentation/fb/pxafb.txt
Documentation/lguest/lguest.c
Documentation/lockstat.txt
Documentation/video4linux/API.html
Documentation/video4linux/CARDLIST.bttv
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/README.cx88
Documentation/video4linux/gspca.txt
Documentation/video4linux/v4l2-framework.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/io.h
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head-clps7500.S [deleted file]
arch/arm/boot/compressed/head.S
arch/arm/boot/compressed/misc.c
arch/arm/common/Kconfig
arch/arm/common/Makefile
arch/arm/common/clkdev.c [new file with mode: 0644]
arch/arm/common/locomo.c
arch/arm/common/vic.c
arch/arm/configs/eseries_pxa_defconfig
arch/arm/configs/h5000_defconfig [new file with mode: 0644]
arch/arm/configs/kirkwood_defconfig
arch/arm/configs/ks8695_defconfig
arch/arm/configs/mx31moboard_defconfig [new file with mode: 0644]
arch/arm/configs/mx31pdk_defconfig [new file with mode: 0644]
arch/arm/configs/neocore926_defconfig [new file with mode: 0644]
arch/arm/configs/netx_defconfig
arch/arm/configs/omap3_pandora_defconfig [new file with mode: 0644]
arch/arm/configs/omap_ldp_defconfig
arch/arm/configs/picotux200_defconfig
arch/arm/configs/realview-smp_defconfig
arch/arm/configs/realview_defconfig
arch/arm/configs/s3c6400_defconfig [new file with mode: 0644]
arch/arm/configs/w90p910_defconfig [new file with mode: 0644]
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/clkdev.h [new file with mode: 0644]
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/dma.h
arch/arm/include/asm/hardware/iomd.h
arch/arm/include/asm/hardware/vic.h
arch/arm/include/asm/hwcap.h
arch/arm/include/asm/io.h
arch/arm/include/asm/irq.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/mtd-xip.h
arch/arm/include/asm/page.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/setup.h
arch/arm/include/asm/smp.h
arch/arm/include/asm/string.h
arch/arm/include/asm/system.h
arch/arm/include/asm/uaccess.h
arch/arm/kernel/armksyms.c
arch/arm/kernel/ftrace.c
arch/arm/kernel/head-common.S
arch/arm/kernel/module.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kernel/thumbee.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/lib/Makefile
arch/arm/lib/memset.S
arch/arm/mach-aaec2000/Makefile
arch/arm/mach-aaec2000/clock.c [deleted file]
arch/arm/mach-aaec2000/clock.h [deleted file]
arch/arm/mach-aaec2000/core.c
arch/arm/mach-aaec2000/include/mach/dma.h [deleted file]
arch/arm/mach-aaec2000/include/mach/io.h
arch/arm/mach-aaec2000/include/mach/memory.h
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91cap9.c
arch/arm/mach-at91/at91cap9_devices.c
arch/arm/mach-at91/at91rm9200_time.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/board-neocore926.c [new file with mode: 0644]
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-usb-a9260.c
arch/arm/mach-at91/board-usb-a9263.c
arch/arm/mach-at91/include/mach/at91_pmc.h
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/dma.h [deleted file]
arch/arm/mach-at91/include/mach/io.h
arch/arm/mach-at91/include/mach/memory.h
arch/arm/mach-at91/sam9_smc.c [new file with mode: 0644]
arch/arm/mach-at91/sam9_smc.h [new file with mode: 0644]
arch/arm/mach-clps711x/include/mach/dma.h [deleted file]
arch/arm/mach-clps711x/include/mach/io.h
arch/arm/mach-clps711x/include/mach/memory.h
arch/arm/mach-clps7500/Makefile [deleted file]
arch/arm/mach-clps7500/Makefile.boot [deleted file]
arch/arm/mach-clps7500/core.c [deleted file]
arch/arm/mach-clps7500/include/mach/acornfb.h [deleted file]
arch/arm/mach-clps7500/include/mach/debug-macro.S [deleted file]
arch/arm/mach-clps7500/include/mach/dma.h [deleted file]
arch/arm/mach-clps7500/include/mach/entry-macro.S [deleted file]
arch/arm/mach-clps7500/include/mach/hardware.h [deleted file]
arch/arm/mach-clps7500/include/mach/io.h [deleted file]
arch/arm/mach-clps7500/include/mach/irq.h [deleted file]
arch/arm/mach-clps7500/include/mach/irqs.h [deleted file]
arch/arm/mach-clps7500/include/mach/memory.h [deleted file]
arch/arm/mach-clps7500/include/mach/system.h [deleted file]
arch/arm/mach-clps7500/include/mach/timex.h [deleted file]
arch/arm/mach-clps7500/include/mach/uncompress.h [deleted file]
arch/arm/mach-clps7500/include/mach/vmalloc.h [deleted file]
arch/arm/mach-davinci/include/mach/dma.h [deleted file]
arch/arm/mach-davinci/include/mach/io.h
arch/arm/mach-davinci/include/mach/memory.h
arch/arm/mach-davinci/include/mach/vmalloc.h
arch/arm/mach-ebsa110/include/mach/dma.h [deleted file]
arch/arm/mach-ebsa110/include/mach/memory.h
arch/arm/mach-ep93xx/Kconfig
arch/arm/mach-ep93xx/Makefile
arch/arm/mach-ep93xx/adssphere.c
arch/arm/mach-ep93xx/clock.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/edb9302.c
arch/arm/mach-ep93xx/edb9302a.c
arch/arm/mach-ep93xx/edb9307.c
arch/arm/mach-ep93xx/edb9307a.c [new file with mode: 0644]
arch/arm/mach-ep93xx/edb9312.c
arch/arm/mach-ep93xx/edb9315.c
arch/arm/mach-ep93xx/edb9315a.c
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-ep93xx/include/mach/dma.h [deleted file]
arch/arm/mach-ep93xx/include/mach/gpio.h
arch/arm/mach-ep93xx/include/mach/io.h
arch/arm/mach-ep93xx/include/mach/memory.h
arch/arm/mach-ep93xx/include/mach/platform.h
arch/arm/mach-ep93xx/micro9.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-footbridge/cats-hw.c
arch/arm/mach-footbridge/common.c
arch/arm/mach-footbridge/dc21285-timer.c
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-footbridge/dma.c
arch/arm/mach-footbridge/ebsa285.c
arch/arm/mach-footbridge/include/mach/hardware.h
arch/arm/mach-footbridge/include/mach/io.h
arch/arm/mach-footbridge/include/mach/isa-dma.h [moved from arch/arm/mach-footbridge/include/mach/dma.h with 91% similarity]
arch/arm/mach-footbridge/include/mach/memory.h
arch/arm/mach-footbridge/isa-irq.c
arch/arm/mach-footbridge/netwinder-hw.c
arch/arm/mach-footbridge/netwinder-leds.c
arch/arm/mach-footbridge/personal.c
arch/arm/mach-h720x/include/mach/io.h
arch/arm/mach-h720x/include/mach/isa-dma.h [moved from arch/arm/mach-h720x/include/mach/dma.h with 60% similarity]
arch/arm/mach-h720x/include/mach/memory.h
arch/arm/mach-imx/dma.c
arch/arm/mach-imx/include/mach/imx-dma.h
arch/arm/mach-imx/include/mach/imxfb.h
arch/arm/mach-imx/include/mach/io.h
arch/arm/mach-imx/include/mach/memory.h
arch/arm/mach-integrator/clock.c
arch/arm/mach-integrator/clock.h
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/impd1.c
arch/arm/mach-integrator/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-integrator/include/mach/memory.h
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-iop13xx/include/mach/dma.h [deleted file]
arch/arm/mach-iop13xx/include/mach/memory.h
arch/arm/mach-iop13xx/include/mach/timex.h
arch/arm/mach-iop32x/include/mach/dma.h [deleted file]
arch/arm/mach-iop32x/include/mach/io.h
arch/arm/mach-iop32x/include/mach/memory.h
arch/arm/mach-iop32x/include/mach/system.h
arch/arm/mach-iop32x/include/mach/timex.h
arch/arm/mach-iop33x/include/mach/dma.h [deleted file]
arch/arm/mach-iop33x/include/mach/io.h
arch/arm/mach-iop33x/include/mach/memory.h
arch/arm/mach-iop33x/include/mach/system.h
arch/arm/mach-iop33x/include/mach/timex.h
arch/arm/mach-ixp2000/include/mach/dma.h [deleted file]
arch/arm/mach-ixp2000/include/mach/memory.h
arch/arm/mach-ixp23xx/include/mach/dma.h [deleted file]
arch/arm/mach-ixp23xx/include/mach/io.h
arch/arm/mach-ixp23xx/include/mach/memory.h
arch/arm/mach-ixp4xx/include/mach/dma.h [deleted file]
arch/arm/mach-ixp4xx/include/mach/io.h
arch/arm/mach-ixp4xx/include/mach/memory.h
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/common.h
arch/arm/mach-kirkwood/include/mach/dma.h [deleted file]
arch/arm/mach-kirkwood/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-kirkwood/include/mach/irqs.h
arch/arm/mach-kirkwood/include/mach/kirkwood.h
arch/arm/mach-kirkwood/include/mach/memory.h
arch/arm/mach-kirkwood/irq.c
arch/arm/mach-kirkwood/rd88f6281-setup.c
arch/arm/mach-ks8695/Kconfig
arch/arm/mach-ks8695/Makefile
arch/arm/mach-ks8695/board-dsm320.c [new file with mode: 0644]
arch/arm/mach-ks8695/board-micrel.c
arch/arm/mach-ks8695/devices.c
arch/arm/mach-ks8695/gpio.c
arch/arm/mach-ks8695/include/mach/dma.h [deleted file]
arch/arm/mach-ks8695/include/mach/gpio.h
arch/arm/mach-ks8695/include/mach/io.h
arch/arm/mach-ks8695/include/mach/memory.h
arch/arm/mach-l7200/include/mach/dma.h [deleted file]
arch/arm/mach-l7200/include/mach/io.h
arch/arm/mach-l7200/include/mach/memory.h
arch/arm/mach-lh7a40x/clocks.c
arch/arm/mach-lh7a40x/include/mach/io.h
arch/arm/mach-lh7a40x/include/mach/memory.h
arch/arm/mach-loki/include/mach/dma.h [deleted file]
arch/arm/mach-loki/include/mach/memory.h
arch/arm/mach-msm/include/mach/io.h
arch/arm/mach-msm/include/mach/memory.h
arch/arm/mach-mv78xx0/common.c
arch/arm/mach-mv78xx0/include/mach/dma.h [deleted file]
arch/arm/mach-mv78xx0/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-mv78xx0/include/mach/irqs.h
arch/arm/mach-mv78xx0/include/mach/memory.h
arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
arch/arm/mach-mv78xx0/irq.c
arch/arm/mach-mx1/Kconfig [new file with mode: 0644]
arch/arm/mach-mx1/Makefile [new file with mode: 0644]
arch/arm/mach-mx1/Makefile.boot [new file with mode: 0644]
arch/arm/mach-mx1/clock.c [new file with mode: 0644]
arch/arm/mach-mx1/crm_regs.h [new file with mode: 0644]
arch/arm/mach-mx1/devices.c [new file with mode: 0644]
arch/arm/mach-mx1/devices.h [new file with mode: 0644]
arch/arm/mach-mx1/generic.c [moved from arch/arm/mach-integrator/include/mach/dma.h with 58% similarity]
arch/arm/mach-mx1/mx1ads.c [new file with mode: 0644]
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/devices.h
arch/arm/mach-mx2/mx27ads.c
arch/arm/mach-mx2/pcm038.c
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/clock.c
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/devices.h
arch/arm/mach-mx3/iomux.c
arch/arm/mach-mx3/mx31moboard.c [new file with mode: 0644]
arch/arm/mach-mx3/mx31pdk.c [new file with mode: 0644]
arch/arm/mach-mx3/pcm037.c
arch/arm/mach-netx/fb.c
arch/arm/mach-netx/include/mach/dma.h [deleted file]
arch/arm/mach-netx/include/mach/io.h
arch/arm/mach-netx/include/mach/memory.h
arch/arm/mach-netx/include/mach/netx-regs.h
arch/arm/mach-netx/time.c
arch/arm/mach-netx/xc.c
arch/arm/mach-ns9xxx/include/mach/dma.h [deleted file]
arch/arm/mach-ns9xxx/include/mach/hardware.h
arch/arm/mach-ns9xxx/include/mach/io.h
arch/arm/mach-ns9xxx/include/mach/memory.h
arch/arm/mach-omap1/Kconfig
arch/arm/mach-omap1/board-fsample.c
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-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-palmtt.c
arch/arm/mach-omap1/board-palmz71.c
arch/arm/mach-omap1/board-perseus2.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.h
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap1/fpga.c
arch/arm/mach-omap1/id.c
arch/arm/mach-omap1/leds-h2p2-debug.c
arch/arm/mach-omap1/leds-osk.c
arch/arm/mach-omap1/leds.c
arch/arm/mach-omap1/pm.c
arch/arm/mach-omap1/serial.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3pandora.c [new file with mode: 0644]
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/clock24xx.h
arch/arm/mach-omap2/clock34xx.c
arch/arm/mach-omap2/clock34xx.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mmc-twl4030.c [new file with mode: 0644]
arch/arm/mach-omap2/mmc-twl4030.h [new file with mode: 0644]
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/usb-tusb6010.c
arch/arm/mach-orion5x/Makefile
arch/arm/mach-orion5x/common.c
arch/arm/mach-orion5x/common.h
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/gpio.c [deleted file]
arch/arm/mach-orion5x/include/mach/dma.h [deleted file]
arch/arm/mach-orion5x/include/mach/gpio.h
arch/arm/mach-orion5x/include/mach/io.h
arch/arm/mach-orion5x/include/mach/irqs.h
arch/arm/mach-orion5x/include/mach/memory.h
arch/arm/mach-orion5x/include/mach/orion5x.h
arch/arm/mach-orion5x/irq.c
arch/arm/mach-orion5x/mpp.c
arch/arm/mach-pnx4008/dma.c
arch/arm/mach-pnx4008/include/mach/dma.h
arch/arm/mach-pnx4008/include/mach/io.h
arch/arm/mach-pnx4008/include/mach/memory.h
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/am200epd.c
arch/arm/mach-pxa/clock.c
arch/arm/mach-pxa/clock.h
arch/arm/mach-pxa/cm-x2xx.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/cpufreq-pxa2xx.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/dma.c
arch/arm/mach-pxa/e330.c
arch/arm/mach-pxa/e350.c
arch/arm/mach-pxa/e400.c
arch/arm/mach-pxa/e740.c
arch/arm/mach-pxa/e750.c
arch/arm/mach-pxa/e800.c
arch/arm/mach-pxa/eseries.c
arch/arm/mach-pxa/eseries.h
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/generic.c
arch/arm/mach-pxa/gpio.c
arch/arm/mach-pxa/gumstix.c
arch/arm/mach-pxa/h5000.c [new file with mode: 0644]
arch/arm/mach-pxa/imote2.c [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/dma.h
arch/arm/mach-pxa/include/mach/eseries-gpio.h
arch/arm/mach-pxa/include/mach/gumstix.h
arch/arm/mach-pxa/include/mach/h5000.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/hardware.h
arch/arm/mach-pxa/include/mach/io.h
arch/arm/mach-pxa/include/mach/littleton.h
arch/arm/mach-pxa/include/mach/memory.h
arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
arch/arm/mach-pxa/include/mach/mfp-pxa930.h
arch/arm/mach-pxa/include/mach/mioa701.h
arch/arm/mach-pxa/include/mach/mtd-xip.h
arch/arm/mach-pxa/include/mach/pxa-regs.h
arch/arm/mach-pxa/include/mach/pxa2xx-gpio.h
arch/arm/mach-pxa/include/mach/pxa2xx-regs.h
arch/arm/mach-pxa/include/mach/pxafb.h
arch/arm/mach-pxa/include/mach/regs-ac97.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/regs-lcd.h
arch/arm/mach-pxa/include/mach/regs-uart.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/timex.h
arch/arm/mach-pxa/include/mach/uncompress.h
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mfp-pxa2xx.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/pwm.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa300.c
arch/arm/mach-pxa/pxa320.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/saar.c
arch/arm/mach-pxa/smemc.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/ssp.c
arch/arm/mach-pxa/tavorevb.c
arch/arm/mach-pxa/time.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-pxa/zylonite_pxa320.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/Makefile
arch/arm/mach-realview/Makefile.boot
arch/arm/mach-realview/clock.c
arch/arm/mach-realview/clock.h
arch/arm/mach-realview/core.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/hotplug.c
arch/arm/mach-realview/include/mach/board-eb.h
arch/arm/mach-realview/include/mach/board-pb11mp.h
arch/arm/mach-realview/include/mach/board-pba8.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-realview/include/mach/debug-macro.S
arch/arm/mach-realview/include/mach/dma.h [deleted file]
arch/arm/mach-realview/include/mach/hardware.h
arch/arm/mach-realview/include/mach/io.h
arch/arm/mach-realview/include/mach/irqs.h
arch/arm/mach-realview/include/mach/memory.h
arch/arm/mach-realview/include/mach/uncompress.h
arch/arm/mach-realview/include/mach/vmalloc.h
arch/arm/mach-realview/localtimer.c
arch/arm/mach-realview/platsmp.c
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pba8.c [new file with mode: 0644]
arch/arm/mach-rpc/include/mach/io.h
arch/arm/mach-rpc/include/mach/irqs.h
arch/arm/mach-rpc/include/mach/isa-dma.h [moved from arch/arm/mach-rpc/include/mach/dma.h with 71% similarity]
arch/arm/mach-rpc/include/mach/memory.h
arch/arm/mach-s3c2400/include/mach/memory.h
arch/arm/mach-s3c2410/Kconfig
arch/arm/mach-s3c2410/Makefile
arch/arm/mach-s3c2410/dma.c
arch/arm/mach-s3c2410/include/mach/dma.h
arch/arm/mach-s3c2410/include/mach/gpio-core.h [new file with mode: 0644]
arch/arm/mach-s3c2410/include/mach/gpio.h
arch/arm/mach-s3c2410/include/mach/irqs.h
arch/arm/mach-s3c2410/include/mach/map.h
arch/arm/mach-s3c2410/include/mach/memory.h
arch/arm/mach-s3c2410/include/mach/regs-clock.h
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
arch/arm/mach-s3c2410/include/mach/spi.h
arch/arm/mach-s3c2410/include/mach/system-reset.h
arch/arm/mach-s3c2410/include/mach/tick.h [new file with mode: 0644]
arch/arm/mach-s3c2410/include/mach/uncompress.h
arch/arm/mach-s3c2410/mach-amlm5900.c
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/mach-n30.c
arch/arm/mach-s3c2410/mach-otom.c
arch/arm/mach-s3c2410/mach-qt2410.c
arch/arm/mach-s3c2410/mach-smdk2410.c
arch/arm/mach-s3c2410/mach-tct_hammer.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-s3c2410/s3c2410.c
arch/arm/mach-s3c2412/Kconfig
arch/arm/mach-s3c2412/clock.c
arch/arm/mach-s3c2412/dma.c
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/mach-smdk2413.c
arch/arm/mach-s3c2412/mach-vstms.c
arch/arm/mach-s3c2412/s3c2412.c
arch/arm/mach-s3c2440/Kconfig
arch/arm/mach-s3c2440/dma.c
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-at2440evb.c
arch/arm/mach-s3c2440/mach-nexcoder.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-smdk2440.c
arch/arm/mach-s3c2442/Kconfig
arch/arm/mach-s3c2443/Kconfig
arch/arm/mach-s3c2443/clock.c
arch/arm/mach-s3c2443/dma.c
arch/arm/mach-s3c2443/mach-smdk2443.c
arch/arm/mach-s3c2443/s3c2443.c
arch/arm/mach-s3c24a0/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/map.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/regs-clock.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/regs-irq.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/tick.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-s3c24a0/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-s3c6400/Kconfig [new file with mode: 0644]
arch/arm/mach-s3c6400/Makefile [new file with mode: 0644]
arch/arm/mach-s3c6400/Makefile.boot [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/dma.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/gpio-core.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/map.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/pwm-clock.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/regs-fb.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/regs-irq.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/tick.h [new file with mode: 0644]
arch/arm/mach-s3c6400/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-s3c6410/Kconfig [new file with mode: 0644]
arch/arm/mach-s3c6410/Makefile [new file with mode: 0644]
arch/arm/mach-s3c6410/cpu.c [new file with mode: 0644]
arch/arm/mach-s3c6410/mach-smdk6410.c [new file with mode: 0644]
arch/arm/mach-s3c6410/setup-sdhci.c [new file with mode: 0644]
arch/arm/mach-sa1100/clock.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/collie_pm.c
arch/arm/mach-sa1100/cpu-sa1100.c
arch/arm/mach-sa1100/cpu-sa1110.c
arch/arm/mach-sa1100/dma.c
arch/arm/mach-sa1100/include/mach/h3600.h
arch/arm/mach-sa1100/include/mach/hardware.h
arch/arm/mach-sa1100/include/mach/io.h
arch/arm/mach-sa1100/include/mach/memory.h
arch/arm/mach-sa1100/include/mach/mtd-xip.h
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/sleep.S
arch/arm/mach-sa1100/time.c
arch/arm/mach-shark/core.c
arch/arm/mach-shark/include/mach/hardware.h
arch/arm/mach-shark/include/mach/io.h
arch/arm/mach-shark/include/mach/isa-dma.h [moved from arch/arm/mach-shark/include/mach/dma.h with 79% similarity]
arch/arm/mach-shark/include/mach/memory.h
arch/arm/mach-versatile/Kconfig
arch/arm/mach-versatile/clock.c
arch/arm/mach-versatile/clock.h
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-versatile/include/mach/dma.h [deleted file]
arch/arm/mach-versatile/include/mach/io.h
arch/arm/mach-versatile/include/mach/irqs.h
arch/arm/mach-versatile/include/mach/memory.h
arch/arm/mach-versatile/include/mach/platform.h
arch/arm/mach-w90x900/Kconfig [new file with mode: 0644]
arch/arm/mach-w90x900/Makefile [new file with mode: 0644]
arch/arm/mach-w90x900/Makefile.boot [new file with mode: 0644]
arch/arm/mach-w90x900/cpu.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/hardware.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/irqs.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/map.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/memory.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/regs-irq.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/regs-serial.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/regs-timer.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/system.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/timex.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-w90x900/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/mach-w90x900/irq.c [new file with mode: 0644]
arch/arm/mach-w90x900/mach-w90p910evb.c [new file with mode: 0644]
arch/arm/mach-w90x900/time.c [new file with mode: 0644]
arch/arm/mach-w90x900/w90p910.c [new file with mode: 0644]
arch/arm/mm/Kconfig
arch/arm/mm/alignment.c
arch/arm/mm/cache-v3.S
arch/arm/mm/cache-v4.S
arch/arm/mm/cache-v4wt.S
arch/arm/mm/cache-v7.S
arch/arm/mm/copypage-feroceon.S [deleted file]
arch/arm/mm/copypage-feroceon.c [new file with mode: 0644]
arch/arm/mm/copypage-v3.S [deleted file]
arch/arm/mm/copypage-v3.c [new file with mode: 0644]
arch/arm/mm/copypage-v4mc.c
arch/arm/mm/copypage-v4wb.S [deleted file]
arch/arm/mm/copypage-v4wb.c [new file with mode: 0644]
arch/arm/mm/copypage-v4wt.S [deleted file]
arch/arm/mm/copypage-v4wt.c [new file with mode: 0644]
arch/arm/mm/copypage-v6.c
arch/arm/mm/copypage-xsc3.S [deleted file]
arch/arm/mm/copypage-xsc3.c [new file with mode: 0644]
arch/arm/mm/copypage-xscale.c
arch/arm/mm/fault.c
arch/arm/mm/init.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/nommu.c
arch/arm/mm/pgd.c
arch/arm/mm/proc-syms.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-xsc3.S
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/dma-mx1-mx2.c
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/include/mach/board-mx27ads.h
arch/arm/plat-mxc/include/mach/board-mx31ads.h
arch/arm/plat-mxc/include/mach/board-mx31pdk.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/dma-mx1-mx2.h
arch/arm/plat-mxc/include/mach/dma.h [deleted file]
arch/arm/plat-mxc/include/mach/entry-macro.S
arch/arm/plat-mxc/include/mach/gpio.h
arch/arm/plat-mxc/include/mach/hardware.h
arch/arm/plat-mxc/include/mach/io.h
arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h
arch/arm/plat-mxc/include/mach/iomux-mx3.h
arch/arm/plat-mxc/include/mach/irqs.h
arch/arm/plat-mxc/include/mach/memory.h
arch/arm/plat-mxc/include/mach/mtd-xip.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/mx1.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/mx27.h
arch/arm/plat-mxc/include/mach/mx31.h
arch/arm/plat-mxc/include/mach/mxc_timer.h
arch/arm/plat-mxc/include/mach/timex.h
arch/arm/plat-mxc/iomux-mx1-mx2.c
arch/arm/plat-mxc/irq.c
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/debug-devices.c
arch/arm/plat-omap/debug-leds.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/i2c.c
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-ldp.h
arch/arm/plat-omap/include/mach/board.h
arch/arm/plat-omap/include/mach/control.h
arch/arm/plat-omap/include/mach/cpu.h
arch/arm/plat-omap/include/mach/gpio.h
arch/arm/plat-omap/include/mach/io.h
arch/arm/plat-omap/include/mach/memory.h
arch/arm/plat-omap/include/mach/mmc.h
arch/arm/plat-omap/include/mach/mux.h
arch/arm/plat-omap/sram.c
arch/arm/plat-orion/Makefile
arch/arm/plat-orion/gpio.c [new file with mode: 0644]
arch/arm/plat-orion/include/plat/ehci-orion.h
arch/arm/plat-orion/include/plat/gpio.h [new file with mode: 0644]
arch/arm/plat-s3c/Kconfig
arch/arm/plat-s3c/Makefile
arch/arm/plat-s3c/clock.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-fb.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-hsmmc.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-hsmmc1.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-i2c0.c [new file with mode: 0644]
arch/arm/plat-s3c/dev-i2c1.c [new file with mode: 0644]
arch/arm/plat-s3c/gpio-config.c [new file with mode: 0644]
arch/arm/plat-s3c/gpio.c [new file with mode: 0644]
arch/arm/plat-s3c/include/mach/io.h [new file with mode: 0644]
arch/arm/plat-s3c/include/mach/timex.h [moved from arch/arm/mach-s3c2410/include/mach/timex.h with 100% similarity]
arch/arm/plat-s3c/include/mach/vmalloc.h [moved from arch/arm/mach-s3c2410/include/mach/vmalloc.h with 91% similarity]
arch/arm/plat-s3c/include/plat/adc.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/clock.h [moved from arch/arm/plat-s3c24xx/include/plat/clock.h with 66% similarity]
arch/arm/plat-s3c/include/plat/cpu-freq.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/cpu.h [moved from arch/arm/plat-s3c24xx/include/plat/cpu.h with 70% similarity]
arch/arm/plat-s3c/include/plat/debug-macro.S
arch/arm/plat-s3c/include/plat/devs.h [moved from arch/arm/plat-s3c24xx/include/plat/devs.h with 79% similarity]
arch/arm/plat-s3c/include/plat/fb.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/gpio-cfg-helpers.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/gpio-cfg.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/gpio-core.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/iic-core.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/iic.h [moved from include/asm-arm/plat-s3c/iic.h with 51% similarity]
arch/arm/plat-s3c/include/plat/map-base.h [moved from arch/arm/plat-s3c/include/plat/map.h with 100% similarity]
arch/arm/plat-s3c/include/plat/nand.h [moved from include/asm-arm/plat-s3c/nand.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-ac97.h [moved from include/asm-arm/plat-s3c/regs-ac97.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-fb.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/regs-iic.h [moved from include/asm-arm/plat-s3c/regs-iic.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-irqtype.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/regs-nand.h [moved from include/asm-arm/plat-s3c/regs-nand.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-rtc.h [moved from include/asm-arm/plat-s3c/regs-rtc.h with 100% similarity]
arch/arm/plat-s3c/include/plat/regs-sdhci.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/regs-serial.h
arch/arm/plat-s3c/include/plat/regs-timer.h
arch/arm/plat-s3c/include/plat/regs-watchdog.h [moved from include/asm-arm/plat-s3c/regs-watchdog.h with 100% similarity]
arch/arm/plat-s3c/include/plat/sdhci.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/uncompress.h
arch/arm/plat-s3c/init.c [new file with mode: 0644]
arch/arm/plat-s3c/pwm-clock.c [moved from arch/arm/plat-s3c24xx/pwm-clock.c with 81% similarity]
arch/arm/plat-s3c/time.c [moved from arch/arm/plat-s3c24xx/time.c with 80% similarity]
arch/arm/plat-s3c24xx/Kconfig
arch/arm/plat-s3c24xx/Makefile
arch/arm/plat-s3c24xx/adc.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/clock-dclk.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/clock.c
arch/arm/plat-s3c24xx/common-smdk.c
arch/arm/plat-s3c24xx/cpu.c
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s3c24xx/dma.c
arch/arm/plat-s3c24xx/gpiolib.c
arch/arm/plat-s3c24xx/include/mach/pwm-clock.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/include/plat/map.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/include/plat/mci.h [moved from include/asm-arm/plat-s3c24xx/mci.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/pll.h [new file with mode: 0644]
arch/arm/plat-s3c24xx/include/plat/regs-spi.h [moved from include/asm-arm/plat-s3c24xx/regs-spi.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/regs-udc.h [moved from include/asm-arm/plat-s3c24xx/regs-udc.h with 100% similarity]
arch/arm/plat-s3c24xx/include/plat/s3c2400.h
arch/arm/plat-s3c24xx/include/plat/s3c2410.h
arch/arm/plat-s3c24xx/include/plat/s3c2412.h
arch/arm/plat-s3c24xx/include/plat/s3c2443.h
arch/arm/plat-s3c24xx/include/plat/udc.h [moved from include/asm-arm/plat-s3c24xx/udc.h with 100% similarity]
arch/arm/plat-s3c24xx/irq.c
arch/arm/plat-s3c24xx/pm.c
arch/arm/plat-s3c24xx/s3c2410-clock.c [moved from arch/arm/mach-s3c2410/clock.c with 99% similarity]
arch/arm/plat-s3c24xx/s3c244x-clock.c
arch/arm/plat-s3c24xx/s3c244x.c
arch/arm/plat-s3c24xx/s3c244x.h
arch/arm/plat-s3c24xx/setup-i2c.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c [new file with mode: 0644]
arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/Kconfig [new file with mode: 0644]
arch/arm/plat-s3c64xx/Makefile [new file with mode: 0644]
arch/arm/plat-s3c64xx/clock.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/cpu.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/dev-uart.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/gpiolib.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-a.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-b.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-c.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-d.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-e.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-f.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-g.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-h.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-i.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-j.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-n.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-o.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-p.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/gpio-bank-q.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/irqs.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/pll.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/regs-clock.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/regs-gpio.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/regs-sys.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/s3c6400.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/include/plat/s3c6410.h [new file with mode: 0644]
arch/arm/plat-s3c64xx/irq-eint.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/irq.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/s3c6400-clock.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/s3c6400-init.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/setup-fb-24bpp.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/setup-i2c0.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/setup-i2c1.c [new file with mode: 0644]
arch/arm/tools/mach-types
arch/arm/vfp/vfp.h
arch/arm/vfp/vfphw.S
arch/arm/vfp/vfpmodule.c
arch/powerpc/platforms/pseries/rtasd.c
arch/s390/include/asm/kvm_virtio.h
arch/s390/mm/pgtable.c
arch/sparc/Kconfig
arch/sparc/Kconfig.debug
arch/sparc/Makefile
arch/sparc/boot/.gitignore [moved from arch/sparc64/boot/.gitignore with 60% similarity]
arch/sparc/boot/Makefile
arch/sparc/boot/piggyback_32.c [moved from arch/sparc/boot/piggyback.c with 100% similarity]
arch/sparc/boot/piggyback_64.c [moved from arch/sparc64/boot/piggyback.c with 100% similarity]
arch/sparc/configs/sparc32_defconfig [moved from arch/sparc/defconfig with 100% similarity]
arch/sparc/configs/sparc64_defconfig [moved from arch/sparc64/defconfig with 100% similarity]
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/asm.h [new file with mode: 0644]
arch/sparc/include/asm/atomic_64.h
arch/sparc/include/asm/bitops_64.h
arch/sparc/include/asm/hypervisor.h
arch/sparc/include/asm/irq_32.h
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/irqflags_64.h
arch/sparc/include/asm/module.h
arch/sparc/include/asm/module_32.h [deleted file]
arch/sparc/include/asm/module_64.h [deleted file]
arch/sparc/include/asm/openprom_32.h
arch/sparc/include/asm/oplib_32.h
arch/sparc/include/asm/pil.h
arch/sparc/include/asm/scatterlist.h
arch/sparc/include/asm/scatterlist_32.h [deleted file]
arch/sparc/include/asm/scatterlist_64.h [deleted file]
arch/sparc/include/asm/sections.h
arch/sparc/include/asm/sections_32.h [deleted file]
arch/sparc/include/asm/sections_64.h [deleted file]
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/spitfire.h
arch/sparc/include/asm/system_32.h
arch/sparc/include/asm/system_64.h
arch/sparc/include/asm/tsb.h
arch/sparc/include/asm/ttable.h
arch/sparc/include/asm/unistd.h
arch/sparc/include/asm/unistd_32.h [deleted file]
arch/sparc/include/asm/unistd_64.h [deleted file]
arch/sparc/kernel/.gitignore [new file with mode: 0644]
arch/sparc/kernel/Makefile
arch/sparc/kernel/asm-offsets.c
arch/sparc/kernel/audit.c [moved from arch/sparc64/kernel/audit.c with 100% similarity]
arch/sparc/kernel/auxio_32.c [moved from arch/sparc/kernel/auxio.c with 100% similarity]
arch/sparc/kernel/auxio_64.c [moved from arch/sparc64/kernel/auxio.c with 67% similarity]
arch/sparc/kernel/central.c [moved from arch/sparc64/kernel/central.c with 100% similarity]
arch/sparc/kernel/cherrs.S [moved from arch/sparc64/kernel/cherrs.S with 98% similarity]
arch/sparc/kernel/chmc.c [moved from arch/sparc64/kernel/chmc.c with 100% similarity]
arch/sparc/kernel/compat_audit.c [moved from arch/sparc64/kernel/compat_audit.c with 91% similarity]
arch/sparc/kernel/cpu.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/ds.c [moved from arch/sparc64/kernel/ds.c with 100% similarity]
arch/sparc/kernel/dtlb_miss.S [moved from arch/sparc64/kernel/dtlb_miss.S with 100% similarity]
arch/sparc/kernel/dtlb_prot.S [moved from arch/sparc64/kernel/dtlb_prot.S with 100% similarity]
arch/sparc/kernel/ebus.c [moved from arch/sparc64/kernel/ebus.c with 100% similarity]
arch/sparc/kernel/entry.h [moved from arch/sparc64/kernel/entry.h with 79% similarity]
arch/sparc/kernel/etrap_32.S [moved from arch/sparc/kernel/etrap.S with 100% similarity]
arch/sparc/kernel/etrap_64.S [moved from arch/sparc64/kernel/etrap.S with 97% similarity]
arch/sparc/kernel/fpu_traps.S [moved from arch/sparc64/kernel/fpu_traps.S with 100% similarity]
arch/sparc/kernel/ftrace.c [moved from arch/sparc64/kernel/ftrace.c with 100% similarity]
arch/sparc/kernel/getsetcc.S [moved from arch/sparc64/kernel/getsetcc.S with 100% similarity]
arch/sparc/kernel/head_32.S [moved from arch/sparc/kernel/head.S with 99% similarity]
arch/sparc/kernel/head_64.S [moved from arch/sparc64/kernel/head.S with 99% similarity]
arch/sparc/kernel/helpers.S [moved from arch/sparc64/kernel/helpers.S with 100% similarity]
arch/sparc/kernel/hvapi.c [moved from arch/sparc64/kernel/hvapi.c with 100% similarity]
arch/sparc/kernel/hvcalls.S [moved from arch/sparc64/kernel/hvcalls.S with 96% similarity]
arch/sparc/kernel/hvtramp.S [moved from arch/sparc64/kernel/hvtramp.S with 95% similarity]
arch/sparc/kernel/idprom.c
arch/sparc/kernel/init_task.c
arch/sparc/kernel/iommu.c [moved from arch/sparc64/kernel/iommu.c with 100% similarity]
arch/sparc/kernel/iommu_common.h [moved from arch/sparc64/kernel/iommu_common.h with 100% similarity]
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq_32.c [moved from arch/sparc/kernel/irq.c with 99% similarity]
arch/sparc/kernel/irq_64.c [moved from arch/sparc64/kernel/irq.c with 94% similarity]
arch/sparc/kernel/itlb_miss.S [moved from arch/sparc64/kernel/itlb_miss.S with 100% similarity]
arch/sparc/kernel/ivec.S [moved from arch/sparc64/kernel/ivec.S with 100% similarity]
arch/sparc/kernel/kernel.h [new file with mode: 0644]
arch/sparc/kernel/kgdb_32.c [moved from arch/sparc/kernel/kgdb.c with 100% similarity]
arch/sparc/kernel/kgdb_64.c [moved from arch/sparc64/kernel/kgdb.c with 100% similarity]
arch/sparc/kernel/kprobes.c [moved from arch/sparc64/kernel/kprobes.c with 100% similarity]
arch/sparc/kernel/kstack.h [moved from arch/sparc64/kernel/kstack.h with 100% similarity]
arch/sparc/kernel/ktlb.S [moved from arch/sparc64/kernel/ktlb.S with 100% similarity]
arch/sparc/kernel/ldc.c [moved from arch/sparc64/kernel/ldc.c with 100% similarity]
arch/sparc/kernel/mdesc.c [moved from arch/sparc64/kernel/mdesc.c with 99% similarity]
arch/sparc/kernel/misctrap.S [moved from arch/sparc64/kernel/misctrap.S with 100% similarity]
arch/sparc/kernel/module.c
arch/sparc/kernel/muldiv.c
arch/sparc/kernel/of_device_32.c [moved from arch/sparc/kernel/of_device.c with 100% similarity]
arch/sparc/kernel/of_device_64.c [moved from arch/sparc64/kernel/of_device.c with 98% similarity]
arch/sparc/kernel/pci.c [moved from arch/sparc64/kernel/pci.c with 100% similarity]
arch/sparc/kernel/pci_common.c [moved from arch/sparc64/kernel/pci_common.c with 100% similarity]
arch/sparc/kernel/pci_fire.c [moved from arch/sparc64/kernel/pci_fire.c with 100% similarity]
arch/sparc/kernel/pci_impl.h [moved from arch/sparc64/kernel/pci_impl.h with 100% similarity]
arch/sparc/kernel/pci_msi.c [moved from arch/sparc64/kernel/pci_msi.c with 100% similarity]
arch/sparc/kernel/pci_psycho.c [moved from arch/sparc64/kernel/pci_psycho.c with 100% similarity]
arch/sparc/kernel/pci_sabre.c [moved from arch/sparc64/kernel/pci_sabre.c with 100% similarity]
arch/sparc/kernel/pci_schizo.c [moved from arch/sparc64/kernel/pci_schizo.c with 100% similarity]
arch/sparc/kernel/pci_sun4v.c [moved from arch/sparc64/kernel/pci_sun4v.c with 100% similarity]
arch/sparc/kernel/pci_sun4v.h [moved from arch/sparc64/kernel/pci_sun4v.h with 100% similarity]
arch/sparc/kernel/pci_sun4v_asm.S [moved from arch/sparc64/kernel/pci_sun4v_asm.S with 100% similarity]
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pmc.c
arch/sparc/kernel/power.c [moved from arch/sparc64/kernel/power.c with 100% similarity]
arch/sparc/kernel/process_32.c [moved from arch/sparc/kernel/process.c with 99% similarity]
arch/sparc/kernel/process_64.c [moved from arch/sparc64/kernel/process.c with 100% similarity]
arch/sparc/kernel/prom.h [new file with mode: 0644]
arch/sparc/kernel/prom_32.c [moved from arch/sparc/kernel/prom.c with 51% similarity]
arch/sparc/kernel/prom_64.c [new file with mode: 0644]
arch/sparc/kernel/prom_common.c [new file with mode: 0644]
arch/sparc/kernel/prom_irqtrans.c [moved from arch/sparc64/kernel/prom.c with 53% similarity]
arch/sparc/kernel/psycho_common.c [moved from arch/sparc64/kernel/psycho_common.c with 100% similarity]
arch/sparc/kernel/psycho_common.h [moved from arch/sparc64/kernel/psycho_common.h with 100% similarity]
arch/sparc/kernel/ptrace_32.c [moved from arch/sparc/kernel/ptrace.c with 100% similarity]
arch/sparc/kernel/ptrace_64.c [moved from arch/sparc64/kernel/ptrace.c with 100% similarity]
arch/sparc/kernel/reboot.c [moved from arch/sparc64/kernel/reboot.c with 100% similarity]
arch/sparc/kernel/rtrap_32.S [moved from arch/sparc/kernel/rtrap.S with 100% similarity]
arch/sparc/kernel/rtrap_64.S [moved from arch/sparc64/kernel/rtrap.S with 95% similarity]
arch/sparc/kernel/sbus.c [moved from arch/sparc64/kernel/sbus.c with 100% similarity]
arch/sparc/kernel/setup_32.c [moved from arch/sparc/kernel/setup.c with 98% similarity]
arch/sparc/kernel/setup_64.c [moved from arch/sparc64/kernel/setup.c with 99% similarity]
arch/sparc/kernel/signal32.c [moved from arch/sparc64/kernel/signal32.c with 100% similarity]
arch/sparc/kernel/signal_32.c [moved from arch/sparc/kernel/signal.c with 100% similarity]
arch/sparc/kernel/signal_64.c [moved from arch/sparc64/kernel/signal.c with 100% similarity]
arch/sparc/kernel/smp_32.c [moved from arch/sparc/kernel/smp.c with 100% similarity]
arch/sparc/kernel/smp_64.c [moved from arch/sparc64/kernel/smp.c with 99% similarity]
arch/sparc/kernel/sparc_ksyms_32.c [moved from arch/sparc/kernel/sparc_ksyms.c with 98% similarity]
arch/sparc/kernel/sparc_ksyms_64.c [moved from arch/sparc64/kernel/sparc64_ksyms.c with 97% similarity]
arch/sparc/kernel/spiterrs.S [moved from arch/sparc64/kernel/spiterrs.S with 99% similarity]
arch/sparc/kernel/sstate.c [moved from arch/sparc64/kernel/sstate.c with 100% similarity]
arch/sparc/kernel/stacktrace.c [moved from arch/sparc64/kernel/stacktrace.c with 60% similarity]
arch/sparc/kernel/starfire.c [moved from arch/sparc64/kernel/starfire.c with 100% similarity]
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4v_ivec.S [moved from arch/sparc64/kernel/sun4v_ivec.S with 98% similarity]
arch/sparc/kernel/sun4v_tlb_miss.S [moved from arch/sparc64/kernel/sun4v_tlb_miss.S with 100% similarity]
arch/sparc/kernel/sys32.S [moved from arch/sparc64/kernel/sys32.S with 100% similarity]
arch/sparc/kernel/sys_sparc32.c [moved from arch/sparc64/kernel/sys_sparc32.c with 100% similarity]
arch/sparc/kernel/sys_sparc_32.c [moved from arch/sparc/kernel/sys_sparc.c with 100% similarity]
arch/sparc/kernel/sys_sparc_64.c [moved from arch/sparc64/kernel/sys_sparc.c with 100% similarity]
arch/sparc/kernel/syscalls.S [moved from arch/sparc64/kernel/syscalls.S with 100% similarity]
arch/sparc/kernel/sysfs.c [moved from arch/sparc64/kernel/sysfs.c with 99% similarity]
arch/sparc/kernel/systbls.h [moved from arch/sparc64/kernel/systbls.h with 100% similarity]
arch/sparc/kernel/systbls_32.S [moved from arch/sparc/kernel/systbls.S with 100% similarity]
arch/sparc/kernel/systbls_64.S [moved from arch/sparc64/kernel/systbls.S with 100% similarity]
arch/sparc/kernel/time_32.c [moved from arch/sparc/kernel/time.c with 100% similarity]
arch/sparc/kernel/time_64.c [moved from arch/sparc64/kernel/time.c with 100% similarity]
arch/sparc/kernel/trampoline_32.S [moved from arch/sparc/kernel/trampoline.S with 100% similarity]
arch/sparc/kernel/trampoline_64.S [moved from arch/sparc64/kernel/trampoline.S with 98% similarity]
arch/sparc/kernel/traps_32.c [moved from arch/sparc/kernel/traps.c with 94% similarity]
arch/sparc/kernel/traps_64.c [moved from arch/sparc64/kernel/traps.c with 99% similarity]
arch/sparc/kernel/tsb.S [moved from arch/sparc64/kernel/tsb.S with 99% similarity]
arch/sparc/kernel/ttable.S [moved from arch/sparc64/kernel/ttable.S with 99% similarity]
arch/sparc/kernel/una_asm_32.S [moved from arch/sparc/kernel/una_asm.S with 100% similarity]
arch/sparc/kernel/una_asm_64.S [moved from arch/sparc64/kernel/una_asm.S with 100% similarity]
arch/sparc/kernel/unaligned_32.c [moved from arch/sparc/kernel/unaligned.c with 100% similarity]
arch/sparc/kernel/unaligned_64.c [moved from arch/sparc64/kernel/unaligned.c with 100% similarity]
arch/sparc/kernel/us2e_cpufreq.c [moved from arch/sparc64/kernel/us2e_cpufreq.c with 100% similarity]
arch/sparc/kernel/us3_cpufreq.c [moved from arch/sparc64/kernel/us3_cpufreq.c with 100% similarity]
arch/sparc/kernel/utrap.S [moved from arch/sparc64/kernel/utrap.S with 100% similarity]
arch/sparc/kernel/vio.c [moved from arch/sparc64/kernel/vio.c with 100% similarity]
arch/sparc/kernel/viohs.c [moved from arch/sparc64/kernel/viohs.c with 100% similarity]
arch/sparc/kernel/visemul.c [moved from arch/sparc64/kernel/visemul.c with 100% similarity]
arch/sparc/kernel/vmlinux.lds.S
arch/sparc/kernel/winfixup.S [moved from arch/sparc64/kernel/winfixup.S with 100% similarity]
arch/sparc/lib/GENbzero.S [moved from arch/sparc64/lib/GENbzero.S with 100% similarity]
arch/sparc/lib/GENcopy_from_user.S [moved from arch/sparc64/lib/GENcopy_from_user.S with 100% similarity]
arch/sparc/lib/GENcopy_to_user.S [moved from arch/sparc64/lib/GENcopy_to_user.S with 100% similarity]
arch/sparc/lib/GENmemcpy.S [moved from arch/sparc64/lib/GENmemcpy.S with 100% similarity]
arch/sparc/lib/GENpage.S [moved from arch/sparc64/lib/GENpage.S with 100% similarity]
arch/sparc/lib/GENpatch.S [moved from arch/sparc64/lib/GENpatch.S with 100% similarity]
arch/sparc/lib/Makefile
arch/sparc/lib/NG2copy_from_user.S [moved from arch/sparc64/lib/NG2copy_from_user.S with 100% similarity]
arch/sparc/lib/NG2copy_to_user.S [moved from arch/sparc64/lib/NG2copy_to_user.S with 100% similarity]
arch/sparc/lib/NG2memcpy.S [moved from arch/sparc64/lib/NG2memcpy.S with 100% similarity]
arch/sparc/lib/NG2page.S [moved from arch/sparc64/lib/NG2page.S with 100% similarity]
arch/sparc/lib/NG2patch.S [moved from arch/sparc64/lib/NG2patch.S with 100% similarity]
arch/sparc/lib/NGbzero.S [moved from arch/sparc64/lib/NGbzero.S with 100% similarity]
arch/sparc/lib/NGcopy_from_user.S [moved from arch/sparc64/lib/NGcopy_from_user.S with 100% similarity]
arch/sparc/lib/NGcopy_to_user.S [moved from arch/sparc64/lib/NGcopy_to_user.S with 100% similarity]
arch/sparc/lib/NGmemcpy.S [moved from arch/sparc64/lib/NGmemcpy.S with 100% similarity]
arch/sparc/lib/NGpage.S [moved from arch/sparc64/lib/NGpage.S with 100% similarity]
arch/sparc/lib/NGpatch.S [moved from arch/sparc64/lib/NGpatch.S with 100% similarity]
arch/sparc/lib/PeeCeeI.c [moved from arch/sparc64/lib/PeeCeeI.c with 100% similarity]
arch/sparc/lib/U1copy_from_user.S [moved from arch/sparc64/lib/U1copy_from_user.S with 100% similarity]
arch/sparc/lib/U1copy_to_user.S [moved from arch/sparc64/lib/U1copy_to_user.S with 100% similarity]
arch/sparc/lib/U1memcpy.S [moved from arch/sparc64/lib/U1memcpy.S with 100% similarity]
arch/sparc/lib/U3copy_from_user.S [moved from arch/sparc64/lib/U3copy_from_user.S with 100% similarity]
arch/sparc/lib/U3copy_to_user.S [moved from arch/sparc64/lib/U3copy_to_user.S with 100% similarity]
arch/sparc/lib/U3memcpy.S [moved from arch/sparc64/lib/U3memcpy.S with 100% similarity]
arch/sparc/lib/U3patch.S [moved from arch/sparc64/lib/U3patch.S with 100% similarity]
arch/sparc/lib/VISsave.S [moved from arch/sparc64/lib/VISsave.S with 100% similarity]
arch/sparc/lib/atomic_32.S [moved from arch/sparc/lib/atomic.S with 100% similarity]
arch/sparc/lib/atomic_64.S [moved from arch/sparc64/lib/atomic.S with 84% similarity]
arch/sparc/lib/bitops.S [moved from arch/sparc64/lib/bitops.S with 84% similarity]
arch/sparc/lib/bzero.S [moved from arch/sparc64/lib/bzero.S with 100% similarity]
arch/sparc/lib/checksum_32.S [moved from arch/sparc/lib/checksum.S with 100% similarity]
arch/sparc/lib/checksum_64.S [moved from arch/sparc64/lib/checksum.S with 100% similarity]
arch/sparc/lib/clear_page.S [moved from arch/sparc64/lib/clear_page.S with 100% similarity]
arch/sparc/lib/copy_in_user.S [moved from arch/sparc64/lib/copy_in_user.S with 100% similarity]
arch/sparc/lib/copy_page.S [moved from arch/sparc64/lib/copy_page.S with 100% similarity]
arch/sparc/lib/csum_copy.S [moved from arch/sparc64/lib/csum_copy.S with 100% similarity]
arch/sparc/lib/csum_copy_from_user.S [moved from arch/sparc64/lib/csum_copy_from_user.S with 100% similarity]
arch/sparc/lib/csum_copy_to_user.S [moved from arch/sparc64/lib/csum_copy_to_user.S with 100% similarity]
arch/sparc/lib/ipcsum.S [moved from arch/sparc64/lib/ipcsum.S with 100% similarity]
arch/sparc/lib/mcount.S [moved from arch/sparc64/lib/mcount.S with 100% similarity]
arch/sparc/lib/memcmp.S
arch/sparc/lib/memmove.S [moved from arch/sparc64/lib/memmove.S with 100% similarity]
arch/sparc/lib/memscan_32.S [moved from arch/sparc/lib/memscan.S with 100% similarity]
arch/sparc/lib/memscan_64.S [moved from arch/sparc64/lib/memscan.S with 100% similarity]
arch/sparc/lib/rwsem_32.S [moved from arch/sparc/lib/rwsem.S with 100% similarity]
arch/sparc/lib/rwsem_64.S [moved from arch/sparc64/lib/rwsem.S with 92% similarity]
arch/sparc/lib/strlen.S
arch/sparc/lib/strlen_user_32.S [moved from arch/sparc/lib/strlen_user.S with 100% similarity]
arch/sparc/lib/strlen_user_64.S [moved from arch/sparc64/lib/strlen_user.S with 100% similarity]
arch/sparc/lib/strncmp_32.S [moved from arch/sparc/lib/strncmp.S with 100% similarity]
arch/sparc/lib/strncmp_64.S [moved from arch/sparc64/lib/strncmp.S with 100% similarity]
arch/sparc/lib/strncpy_from_user_32.S [moved from arch/sparc/lib/strncpy_from_user.S with 100% similarity]
arch/sparc/lib/strncpy_from_user_64.S [moved from arch/sparc64/lib/strncpy_from_user.S with 100% similarity]
arch/sparc/lib/user_fixup.c [moved from arch/sparc64/lib/user_fixup.c with 100% similarity]
arch/sparc/lib/xor.S [moved from arch/sparc64/lib/xor.S with 100% similarity]
arch/sparc/math-emu/Makefile
arch/sparc/math-emu/ashldi3.S [deleted file]
arch/sparc/math-emu/math_32.c [moved from arch/sparc/math-emu/math.c with 99% similarity]
arch/sparc/math-emu/math_64.c [moved from arch/sparc64/math-emu/math.c with 99% similarity]
arch/sparc/math-emu/sfp-util_32.h [moved from arch/sparc/math-emu/sfp-util.h with 100% similarity]
arch/sparc/math-emu/sfp-util_64.h [moved from arch/sparc64/math-emu/sfp-util.h with 100% similarity]
arch/sparc/mm/Makefile
arch/sparc/mm/fault_32.c [moved from arch/sparc/mm/fault.c with 100% similarity]
arch/sparc/mm/fault_64.c [moved from arch/sparc64/mm/fault.c with 100% similarity]
arch/sparc/mm/generic_32.c [moved from arch/sparc/mm/generic.c with 100% similarity]
arch/sparc/mm/generic_64.c [moved from arch/sparc64/mm/generic.c with 100% similarity]
arch/sparc/mm/hugetlbpage.c [moved from arch/sparc64/mm/hugetlbpage.c with 100% similarity]
arch/sparc/mm/init_32.c [moved from arch/sparc/mm/init.c with 97% similarity]
arch/sparc/mm/init_64.c [moved from arch/sparc64/mm/init.c with 99% similarity]
arch/sparc/mm/init_64.h [moved from arch/sparc64/mm/init.h with 100% similarity]
arch/sparc/mm/io-unit.c
arch/sparc/mm/iommu.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/mm/tlb.c [moved from arch/sparc64/mm/tlb.c with 100% similarity]
arch/sparc/mm/tsb.c [moved from arch/sparc64/mm/tsb.c with 97% similarity]
arch/sparc/mm/ultra.S [moved from arch/sparc64/mm/ultra.S with 99% similarity]
arch/sparc/oprofile/init.c
arch/sparc/prom/Makefile
arch/sparc/prom/bootstr_32.c [moved from arch/sparc/prom/bootstr.c with 100% similarity]
arch/sparc/prom/bootstr_64.c [moved from arch/sparc64/prom/bootstr.c with 100% similarity]
arch/sparc/prom/cif.S [moved from arch/sparc64/prom/cif.S with 100% similarity]
arch/sparc/prom/console_32.c [moved from arch/sparc/prom/console.c with 100% similarity]
arch/sparc/prom/console_64.c [moved from arch/sparc64/prom/console.c with 100% similarity]
arch/sparc/prom/devops_32.c [moved from arch/sparc/prom/devops.c with 100% similarity]
arch/sparc/prom/devops_64.c [moved from arch/sparc64/prom/devops.c with 100% similarity]
arch/sparc/prom/init_32.c [moved from arch/sparc/prom/init.c with 100% similarity]
arch/sparc/prom/init_64.c [moved from arch/sparc64/prom/init.c with 100% similarity]
arch/sparc/prom/misc_32.c [moved from arch/sparc/prom/misc.c with 98% similarity]
arch/sparc/prom/misc_64.c [moved from arch/sparc64/prom/misc.c with 100% similarity]
arch/sparc/prom/p1275.c [moved from arch/sparc64/prom/p1275.c with 100% similarity]
arch/sparc/prom/printf.c
arch/sparc/prom/tree_32.c [moved from arch/sparc/prom/tree.c with 97% similarity]
arch/sparc/prom/tree_64.c [moved from arch/sparc64/prom/tree.c with 100% similarity]
arch/sparc64/Kconfig [deleted file]
arch/sparc64/Kconfig.debug [deleted file]
arch/sparc64/Makefile [deleted file]
arch/sparc64/boot/Makefile [deleted file]
arch/sparc64/kernel/Makefile [deleted file]
arch/sparc64/kernel/asm-offsets.c [deleted file]
arch/sparc64/kernel/cpu.c [deleted file]
arch/sparc64/kernel/idprom.c [deleted file]
arch/sparc64/kernel/init_task.c [deleted file]
arch/sparc64/kernel/module.c [deleted file]
arch/sparc64/kernel/vmlinux.lds.S [deleted file]
arch/sparc64/lib/Makefile [deleted file]
arch/sparc64/lib/iomap.c [deleted file]
arch/sparc64/lib/memcmp.S [deleted file]
arch/sparc64/lib/strlen.S [deleted file]
arch/sparc64/math-emu/Makefile [deleted file]
arch/sparc64/mm/Makefile [deleted file]
arch/sparc64/oprofile/Makefile [deleted file]
arch/sparc64/oprofile/init.c [deleted file]
arch/sparc64/prom/Makefile [deleted file]
arch/sparc64/prom/printf.c [deleted file]
arch/um/include/asm/system.h
arch/x86/Kconfig
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/iommu.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pci_64.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/uaccess_32.h
arch/x86/include/asm/uaccess_64.h
arch/x86/kernel/Makefile
arch/x86/kernel/hpet.c
arch/x86/kernel/io_apic.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_32.c
arch/x86/kernel/irq_64.c
arch/x86/kernel/irqinit_32.c
arch/x86/kernel/irqinit_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-swiotlb_64.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup.c
arch/x86/lguest/i386_head.S
arch/x86/lib/usercopy_32.c
arch/x86/lib/usercopy_64.c
arch/x86/mm/init_32.c
arch/x86/oprofile/op_model_amd.c
block/Kconfig
block/as-iosched.c
block/blk-barrier.c
block/blk-core.c
block/blk-settings.c
block/blk-softirq.c
block/blk-sysfs.c
block/blk-tag.c
block/blk-timeout.c
block/cfq-iosched.c
block/compat_ioctl.c
block/deadline-iosched.c
block/elevator.c
block/genhd.c
block/ioctl.c
block/noop-iosched.c
block/scsi_ioctl.c
drivers/ata/ahci.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libata-acpi.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_it821x.c
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_legacy.c
drivers/ata/pata_oldpiix.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_platform.c
drivers/ata/pata_radisys.c
drivers/ata/pata_rz1000.c
drivers/ata/pata_scc.c
drivers/ata/pata_serverworks.c
drivers/ata/pata_sis.c
drivers/ata/sata_mv.c
drivers/ata/sata_sil.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/virtio_blk.c
drivers/block/xen-blkfront.c
drivers/cdrom/cdrom.c
drivers/char/agp/intel-agp.c
drivers/char/ds1620.c
drivers/char/hpet.c
drivers/char/hvc_console.c
drivers/char/nwflash.c
drivers/char/random.c
drivers/char/virtio_console.c
drivers/clocksource/acpi_pm.c
drivers/firmware/dmi_scan.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_context.c
drivers/gpu/drm/drm_crtc.c [new file with mode: 0644]
drivers/gpu/drm/drm_crtc_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c [new file with mode: 0644]
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_hashtab.c
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_modes.c [new file with mode: 0644]
drivers/gpu/drm/drm_proc.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo.h [new file with mode: 0644]
drivers/gpu/drm/i915/dvo_ch7017.c [new file with mode: 0644]
drivers/gpu/drm/i915/dvo_ch7xxx.c [new file with mode: 0644]
drivers/gpu/drm/i915/dvo_ivch.c [new file with mode: 0644]
drivers/gpu/drm/i915/dvo_sil164.c [new file with mode: 0644]
drivers/gpu/drm/i915/dvo_tfp410.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_proc.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_mem.c
drivers/gpu/drm/i915/i915_opregion.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_bios.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_bios.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_crt.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_display.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_drv.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_dvo.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_fb.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_i2c.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_lvds.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_modes.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_sdvo.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_sdvo_regs.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_tv.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r300_cmdbuf.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_state.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/cmd64x.c
drivers/ide/cy82c693.c
drivers/ide/gayle.c
drivers/ide/hpt366.c
drivers/ide/ide-acpi.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-dma-sff.c
drivers/ide/ide-io.c
drivers/ide/ide-ioctls.c
drivers/ide/ide-iops.c
drivers/ide/ide-legacy.c [new file with mode: 0644]
drivers/ide/ide-lib.c
drivers/ide/ide-park.c
drivers/ide/ide-pm.c [new file with mode: 0644]
drivers/ide/ide-probe.c
drivers/ide/ide-proc.c
drivers/ide/ide.c
drivers/ide/ide_arm.c
drivers/ide/pdc202xx_old.c
drivers/ide/rz1000.c
drivers/ide/trm290.c
drivers/ide/tx4938ide.c
drivers/ide/tx4939ide.c
drivers/ide/umc8672.c
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/serio/Kconfig
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/mainstone-wm97xx.c
drivers/lguest/lg.h
drivers/lguest/lguest_device.c
drivers/lguest/lguest_user.c
drivers/lguest/page_tables.c
drivers/md/dm-crypt.c
drivers/md/dm-io.c
drivers/md/dm.c
drivers/media/common/ir-keymaps.c
drivers/media/common/saa7146_fops.c
drivers/media/common/saa7146_video.c
drivers/media/common/tuners/mxl5005s.c
drivers/media/common/tuners/tda827x.c
drivers/media/common/tuners/tda8290.c
drivers/media/common/tuners/tda9887.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/Kconfig
drivers/media/dvb/b2c2/Kconfig
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h
drivers/media/dvb/dvb-usb/anysee.c
drivers/media/dvb/dvb-usb/cinergyT2-core.c
drivers/media/dvb/dvb-usb/cinergyT2.h
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/gp8psk-fe.c
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/dvb-usb/gp8psk.h
drivers/media/dvb/dvb-usb/usb-urb.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/cx24113.c [new file with mode: 0644]
drivers/media/dvb/frontends/cx24113.h
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/dib7000p.h
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/drx397xD_fw.h
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/lgdt3304.c [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt3304.h [new file with mode: 0644]
drivers/media/dvb/frontends/s5h1411.c
drivers/media/dvb/frontends/s921_core.c [new file with mode: 0644]
drivers/media/dvb/frontends/s921_core.h [new file with mode: 0644]
drivers/media/dvb/frontends/s921_module.c [new file with mode: 0644]
drivers/media/dvb/frontends/s921_module.h [new file with mode: 0644]
drivers/media/dvb/frontends/si21xx.c
drivers/media/dvb/frontends/stb0899_algo.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_cfg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_drv.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_drv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb0899_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb6100.c [new file with mode: 0644]
drivers/media/dvb/frontends/stb6100.h [new file with mode: 0644]
drivers/media/dvb/frontends/stb6100_cfg.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda8261.c [new file with mode: 0644]
drivers/media/dvb/frontends/tda8261.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda8261_cfg.h [new file with mode: 0644]
drivers/media/dvb/frontends/zl10353.c
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/siano/sms-cards.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/dvb/siano/smsdvb.c
drivers/media/dvb/siano/smsusb.c
drivers/media/dvb/ttpci/Kconfig
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget-ci.c
drivers/media/dvb/ttpci/budget.h
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-rtrack2.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/arv.c
drivers/media/video/bt8xx/bt832.c [deleted file]
drivers/media/video/bt8xx/bt832.h [deleted file]
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-gpio.c
drivers/media/video/bt8xx/bttv.h
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/bw-qcam.c
drivers/media/video/c-qcam.c
drivers/media/video/cpia.c
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_usb.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cs5345.c
drivers/media/video/cs53l32a.c
drivers/media/video/cx18/cx18-av-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-core.h
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-av-vbi.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-cards.h
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-dvb.h
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-firmware.c
drivers/media/video/cx18/cx18-gpio.c
drivers/media/video/cx18/cx18-gpio.h
drivers/media/video/cx18/cx18-i2c.c
drivers/media/video/cx18/cx18-io.c
drivers/media/video/cx18/cx18-io.h
drivers/media/video/cx18/cx18-ioctl.c
drivers/media/video/cx18/cx18-ioctl.h
drivers/media/video/cx18/cx18-irq.c
drivers/media/video/cx18/cx18-irq.h
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-mailbox.h
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-queue.h
drivers/media/video/cx18/cx18-scb.c
drivers/media/video/cx18/cx18-scb.h
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-streams.h
drivers/media/video/cx18/cx18-vbi.c
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx18/cx23418.h
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx25840/Kconfig
drivers/media/video/cx25840/cx25840-audio.c
drivers/media/video/cx25840/cx25840-core.c
drivers/media/video/cx25840/cx25840-core.h
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/cx25840/cx25840-vbi.c
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-blackbird.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-mpeg.c
drivers/media/video/cx88/cx88.h
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h
drivers/media/video/et61x251/et61x251_core.c
drivers/media/video/gspca/Kconfig
drivers/media/video/gspca/Makefile
drivers/media/video/gspca/conex.c
drivers/media/video/gspca/etoms.c
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/m5602_bridge.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/m5602/m5602_sensor.h
drivers/media/video/gspca/mars.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c [new file with mode: 0644]
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca501.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca506.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/stk014.c
drivers/media/video/gspca/stv06xx/Kconfig [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/Makefile [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_sensor.h [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c [new file with mode: 0644]
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h [new file with mode: 0644]
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/tv8532.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx-reg.h
drivers/media/video/gspca/zc3xx.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-cards.c
drivers/media/video/ivtv/ivtv-controls.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-gpio.h
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-i2c.h
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-routing.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/ivtv/ivtv-vbi.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/m52790.c
drivers/media/video/msp3400-driver.c
drivers/media/video/msp3400-driver.h
drivers/media/video/msp3400-kthreads.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c [new file with mode: 0644]
drivers/media/video/mt9v022.c
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/ov511.c
drivers/media/video/ov772x.c [new file with mode: 0644]
drivers/media/video/pms.c
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pwc/pwc.h
drivers/media/video/pxa_camera.c
drivers/media/video/pxa_camera.h [new file with mode: 0644]
drivers/media/video/saa5246a.c
drivers/media/video/saa5249.c
drivers/media/video/saa7115.c
drivers/media/video/saa7127.c
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-tvaudio.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/saa717x.c
drivers/media/video/se401.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/sn9c102/sn9c102_core.c
drivers/media/video/sn9c102/sn9c102_devtable.h
drivers/media/video/soc_camera.c
drivers/media/video/soc_camera_platform.c
drivers/media/video/stk-webcam.c
drivers/media/video/stv680.c
drivers/media/video/tda7432.c
drivers/media/video/tda9840.c
drivers/media/video/tda9875.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/tlv320aic23b.c
drivers/media/video/tuner-core.c
drivers/media/video/tvaudio.c
drivers/media/video/tvp514x.c [new file with mode: 0644]
drivers/media/video/tvp514x_regs.h [new file with mode: 0644]
drivers/media/video/tvp5150.c
drivers/media/video/tw9910.c [new file with mode: 0644]
drivers/media/video/upd64031a.c
drivers/media/video/upd64083.c
drivers/media/video/usbvideo/ibmcam.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvideo/ultracam.c
drivers/media/video/usbvideo/usbvideo.c
drivers/media/video/usbvideo/vicam.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-compat-ioctl32.c [moved from drivers/media/video/compat_ioctl32.c with 53% similarity]
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c [new file with mode: 0644]
drivers/media/video/v4l2-ioctl.c
drivers/media/video/v4l2-subdev.c [new file with mode: 0644]
drivers/media/video/vino.c
drivers/media/video/vp27smpx.c
drivers/media/video/w9966.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/media/video/zc0301/zc0301_core.c
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zoran/zoran_driver.c
drivers/mfd/asic3.c
drivers/mfd/mcp-core.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/ucb1x00-assabet.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/ucb1x00-ts.c
drivers/mmc/host/imxmmc.c
drivers/mmc/host/imxmmc.h
drivers/mmc/host/mmci.c
drivers/mmc/host/omap.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mtd/maps/dc21285.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/onenand/omap2.c
drivers/net/arm/ep93xx_eth.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/arm/ks8695net.c
drivers/net/cs89x0.c
drivers/net/eexpress.h
drivers/net/irda/pxaficp_ir.c
drivers/net/irda/sa1100_ir.c
drivers/net/mlx4/en_main.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/en_params.c
drivers/net/mlx4/mlx4_en.h
drivers/net/pasemi_mac.c
drivers/net/smc911x.h
drivers/net/smc91x.h
drivers/net/smsc911x.c
drivers/net/spider_net.c
drivers/net/tun.c
drivers/net/usb/hso.c
drivers/net/wan/ixp4xx_hss.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/oprofile/buffer_sync.c
drivers/oprofile/cpu_buffer.c
drivers/oprofile/cpu_buffer.h
drivers/oprofile/oprofile_files.c
drivers/pci/intr_remapping.c
drivers/pci/msi.c
drivers/pcmcia/Kconfig
drivers/pcmcia/Makefile
drivers/pcmcia/pxa2xx_e740.c [new file with mode: 0644]
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/s390/kvm/kvm_virtio.c
drivers/scsi/ide-scsi.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/amba-pl010.c
drivers/serial/amba-pl011.c
drivers/serial/imx.c
drivers/serial/pxa.c
drivers/serial/s3c24a0.c [new file with mode: 0644]
drivers/serial/s3c6400.c [new file with mode: 0644]
drivers/serial/samsung.c
drivers/serial/samsung.h
drivers/serial/serial_lh7a40x.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi_s3c24xx.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pxa27x.c
drivers/video/Kconfig
drivers/video/amba-clcd.c
drivers/video/console/vgacon.c
drivers/video/cyber2000fb.c
drivers/video/imxfb.c
drivers/video/imxfb.h [deleted file]
drivers/video/pxafb.c
drivers/video/pxafb.h
drivers/video/sa1100fb.c
drivers/virtio/virtio.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/xen/events.c
firmware/Makefile
fs/aio.c
fs/bio-integrity.c
fs/bio.c
fs/buffer.c
fs/exec.c
fs/ext4/super.c
fs/jfs/inode.c
fs/proc/stat.c
include/asm-generic/bug.h
include/drm/Kbuild
include/drm/drm.h
include/drm/drmP.h
include/drm/drm_crtc.h [new file with mode: 0644]
include/drm/drm_crtc_helper.h [new file with mode: 0644]
include/drm/drm_edid.h [new file with mode: 0644]
include/drm/drm_mode.h [new file with mode: 0644]
include/drm/drm_sarea.h
include/drm/i915_drm.h
include/linux/Kbuild
include/linux/aio.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/bottom_half.h
include/linux/buffer_head.h
include/linux/console.h
include/linux/debug_locks.h
include/linux/dmi.h
include/linux/elevator.h
include/linux/fault-inject.h
include/linux/futex.h
include/linux/genhd.h
include/linux/hardirq.h
include/linux/hrtimer.h
include/linux/ide.h
include/linux/interrupt.h
include/linux/irq.h
include/linux/irqnr.h
include/linux/kernel.h
include/linux/kernel_stat.h
include/linux/lguest_launcher.h
include/linux/libata.h
include/linux/lockdep.h
include/linux/mm_types.h
include/linux/msi.h
include/linux/mutex.h
include/linux/of_platform.h
include/linux/oprofile.h
include/linux/posix-timers.h
include/linux/random.h
include/linux/rcuclassic.h
include/linux/rcupdate.h
include/linux/rcutree.h [new file with mode: 0644]
include/linux/ring_buffer.h
include/linux/serial_core.h
include/linux/slab.h
include/linux/swiotlb.h
include/linux/timex.h
include/linux/types.h
include/linux/uaccess.h
include/linux/videodev2.h
include/linux/virtio_balloon.h
include/linux/virtio_console.h
include/linux/virtio_pci.h
include/linux/virtio_ring.h
include/media/i2c-addr.h
include/media/ir-common.h
include/media/ov772x.h [new file with mode: 0644]
include/media/saa7146_vv.h
include/media/soc_camera.h
include/media/tvp514x.h [new file with mode: 0644]
include/media/tw9910.h [new file with mode: 0644]
include/media/v4l2-chip-ident.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-device.h [new file with mode: 0644]
include/media/v4l2-int-device.h
include/media/v4l2-ioctl.h
include/media/v4l2-subdev.h [new file with mode: 0644]
init/Kconfig
init/main.c
kernel/Kconfig.preempt
kernel/Makefile
kernel/exit.c
kernel/extable.c
kernel/fork.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/Makefile
kernel/irq/autoprobe.c
kernel/irq/chip.c
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/manage.c
kernel/irq/numa_migrate.c [new file with mode: 0644]
kernel/irq/proc.c
kernel/irq/spurious.c
kernel/lockdep.c
kernel/lockdep_proc.c
kernel/mutex.c
kernel/notifier.c
kernel/panic.c
kernel/posix-cpu-timers.c
kernel/posix-timers.c
kernel/printk.c
kernel/rcuclassic.c
kernel/rcupreempt.c
kernel/rcupreempt_trace.c
kernel/rcutorture.c
kernel/rcutree.c [new file with mode: 0644]
kernel/rcutree_trace.c [new file with mode: 0644]
kernel/resource.c
kernel/sched.c
kernel/softirq.c
kernel/softlockup.c
kernel/stacktrace.c
kernel/sys.c
kernel/sysctl.c
kernel/time/ntp.c
kernel/time/tick-sched.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace_sysprof.c
lib/Kconfig.debug
lib/debugobjects.c
lib/swiotlb.c
mm/Makefile
mm/bounce.c
mm/failslab.c [new file with mode: 0644]
mm/memory.c
mm/slab.c
mm/slub.c
net/core/dev.c
net/core/neighbour.c
net/dccp/proto.c
net/ipv4/inet_connection_sock.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv4/proc.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/ipvs/ip_vs_lblcr.c
net/netfilter/ipvs/ip_vs_lc.c
net/netfilter/ipvs/ip_vs_nq.c
net/netfilter/ipvs/ip_vs_rr.c
net/netfilter/ipvs/ip_vs_sed.c
net/netfilter/ipvs/ip_vs_sh.c
net/netfilter/ipvs/ip_vs_wlc.c
net/netfilter/ipvs/ip_vs_wrr.c
net/netfilter/nf_conntrack_standalone.c
net/sched/Kconfig
net/sched/cls_cgroup.c
net/xfrm/xfrm_proc.c
security/keys/keyctl.c
sound/arm/pxa2xx-ac97-lib.c
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm.h
sound/core/hrtimer.c
sound/drivers/pcsp/pcsp.c
sound/i2c/other/tea575x-tuner.c
sound/oss/waveartist.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/s3c24xx/s3c2443-ac97.c

index 461481dfb7c31b4bfbb0509993ec0c2351cc97c2..7dc0695a8f902994647300b87a00cb9241d152fa 100644 (file)
@@ -16,6 +16,8 @@ RTFP.txt
        - List of RCU papers (bibliography) going back to 1980.
 torture.txt
        - RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST)
+trace.txt
+       - CONFIG_RCU_TRACE debugfs files and formats
 UP.txt
        - RCU on Uniprocessor Systems
 whatisRCU.txt
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
new file mode 100644 (file)
index 0000000..0688482
--- /dev/null
@@ -0,0 +1,413 @@
+CONFIG_RCU_TRACE debugfs Files and Formats
+
+
+The rcupreempt and rcutree implementations of RCU provide debugfs trace
+output that summarizes counters and state.  This information is useful for
+debugging RCU itself, and can sometimes also help to debug abuses of RCU.
+Note that the rcuclassic implementation of RCU does not provide debugfs
+trace output.
+
+The following sections describe the debugfs files and formats for
+preemptable RCU (rcupreempt) and hierarchical RCU (rcutree).
+
+
+Preemptable RCU debugfs Files and Formats
+
+This implementation of RCU provides three debugfs files under the
+top-level directory RCU: rcu/rcuctrs (which displays the per-CPU
+counters used by preemptable RCU) rcu/rcugp (which displays grace-period
+counters), and rcu/rcustats (which internal counters for debugging RCU).
+
+The output of "cat rcu/rcuctrs" looks as follows:
+
+CPU last cur F M
+  0    5  -5 0 0
+  1   -1   0 0 0
+  2    0   1 0 0
+  3    0   1 0 0
+  4    0   1 0 0
+  5    0   1 0 0
+  6    0   2 0 0
+  7    0  -1 0 0
+  8    0   1 0 0
+ggp = 26226, state = waitzero
+
+The per-CPU fields are as follows:
+
+o      "CPU" gives the CPU number.  Offline CPUs are not displayed.
+
+o      "last" gives the value of the counter that is being decremented
+       for the current grace period phase.  In the example above,
+       the counters sum to 4, indicating that there are still four
+       RCU read-side critical sections still running that started
+       before the last counter flip.
+
+o      "cur" gives the value of the counter that is currently being
+       both incremented (by rcu_read_lock()) and decremented (by
+       rcu_read_unlock()).  In the example above, the counters sum to
+       1, indicating that there is only one RCU read-side critical section
+       still running that started after the last counter flip.
+
+o      "F" indicates whether RCU is waiting for this CPU to acknowledge
+       a counter flip.  In the above example, RCU is not waiting on any,
+       which is consistent with the state being "waitzero" rather than
+       "waitack".
+
+o      "M" indicates whether RCU is waiting for this CPU to execute a
+       memory barrier.  In the above example, RCU is not waiting on any,
+       which is consistent with the state being "waitzero" rather than
+       "waitmb".
+
+o      "ggp" is the global grace-period counter.
+
+o      "state" is the RCU state, which can be one of the following:
+
+       o       "idle": there is no grace period in progress.
+
+       o       "waitack": RCU just incremented the global grace-period
+               counter, which has the effect of reversing the roles of
+               the "last" and "cur" counters above, and is waiting for
+               all the CPUs to acknowledge the flip.  Once the flip has
+               been acknowledged, CPUs will no longer be incrementing
+               what are now the "last" counters, so that their sum will
+               decrease monotonically down to zero.
+
+       o       "waitzero": RCU is waiting for the sum of the "last" counters
+               to decrease to zero.
+
+       o       "waitmb": RCU is waiting for each CPU to execute a memory
+               barrier, which ensures that instructions from a given CPU's
+               last RCU read-side critical section cannot be reordered
+               with instructions following the memory-barrier instruction.
+
+The output of "cat rcu/rcugp" looks as follows:
+
+oldggp=48870  newggp=48873
+
+Note that reading from this file provokes a synchronize_rcu().  The
+"oldggp" value is that of "ggp" from rcu/rcuctrs above, taken before
+executing the synchronize_rcu(), and the "newggp" value is also the
+"ggp" value, but taken after the synchronize_rcu() command returns.
+
+
+The output of "cat rcu/rcugp" looks as follows:
+
+na=1337955 nl=40 wa=1337915 wl=44 da=1337871 dl=0 dr=1337871 di=1337871
+1=50989 e1=6138 i1=49722 ie1=82 g1=49640 a1=315203 ae1=265563 a2=49640
+z1=1401244 ze1=1351605 z2=49639 m1=5661253 me1=5611614 m2=49639
+
+These are counters tracking internal preemptable-RCU events, however,
+some of them may be useful for debugging algorithms using RCU.  In
+particular, the "nl", "wl", and "dl" values track the number of RCU
+callbacks in various states.  The fields are as follows:
+
+o      "na" is the total number of RCU callbacks that have been enqueued
+       since boot.
+
+o      "nl" is the number of RCU callbacks waiting for the previous
+       grace period to end so that they can start waiting on the next
+       grace period.
+
+o      "wa" is the total number of RCU callbacks that have started waiting
+       for a grace period since boot.  "na" should be roughly equal to
+       "nl" plus "wa".
+
+o      "wl" is the number of RCU callbacks currently waiting for their
+       grace period to end.
+
+o      "da" is the total number of RCU callbacks whose grace periods
+       have completed since boot.  "wa" should be roughly equal to
+       "wl" plus "da".
+
+o      "dr" is the total number of RCU callbacks that have been removed
+       from the list of callbacks ready to invoke.  "dr" should be roughly
+       equal to "da".
+
+o      "di" is the total number of RCU callbacks that have been invoked
+       since boot.  "di" should be roughly equal to "da", though some
+       early versions of preemptable RCU had a bug so that only the
+       last CPU's count of invocations was displayed, rather than the
+       sum of all CPU's counts.
+
+o      "1" is the number of calls to rcu_try_flip().  This should be
+       roughly equal to the sum of "e1", "i1", "a1", "z1", and "m1"
+       described below.  In other words, the number of times that
+       the state machine is visited should be equal to the sum of the
+       number of times that each state is visited plus the number of
+       times that the state-machine lock acquisition failed.
+
+o      "e1" is the number of times that rcu_try_flip() was unable to
+       acquire the fliplock.
+
+o      "i1" is the number of calls to rcu_try_flip_idle().
+
+o      "ie1" is the number of times rcu_try_flip_idle() exited early
+       due to the calling CPU having no work for RCU.
+
+o      "g1" is the number of times that rcu_try_flip_idle() decided
+       to start a new grace period.  "i1" should be roughly equal to
+       "ie1" plus "g1".
+
+o      "a1" is the number of calls to rcu_try_flip_waitack().
+
+o      "ae1" is the number of times that rcu_try_flip_waitack() found
+       that at least one CPU had not yet acknowledge the new grace period
+       (AKA "counter flip").
+
+o      "a2" is the number of time rcu_try_flip_waitack() found that
+       all CPUs had acknowledged.  "a1" should be roughly equal to
+       "ae1" plus "a2".  (This particular output was collected on
+       a 128-CPU machine, hence the smaller-than-usual fraction of
+       calls to rcu_try_flip_waitack() finding all CPUs having already
+       acknowledged.)
+
+o      "z1" is the number of calls to rcu_try_flip_waitzero().
+
+o      "ze1" is the number of times that rcu_try_flip_waitzero() found
+       that not all of the old RCU read-side critical sections had
+       completed.
+
+o      "z2" is the number of times that rcu_try_flip_waitzero() finds
+       the sum of the counters equal to zero, in other words, that
+       all of the old RCU read-side critical sections had completed.
+       The value of "z1" should be roughly equal to "ze1" plus
+       "z2".
+
+o      "m1" is the number of calls to rcu_try_flip_waitmb().
+
+o      "me1" is the number of times that rcu_try_flip_waitmb() finds
+       that at least one CPU has not yet executed a memory barrier.
+
+o      "m2" is the number of times that rcu_try_flip_waitmb() finds that
+       all CPUs have executed a memory barrier.
+
+
+Hierarchical RCU debugfs Files and Formats
+
+This implementation of RCU provides three debugfs files under the
+top-level directory RCU: rcu/rcudata (which displays fields in struct
+rcu_data), rcu/rcugp (which displays grace-period counters), and
+rcu/rcuhier (which displays the struct rcu_node hierarchy).
+
+The output of "cat rcu/rcudata" looks as follows:
+
+rcu:
+  0 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=1 rp=3c2a dt=23301/73 dn=2 df=1882 of=0 ri=2126 ql=2 b=10
+  1 c=4011 g=4012 pq=1 pqc=4011 qp=0 rpfq=3 rp=39a6 dt=78073/1 dn=2 df=1402 of=0 ri=1875 ql=46 b=10
+  2 c=4010 g=4010 pq=1 pqc=4010 qp=0 rpfq=-5 rp=1d12 dt=16646/0 dn=2 df=3140 of=0 ri=2080 ql=0 b=10
+  3 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=2b50 dt=21159/1 dn=2 df=2230 of=0 ri=1923 ql=72 b=10
+  4 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1644 dt=5783/1 dn=2 df=3348 of=0 ri=2805 ql=7 b=10
+  5 c=4012 g=4013 pq=0 pqc=4011 qp=1 rpfq=3 rp=1aac dt=5879/1 dn=2 df=3140 of=0 ri=2066 ql=10 b=10
+  6 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=ed8 dt=5847/1 dn=2 df=3797 of=0 ri=1266 ql=10 b=10
+  7 c=4012 g=4013 pq=1 pqc=4012 qp=1 rpfq=3 rp=1fa2 dt=6199/1 dn=2 df=2795 of=0 ri=2162 ql=28 b=10
+rcu_bh:
+  0 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-145 rp=21d6 dt=23301/73 dn=2 df=0 of=0 ri=0 ql=0 b=10
+  1 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-170 rp=20ce dt=78073/1 dn=2 df=26 of=0 ri=5 ql=0 b=10
+  2 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-83 rp=fbd dt=16646/0 dn=2 df=28 of=0 ri=4 ql=0 b=10
+  3 c=-268 g=-268 pq=1 pqc=-268 qp=0 rpfq=-105 rp=178c dt=21159/1 dn=2 df=28 of=0 ri=2 ql=0 b=10
+  4 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-30 rp=b54 dt=5783/1 dn=2 df=32 of=0 ri=0 ql=0 b=10
+  5 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-29 rp=df5 dt=5879/1 dn=2 df=30 of=0 ri=3 ql=0 b=10
+  6 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-28 rp=788 dt=5847/1 dn=2 df=32 of=0 ri=0 ql=0 b=10
+  7 c=-268 g=-268 pq=1 pqc=-268 qp=1 rpfq=-53 rp=1098 dt=6199/1 dn=2 df=30 of=0 ri=3 ql=0 b=10
+
+The first section lists the rcu_data structures for rcu, the second for
+rcu_bh.  Each section has one line per CPU, or eight for this 8-CPU system.
+The fields are as follows:
+
+o      The number at the beginning of each line is the CPU number.
+       CPUs numbers followed by an exclamation mark are offline,
+       but have been online at least once since boot.  There will be
+       no output for CPUs that have never been online, which can be
+       a good thing in the surprisingly common case where NR_CPUS is
+       substantially larger than the number of actual CPUs.
+
+o      "c" is the count of grace periods that this CPU believes have
+       completed.  CPUs in dynticks idle mode may lag quite a ways
+       behind, for example, CPU 4 under "rcu" above, which has slept
+       through the past 25 RCU grace periods.  It is not unusual to
+       see CPUs lagging by thousands of grace periods.
+
+o      "g" is the count of grace periods that this CPU believes have
+       started.  Again, CPUs in dynticks idle mode may lag behind.
+       If the "c" and "g" values are equal, this CPU has already
+       reported a quiescent state for the last RCU grace period that
+       it is aware of, otherwise, the CPU believes that it owes RCU a
+       quiescent state.
+
+o      "pq" indicates that this CPU has passed through a quiescent state
+       for the current grace period.  It is possible for "pq" to be
+       "1" and "c" different than "g", which indicates that although
+       the CPU has passed through a quiescent state, either (1) this
+       CPU has not yet reported that fact, (2) some other CPU has not
+       yet reported for this grace period, or (3) both.
+
+o      "pqc" indicates which grace period the last-observed quiescent
+       state for this CPU corresponds to.  This is important for handling
+       the race between CPU 0 reporting an extended dynticks-idle
+       quiescent state for CPU 1 and CPU 1 suddenly waking up and
+       reporting its own quiescent state.  If CPU 1 was the last CPU
+       for the current grace period, then the CPU that loses this race
+       will attempt to incorrectly mark CPU 1 as having checked in for
+       the next grace period!
+
+o      "qp" indicates that RCU still expects a quiescent state from
+       this CPU.
+
+o      "rpfq" is the number of rcu_pending() calls on this CPU required
+       to induce this CPU to invoke force_quiescent_state().
+
+o      "rp" is low-order four hex digits of the count of how many times
+       rcu_pending() has been invoked on this CPU.
+
+o      "dt" is the current value of the dyntick counter that is incremented
+       when entering or leaving dynticks idle state, either by the
+       scheduler or by irq.  The number after the "/" is the interrupt
+       nesting depth when in dyntick-idle state, or one greater than
+       the interrupt-nesting depth otherwise.
+
+       This field is displayed only for CONFIG_NO_HZ kernels.
+
+o      "dn" is the current value of the dyntick counter that is incremented
+       when entering or leaving dynticks idle state via NMI.  If both
+       the "dt" and "dn" values are even, then this CPU is in dynticks
+       idle mode and may be ignored by RCU.  If either of these two
+       counters is odd, then RCU must be alert to the possibility of
+       an RCU read-side critical section running on this CPU.
+
+       This field is displayed only for CONFIG_NO_HZ kernels.
+
+o      "df" is the number of times that some other CPU has forced a
+       quiescent state on behalf of this CPU due to this CPU being in
+       dynticks-idle state.
+
+       This field is displayed only for CONFIG_NO_HZ kernels.
+
+o      "of" is the number of times that some other CPU has forced a
+       quiescent state on behalf of this CPU due to this CPU being
+       offline.  In a perfect world, this might neve happen, but it
+       turns out that offlining and onlining a CPU can take several grace
+       periods, and so there is likely to be an extended period of time
+       when RCU believes that the CPU is online when it really is not.
+       Please note that erring in the other direction (RCU believing a
+       CPU is offline when it is really alive and kicking) is a fatal
+       error, so it makes sense to err conservatively.
+
+o      "ri" is the number of times that RCU has seen fit to send a
+       reschedule IPI to this CPU in order to get it to report a
+       quiescent state.
+
+o      "ql" is the number of RCU callbacks currently residing on
+       this CPU.  This is the total number of callbacks, regardless
+       of what state they are in (new, waiting for grace period to
+       start, waiting for grace period to end, ready to invoke).
+
+o      "b" is the batch limit for this CPU.  If more than this number
+       of RCU callbacks is ready to invoke, then the remainder will
+       be deferred.
+
+
+The output of "cat rcu/rcugp" looks as follows:
+
+rcu: completed=33062  gpnum=33063
+rcu_bh: completed=464  gpnum=464
+
+Again, this output is for both "rcu" and "rcu_bh".  The fields are
+taken from the rcu_state structure, and are as follows:
+
+o      "completed" is the number of grace periods that have completed.
+       It is comparable to the "c" field from rcu/rcudata in that a
+       CPU whose "c" field matches the value of "completed" is aware
+       that the corresponding RCU grace period has completed.
+
+o      "gpnum" is the number of grace periods that have started.  It is
+       comparable to the "g" field from rcu/rcudata in that a CPU
+       whose "g" field matches the value of "gpnum" is aware that the
+       corresponding RCU grace period has started.
+
+       If these two fields are equal (as they are for "rcu_bh" above),
+       then there is no grace period in progress, in other words, RCU
+       is idle.  On the other hand, if the two fields differ (as they
+       do for "rcu" above), then an RCU grace period is in progress.
+
+
+The output of "cat rcu/rcuhier" looks as follows, with very long lines:
+
+c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6
+1/1 0:127 ^0    
+3/3 0:35 ^0    0/0 36:71 ^1    0/0 72:107 ^2    0/0 108:127 ^3    
+3/3f 0:5 ^0    2/3 6:11 ^1    0/0 12:17 ^2    0/0 18:23 ^3    0/0 24:29 ^4    0/0 30:35 ^5    0/0 36:41 ^0    0/0 42:47 ^1    0/0 48:53 ^2    0/0 54:59 ^3    0/0 60:65 ^4    0/0 66:71 ^5    0/0 72:77 ^0    0/0 78:83 ^1    0/0 84:89 ^2    0/0 90:95 ^3    0/0 96:101 ^4    0/0 102:107 ^5    0/0 108:113 ^0    0/0 114:119 ^1    0/0 120:125 ^2    0/0 126:127 ^3    
+rcu_bh:
+c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0
+0/1 0:127 ^0    
+0/3 0:35 ^0    0/0 36:71 ^1    0/0 72:107 ^2    0/0 108:127 ^3    
+0/3f 0:5 ^0    0/3 6:11 ^1    0/0 12:17 ^2    0/0 18:23 ^3    0/0 24:29 ^4    0/0 30:35 ^5    0/0 36:41 ^0    0/0 42:47 ^1    0/0 48:53 ^2    0/0 54:59 ^3    0/0 60:65 ^4    0/0 66:71 ^5    0/0 72:77 ^0    0/0 78:83 ^1    0/0 84:89 ^2    0/0 90:95 ^3    0/0 96:101 ^4    0/0 102:107 ^5    0/0 108:113 ^0    0/0 114:119 ^1    0/0 120:125 ^2    0/0 126:127 ^3
+
+This is once again split into "rcu" and "rcu_bh" portions.  The fields are
+as follows:
+
+o      "c" is exactly the same as "completed" under rcu/rcugp.
+
+o      "g" is exactly the same as "gpnum" under rcu/rcugp.
+
+o      "s" is the "signaled" state that drives force_quiescent_state()'s
+       state machine.
+
+o      "jfq" is the number of jiffies remaining for this grace period
+       before force_quiescent_state() is invoked to help push things
+       along.  Note that CPUs in dyntick-idle mode thoughout the grace
+       period will not report on their own, but rather must be check by
+       some other CPU via force_quiescent_state().
+
+o      "j" is the low-order four hex digits of the jiffies counter.
+       Yes, Paul did run into a number of problems that turned out to
+       be due to the jiffies counter no longer counting.  Why do you ask?
+
+o      "nfqs" is the number of calls to force_quiescent_state() since
+       boot.
+
+o      "nfqsng" is the number of useless calls to force_quiescent_state(),
+       where there wasn't actually a grace period active.  This can
+       happen due to races.  The number in parentheses is the difference
+       between "nfqs" and "nfqsng", or the number of times that
+       force_quiescent_state() actually did some real work.
+
+o      "fqlh" is the number of calls to force_quiescent_state() that
+       exited immediately (without even being counted in nfqs above)
+       due to contention on ->fqslock.
+
+o      Each element of the form "1/1 0:127 ^0" represents one struct
+       rcu_node.  Each line represents one level of the hierarchy, from
+       root to leaves.  It is best to think of the rcu_data structures
+       as forming yet another level after the leaves.  Note that there
+       might be either one, two, or three levels of rcu_node structures,
+       depending on the relationship between CONFIG_RCU_FANOUT and
+       CONFIG_NR_CPUS.
+       
+       o       The numbers separated by the "/" are the qsmask followed
+               by the qsmaskinit.  The qsmask will have one bit
+               set for each entity in the next lower level that
+               has not yet checked in for the current grace period.
+               The qsmaskinit will have one bit for each entity that is
+               currently expected to check in during each grace period.
+               The value of qsmaskinit is assigned to that of qsmask
+               at the beginning of each grace period.
+
+               For example, for "rcu", the qsmask of the first entry
+               of the lowest level is 0x14, meaning that we are still
+               waiting for CPUs 2 and 4 to check in for the current
+               grace period.
+
+       o       The numbers separated by the ":" are the range of CPUs
+               served by this struct rcu_node.  This can be helpful
+               in working out how the hierarchy is wired together.
+
+               For example, the first entry at the lowest level shows
+               "0:5", indicating that it covers CPUs 0 through 5.
+
+       o       The number after the "^" indicates the bit in the
+               next higher level rcu_node structure that this
+               rcu_node structure corresponds to.
+
+               For example, the first entry at the lowest level shows
+               "^0", indicating that it corresponds to bit zero in
+               the first entry at the middle level.
diff --git a/Documentation/arm/pxa/mfp.txt b/Documentation/arm/pxa/mfp.txt
new file mode 100644 (file)
index 0000000..a179e5b
--- /dev/null
@@ -0,0 +1,286 @@
+                 MFP Configuration for PXA2xx/PXA3xx Processors
+
+                       Eric Miao <eric.miao@marvell.com>
+
+MFP stands for Multi-Function Pin, which is the pin-mux logic on PXA3xx and
+later PXA series processors.  This document describes the existing MFP API,
+and how board/platform driver authors could make use of it.
+
+ Basic Concept
+===============
+
+Unlike the GPIO alternate function settings on PXA25x and PXA27x, a new MFP
+mechanism is introduced from PXA3xx to completely move the pin-mux functions
+out of the GPIO controller. In addition to pin-mux configurations, the MFP
+also controls the low power state, driving strength, pull-up/down and event
+detection of each pin.  Below is a diagram of internal connections between
+the MFP logic and the remaining SoC peripherals:
+
+ +--------+
+ |        |--(GPIO19)--+
+ |  GPIO  |            |
+ |        |--(GPIO...) |
+ +--------+            |
+                       |       +---------+
+ +--------+            +------>|         |
+ |  PWM2  |--(PWM_OUT)-------->|   MFP   |
+ +--------+            +------>|         |-------> to external PAD
+                       | +---->|         |
+ +--------+            | | +-->|         |
+ |  SSP2  |---(TXD)----+ | |   +---------+
+ +--------+              | |
+                         | |
+ +--------+              | |
+ | Keypad |--(MKOUT4)----+ |
+ +--------+                |
+                           |
+ +--------+                |
+ |  UART2 |---(TXD)--------+
+ +--------+
+
+NOTE: the external pad is named as MFP_PIN_GPIO19, it doesn't necessarily
+mean it's dedicated for GPIO19, only as a hint that internally this pin
+can be routed from GPIO19 of the GPIO controller.
+
+To better understand the change from PXA25x/PXA27x GPIO alternate function
+to this new MFP mechanism, here are several key points:
+
+  1. GPIO controller on PXA3xx is now a dedicated controller, same as other
+     internal controllers like PWM, SSP and UART, with 128 internal signals
+     which can be routed to external through one or more MFPs (e.g. GPIO<0>
+     can be routed through either MFP_PIN_GPIO0 as well as MFP_PIN_GPIO0_2,
+     see arch/arm/mach-pxa/mach/include/mfp-pxa300.h)
+
+  2. Alternate function configuration is removed from this GPIO controller,
+     the remaining functions are pure GPIO-specific, i.e.
+
+       - GPIO signal level control
+       - GPIO direction control
+       - GPIO level change detection
+
+  3. Low power state for each pin is now controlled by MFP, this means the
+     PGSRx registers on PXA2xx are now useless on PXA3xx
+
+  4. Wakeup detection is now controlled by MFP, PWER does not control the
+     wakeup from GPIO(s) any more, depending on the sleeping state, ADxER
+     (as defined in pxa3xx-regs.h) controls the wakeup from MFP
+
+NOTE: with such a clear separation of MFP and GPIO, by GPIO<xx> we normally
+mean it is a GPIO signal, and by MFP<xxx> or pin xxx, we mean a physical
+pad (or ball).
+
+ MFP API Usage
+===============
+
+For board code writers, here are some guidelines:
+
+1. include ONE of the following header files in your <board>.c:
+
+   - #include <mach/mfp-pxa25x.h>
+   - #include <mach/mfp-pxa27x.h>
+   - #include <mach/mfp-pxa300.h>
+   - #include <mach/mfp-pxa320.h>
+   - #include <mach/mfp-pxa930.h>
+
+   NOTE: only one file in your <board>.c, depending on the processors used,
+   because pin configuration definitions may conflict in these file (i.e.
+   same name, different meaning and settings on different processors). E.g.
+   for zylonite platform, which support both PXA300/PXA310 and PXA320, two
+   separate files are introduced: zylonite_pxa300.c and zylonite_pxa320.c
+   (in addition to handle MFP configuration differences, they also handle
+   the other differences between the two combinations).
+
+   NOTE: PXA300 and PXA310 are almost identical in pin configurations (with
+   PXA310 supporting some additional ones), thus the difference is actually
+   covered in a single mfp-pxa300.h.
+
+2. prepare an array for the initial pin configurations, e.g.:
+
+   static unsigned long mainstone_pin_config[] __initdata = {
+       /* Chip Select */
+       GPIO15_nCS_1,
+
+       /* LCD - 16bpp Active TFT */
+       GPIOxx_TFT_LCD_16BPP,
+       GPIO16_PWM0_OUT,        /* Backlight */
+
+       /* MMC */
+       GPIO32_MMC_CLK,
+       GPIO112_MMC_CMD,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+
+       ...
+
+       /* GPIO */
+       GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
+   };
+
+   a) once the pin configurations are passed to pxa{2xx,3xx}_mfp_config(),
+   and written to the actual registers, they are useless and may discard,
+   adding '__initdata' will help save some additional bytes here.
+
+   b) when there is only one possible pin configurations for a component,
+   some simplified definitions can be used, e.g. GPIOxx_TFT_LCD_16BPP on
+   PXA25x and PXA27x processors
+
+   c) if by board design, a pin can be configured to wake up the system
+   from low power state, it can be 'OR'ed with any of:
+
+      WAKEUP_ON_EDGE_BOTH
+      WAKEUP_ON_EDGE_RISE
+      WAKEUP_ON_EDGE_FALL
+      WAKEUP_ON_LEVEL_HIGH - specifically for enabling of keypad GPIOs,
+
+   to indicate that this pin has the capability of wake-up the system,
+   and on which edge(s). This, however, doesn't necessarily mean the
+   pin _will_ wakeup the system, it will only when set_irq_wake() is
+   invoked with the corresponding GPIO IRQ (GPIO_IRQ(xx) or gpio_to_irq())
+   and eventually calls gpio_set_wake() for the actual register setting.
+
+   d) although PXA3xx MFP supports edge detection on each pin, the
+   internal logic will only wakeup the system when those specific bits
+   in ADxER registers are set, which can be well mapped to the
+   corresponding peripheral, thus set_irq_wake() can be called with 
+   the peripheral IRQ to enable the wakeup.
+
+
+ MFP on PXA3xx
+===============
+
+Every external I/O pad on PXA3xx (excluding those for special purpose) has
+one MFP logic associated, and is controlled by one MFP register (MFPR).
+
+The MFPR has the following bit definitions (for PXA300/PXA310/PXA320):
+
+ 31                        16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+  +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+  |         RESERVED        |PS|PU|PD|  DRIVE |SS|SD|SO|EC|EF|ER|--| AF_SEL |
+  +-------------------------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+  Bit 3:   RESERVED
+  Bit 4:   EDGE_RISE_EN - enable detection of rising edge on this pin
+  Bit 5:   EDGE_FALL_EN - enable detection of falling edge on this pin
+  Bit 6:   EDGE_CLEAR   - disable edge detection on this pin
+  Bit 7:   SLEEP_OE_N   - enable outputs during low power modes
+  Bit 8:   SLEEP_DATA   - output data on the pin during low power modes
+  Bit 9:   SLEEP_SEL    - selection control for low power modes signals
+  Bit 13:  PULLDOWN_EN  - enable the internal pull-down resistor on this pin
+  Bit 14:  PULLUP_EN    - enable the internal pull-up resistor on this pin
+  Bit 15:  PULL_SEL     - pull state controlled by selected alternate function
+                          (0) or by PULL{UP,DOWN}_EN bits (1)
+
+  Bit 0 - 2: AF_SEL - alternate function selection, 8 possibilities, from 0-7
+  Bit 10-12: DRIVE  - drive strength and slew rate
+                       0b000 - fast 1mA
+                       0b001 - fast 2mA
+                       0b002 - fast 3mA
+                       0b003 - fast 4mA
+                       0b004 - slow 6mA
+                       0b005 - fast 6mA
+                       0b006 - slow 10mA
+                       0b007 - fast 10mA
+
+ MFP Design for PXA2xx/PXA3xx
+==============================
+
+Due to the difference of pin-mux handling between PXA2xx and PXA3xx, a unified
+MFP API is introduced to cover both series of processors.
+
+The basic idea of this design is to introduce definitions for all possible pin
+configurations, these definitions are processor and platform independent, and
+the actual API invoked to convert these definitions into register settings and
+make them effective there-after.
+
+  Files Involved
+  --------------
+
+  - arch/arm/mach-pxa/include/mach/mfp.h
+  
+  for
+    1. Unified pin definitions - enum constants for all configurable pins
+    2. processor-neutral bit definitions for a possible MFP configuration
+
+  - arch/arm/mach-pxa/include/mach/mfp-pxa3xx.h
+
+  for PXA3xx specific MFPR register bit definitions and PXA3xx common pin
+  configurations
+
+  - arch/arm/mach-pxa/include/mach/mfp-pxa2xx.h
+
+  for PXA2xx specific definitions and PXA25x/PXA27x common pin configurations
+
+  - arch/arm/mach-pxa/include/mach/mfp-pxa25x.h
+    arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
+    arch/arm/mach-pxa/include/mach/mfp-pxa300.h
+    arch/arm/mach-pxa/include/mach/mfp-pxa320.h
+    arch/arm/mach-pxa/include/mach/mfp-pxa930.h
+
+  for processor specific definitions
+
+  - arch/arm/mach-pxa/mfp-pxa3xx.c
+  - arch/arm/mach-pxa/mfp-pxa2xx.c
+
+  for implementation of the pin configuration to take effect for the actual
+  processor.
+
+  Pin Configuration
+  -----------------
+
+  The following comments are copied from mfp.h (see the actual source code
+  for most updated info)
+  
+  /*
+   * a possible MFP configuration is represented by a 32-bit integer
+   *
+   * bit  0.. 9 - MFP Pin Number (1024 Pins Maximum)
+   * bit 10..12 - Alternate Function Selection
+   * bit 13..15 - Drive Strength
+   * bit 16..18 - Low Power Mode State
+   * bit 19..20 - Low Power Mode Edge Detection
+   * bit 21..22 - Run Mode Pull State
+   *
+   * to facilitate the definition, the following macros are provided
+   *
+   * MFP_CFG_DEFAULT - default MFP configuration value, with
+   *             alternate function = 0,
+   *             drive strength = fast 3mA (MFP_DS03X)
+   *             low power mode = default
+   *             edge detection = none
+   *
+   * MFP_CFG   - default MFPR value with alternate function
+   * MFP_CFG_DRV       - default MFPR value with alternate function and
+   *             pin drive strength
+   * MFP_CFG_LPM       - default MFPR value with alternate function and
+   *             low power mode
+   * MFP_CFG_X - default MFPR value with alternate function,
+   *             pin drive strength and low power mode
+   */
+
+   Examples of pin configurations are:
+
+   #define GPIO94_SSP3_RXD             MFP_CFG_X(GPIO94, AF1, DS08X, FLOAT)
+
+   which reads GPIO94 can be configured as SSP3_RXD, with alternate function
+   selection of 1, driving strength of 0b101, and a float state in low power
+   modes.
+
+   NOTE: this is the default setting of this pin being configured as SSP3_RXD
+   which can be modified a bit in board code, though it is not recommended to
+   do so, simply because this default setting is usually carefully encoded,
+   and is supposed to work in most cases.
+
+  Register Settings
+  -----------------
+
+   Register settings on PXA3xx for a pin configuration is actually very
+   straight-forward, most bits can be converted directly into MFPR value
+   in a easier way. Two sets of MFPR values are calculated: the run-time
+   ones and the low power mode ones, to allow different settings.
+
+   The conversion from a generic pin configuration to the actual register
+   settings on PXA2xx is a bit complicated: many registers are involved,
+   including GAFRx, GPDRx, PGSRx, PWER, PKWR, PFER and PRER. Please see
+   mfp-pxa2xx.c for how the conversion is made.
index 4dbb8be1c991c3b4049d69ff68c99c12e5f34ce3..3c5434c83daf360d9bf36cb7f8d09727af7a5966 100644 (file)
@@ -914,7 +914,7 @@ I/O scheduler, a.k.a. elevator, is implemented in two layers.  Generic dispatch
 queue and specific I/O schedulers.  Unless stated otherwise, elevator is used
 to refer to both parts and I/O scheduler to specific I/O schedulers.
 
-Block layer implements generic dispatch queue in ll_rw_blk.c and elevator.c.
+Block layer implements generic dispatch queue in block/*.c.
 The generic dispatch queue is responsible for properly ordering barrier
 requests, requeueing, handling non-fs requests and all other subtleties.
 
@@ -926,8 +926,8 @@ be built inside the kernel.  Each queue can choose different one and can also
 change to another one dynamically.
 
 A block layer call to the i/o scheduler follows the convention elv_xxx(). This
-calls elevator_xxx_fn in the elevator switch (drivers/block/elevator.c). Oh,
-xxx and xxx might not match exactly, but use your imagination. If an elevator
+calls elevator_xxx_fn in the elevator switch (block/elevator.c). Oh, xxx
+and xxx might not match exactly, but use your imagination. If an elevator
 doesn't implement a function, the switch does nothing or some minimal house
 keeping work.
 
diff --git a/Documentation/dvb/technisat.txt b/Documentation/dvb/technisat.txt
new file mode 100644 (file)
index 0000000..cdf6ee4
--- /dev/null
@@ -0,0 +1,69 @@
+How to set up the Technisat devices
+===================================
+
+1) Find out what device you have
+================================
+
+First start your linux box with a shipped kernel:
+lspci -vvv for a PCI device (lsusb -vvv for an USB device) will show you for example:
+02:0b.0 Network controller: Techsan Electronics Co Ltd B2C2 FlexCopII DVB chip / Technisat SkyStar2 DVB card (rev 02)
+
+dmesg | grep frontend may show you for example:
+DVB: registering frontend 0 (Conexant CX24123/CX24109)...
+
+2) Kernel compilation:
+======================
+
+If the Technisat is the only TV device in your box get rid of unnecessary modules and check this one:
+"Multimedia devices" => "Customise analog and hybrid tuner modules to build"
+In this directory uncheck every driver which is activated there.
+
+Then please activate:
+2a) Main module part:
+
+a.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters"
+b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card OR
+c.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC USB" in case of an USB 1.1 adapter
+d.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Enable debug for the B2C2 FlexCop drivers"
+Notice: d.) is helpful for troubleshooting
+
+2b) Frontend module part:
+
+1.) Revision 2.3:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink VP310/MT312/ZL10313 based"
+
+2.) Revision 2.6:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0299 based"
+
+3.) Revision 2.7:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Samsung S5H1420 based"
+c.)"Multimedia devices" => "Customise DVB frontends" => "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
+
+4.) Revision 2.8:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+c.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24123 based"
+d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
+
+5.) DVB-T card:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink MT352 based"
+
+6.) DVB-C card:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0297 based"
+
+7.) ATSC card 1st generation:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "Broadcom BCM3510"
+
+8.) ATSC card 2nd generation:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "NxtWave Communications NXT2002/NXT2004 based"
+c.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based"
+
+Author: Uwe Bugla <uwe.bugla@gmx.de> December 2008
index db9b8500b43b01cd62841d7c7b6ff1650b2829a1..d143a0a749f9ff3d975e7d0f62b89bb05c0e0620 100644 (file)
@@ -5,9 +5,13 @@ The driver supports the following options, either via
 options=<OPTIONS> when modular or video=pxafb:<OPTIONS> when built in.
 
 For example:
-       modprobe pxafb options=mode:640x480-8,passive
+       modprobe pxafb options=vmem:2M,mode:640x480-8,passive
 or on the kernel command line
-       video=pxafb:mode:640x480-8,passive
+       video=pxafb:vmem:2M,mode:640x480-8,passive
+
+vmem: VIDEO_MEM_SIZE
+       Amount of video memory to allocate (can be suffixed with K or M
+       for kilobytes or megabytes)
 
 mode:XRESxYRES[-BPP]
        XRES == LCCR1_PPL + 1
@@ -52,3 +56,87 @@ outputen:POLARITY
 pixclockpol:POLARITY
        pixel clock polarity
        0 => falling edge, 1 => rising edge
+
+
+Overlay Support for PXA27x and later LCD controllers
+====================================================
+
+  PXA27x and later processors support overlay1 and overlay2 on-top of the
+  base framebuffer (although under-neath the base is also possible). They
+  support palette and no-palette RGB formats, as well as YUV formats (only
+  available on overlay2). These overlays have dedicated DMA channels and
+  behave in a similar way as a framebuffer.
+
+  However, there are some differences between these overlay framebuffers
+  and normal framebuffers, as listed below:
+
+  1. overlay can start at a 32-bit word aligned position within the base
+     framebuffer, which means they have a start (x, y). This information
+     is encoded into var->nonstd (no, var->xoffset and var->yoffset are
+     not for such purpose).
+
+  2. overlay framebuffer is allocated dynamically according to specified
+     'struct fb_var_screeninfo', the amount is decided by:
+
+        var->xres_virtual * var->yres_virtual * bpp
+
+     bpp = 16 -- for RGB565 or RGBT555
+         = 24 -- for YUV444 packed
+         = 24 -- for YUV444 planar
+        = 16 -- for YUV422 planar (1 pixel = 1 Y + 1/2 Cb + 1/2 Cr)
+        = 12 -- for YUV420 planar (1 pixel = 1 Y + 1/4 Cb + 1/4 Cr)
+
+     NOTE:
+
+     a. overlay does not support panning in x-direction, thus
+        var->xres_virtual will always be equal to var->xres
+
+     b. line length of overlay(s) must be on a 32-bit word boundary,
+        for YUV planar modes, it is a requirement for the component
+       with minimum bits per pixel,  e.g. for YUV420, Cr component
+       for one pixel is actually 2-bits, it means the line length
+       should be a multiple of 16-pixels
+
+     c. starting horizontal position (XPOS) should start on a 32-bit
+        word boundary, otherwise the fb_check_var() will just fail.
+
+     d. the rectangle of the overlay should be within the base plane,
+        otherwise fail
+
+     Applications should follow the sequence below to operate an overlay
+     framebuffer:
+
+         a. open("/dev/fb[1-2]", ...)
+        b. ioctl(fd, FBIOGET_VSCREENINFO, ...)
+        c. modify 'var' with desired parameters:
+           1) var->xres and var->yres
+           2) larger var->yres_virtual if more memory is required,
+              usually for double-buffering
+           3) var->nonstd for starting (x, y) and color format
+           4) var->{red, green, blue, transp} if RGB mode is to be used
+        d. ioctl(fd, FBIOPUT_VSCREENINFO, ...)
+        e. ioctl(fd, FBIOGET_FSCREENINFO, ...)
+        f. mmap
+        g. ...
+
+  3. for YUV planar formats, these are actually not supported within the
+     framebuffer framework, application has to take care of the offsets
+     and lengths of each component within the framebuffer.
+
+  4. var->nonstd is used to pass starting (x, y) position and color format,
+     the detailed bit fields are shown below:
+
+    31                23  20         10          0
+     +-----------------+---+----------+----------+
+     |  ... unused ... |FOR|   XPOS   |   YPOS   |
+     +-----------------+---+----------+----------+
+
+     FOR  - color format, as defined by OVERLAY_FORMAT_* in pxafb.h
+            0 - RGB
+           1 - YUV444 PACKED
+           2 - YUV444 PLANAR
+           3 - YUV422 PLANAR
+           4 - YUR420 PLANAR
+
+     XPOS - starting horizontal position
+     YPOS - starting vertical position
index 804520633fcf6ad7697b56a2ad18726d1af31cc1..f2dbbf3bdeaba7a5c6d58e1ccb3f8a686ade88ed 100644 (file)
@@ -481,51 +481,6 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
        /* We return the initrd size. */
        return len;
 }
-
-/* Once we know how much memory we have we can construct simple linear page
- * tables which set virtual == physical which will get the Guest far enough
- * into the boot to create its own.
- *
- * We lay them out of the way, just below the initrd (which is why we need to
- * know its size here). */
-static unsigned long setup_pagetables(unsigned long mem,
-                                     unsigned long initrd_size)
-{
-       unsigned long *pgdir, *linear;
-       unsigned int mapped_pages, i, linear_pages;
-       unsigned int ptes_per_page = getpagesize()/sizeof(void *);
-
-       mapped_pages = mem/getpagesize();
-
-       /* Each PTE page can map ptes_per_page pages: how many do we need? */
-       linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
-
-       /* We put the toplevel page directory page at the top of memory. */
-       pgdir = from_guest_phys(mem) - initrd_size - getpagesize();
-
-       /* Now we use the next linear_pages pages as pte pages */
-       linear = (void *)pgdir - linear_pages*getpagesize();
-
-       /* Linear mapping is easy: put every page's address into the mapping in
-        * order.  PAGE_PRESENT contains the flags Present, Writable and
-        * Executable. */
-       for (i = 0; i < mapped_pages; i++)
-               linear[i] = ((i * getpagesize()) | PAGE_PRESENT);
-
-       /* The top level points to the linear page table pages above. */
-       for (i = 0; i < mapped_pages; i += ptes_per_page) {
-               pgdir[i/ptes_per_page]
-                       = ((to_guest_phys(linear) + i*sizeof(void *))
-                          | PAGE_PRESENT);
-       }
-
-       verbose("Linear mapping of %u pages in %u pte pages at %#lx\n",
-               mapped_pages, linear_pages, to_guest_phys(linear));
-
-       /* We return the top level (guest-physical) address: the kernel needs
-        * to know where it is. */
-       return to_guest_phys(pgdir);
-}
 /*:*/
 
 /* Simple routine to roll all the commandline arguments together with spaces
@@ -548,13 +503,13 @@ static void concat(char *dst, char *args[])
 
 /*L:185 This is where we actually tell the kernel to initialize the Guest.  We
  * saw the arguments it expects when we looked at initialize() in lguest_user.c:
- * the base of Guest "physical" memory, the top physical page to allow, the
- * top level pagetable and the entry point for the Guest. */
-static int tell_kernel(unsigned long pgdir, unsigned long start)
+ * the base of Guest "physical" memory, the top physical page to allow and the
+ * entry point for the Guest. */
+static int tell_kernel(unsigned long start)
 {
        unsigned long args[] = { LHREQ_INITIALIZE,
                                 (unsigned long)guest_base,
-                                guest_limit / getpagesize(), pgdir, start };
+                                guest_limit / getpagesize(), start };
        int fd;
 
        verbose("Guest: %p - %p (%#lx)\n",
@@ -1030,7 +985,7 @@ static void update_device_status(struct device *dev)
                /* Zero out the virtqueues. */
                for (vq = dev->vq; vq; vq = vq->next) {
                        memset(vq->vring.desc, 0,
-                              vring_size(vq->config.num, getpagesize()));
+                              vring_size(vq->config.num, LGUEST_VRING_ALIGN));
                        lg_last_avail(vq) = 0;
                }
        } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
@@ -1211,7 +1166,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
        void *p;
 
        /* First we need some memory for this virtqueue. */
-       pages = (vring_size(num_descs, getpagesize()) + getpagesize() - 1)
+       pages = (vring_size(num_descs, LGUEST_VRING_ALIGN) + getpagesize() - 1)
                / getpagesize();
        p = get_pages(pages);
 
@@ -1228,7 +1183,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
        vq->config.pfn = to_guest_phys(p) / getpagesize();
 
        /* Initialize the vring. */
-       vring_init(&vq->vring, num_descs, p, getpagesize());
+       vring_init(&vq->vring, num_descs, p, LGUEST_VRING_ALIGN);
 
        /* Append virtqueue to this device's descriptor.  We use
         * device_config() to get the end of the device's current virtqueues;
@@ -1941,7 +1896,7 @@ int main(int argc, char *argv[])
 {
        /* Memory, top-level pagetable, code startpoint and size of the
         * (optional) initrd. */
-       unsigned long mem = 0, pgdir, start, initrd_size = 0;
+       unsigned long mem = 0, start, initrd_size = 0;
        /* Two temporaries and the /dev/lguest file descriptor. */
        int i, c, lguest_fd;
        /* The boot information for the Guest. */
@@ -2040,9 +1995,6 @@ int main(int argc, char *argv[])
                boot->hdr.type_of_loader = 0xFF;
        }
 
-       /* Set up the initial linear pagetables, starting below the initrd. */
-       pgdir = setup_pagetables(mem, initrd_size);
-
        /* The Linux boot header contains an "E820" memory map: ours is a
         * simple, single region. */
        boot->e820_entries = 1;
@@ -2064,7 +2016,7 @@ int main(int argc, char *argv[])
 
        /* We tell the kernel to initialize the Guest: this returns the open
         * /dev/lguest file descriptor. */
-       lguest_fd = tell_kernel(pgdir, start);
+       lguest_fd = tell_kernel(start);
 
        /* We clone off a thread, which wakes the Launcher whenever one of the
         * input file descriptors needs attention.  We call this the Waker, and
index 4ba4664ce5c315d024c3bc7fd515e44ac92d4653..9cb9138f7a79bcd67bf4ac2f69741e812b5a14c2 100644 (file)
@@ -71,35 +71,50 @@ Look at the current lock statistics:
 
 # less /proc/lock_stat
 
-01 lock_stat version 0.2
+01 lock_stat version 0.3
 02 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 03                               class name    con-bounces    contentions   waittime-min   waittime-max waittime-total    acq-bounces   acquisitions   holdtime-min   holdtime-max holdtime-total
 04 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 05
-06               &inode->i_data.tree_lock-W:            15          21657           0.18     1093295.30 11547131054.85             58          10415           0.16          87.51        6387.60
-07               &inode->i_data.tree_lock-R:             0              0           0.00           0.00           0.00          23302         231198           0.25           8.45       98023.38
-08               --------------------------
-09                 &inode->i_data.tree_lock              0          [<ffffffff8027c08f>] add_to_page_cache+0x5f/0x190
-10
-11 ...............................................................................................................................................................................................
-12
-13                              dcache_lock:          1037           1161           0.38          45.32         774.51           6611         243371           0.15         306.48       77387.24
-14                              -----------
-15                              dcache_lock            180          [<ffffffff802c0d7e>] sys_getcwd+0x11e/0x230
-16                              dcache_lock            165          [<ffffffff802c002a>] d_alloc+0x15a/0x210
-17                              dcache_lock             33          [<ffffffff8035818d>] _atomic_dec_and_lock+0x4d/0x70
-18                              dcache_lock              1          [<ffffffff802beef8>] shrink_dcache_parent+0x18/0x130
+06                          &mm->mmap_sem-W:           233            538 18446744073708       22924.27      607243.51           1342          45806           1.71        8595.89     1180582.34
+07                          &mm->mmap_sem-R:           205            587 18446744073708       28403.36      731975.00           1940         412426           0.58      187825.45     6307502.88
+08                          ---------------
+09                            &mm->mmap_sem            487          [<ffffffff8053491f>] do_page_fault+0x466/0x928
+10                            &mm->mmap_sem            179          [<ffffffff802a6200>] sys_mprotect+0xcd/0x21d
+11                            &mm->mmap_sem            279          [<ffffffff80210a57>] sys_mmap+0x75/0xce
+12                            &mm->mmap_sem             76          [<ffffffff802a490b>] sys_munmap+0x32/0x59
+13                          ---------------
+14                            &mm->mmap_sem            270          [<ffffffff80210a57>] sys_mmap+0x75/0xce
+15                            &mm->mmap_sem            431          [<ffffffff8053491f>] do_page_fault+0x466/0x928
+16                            &mm->mmap_sem            138          [<ffffffff802a490b>] sys_munmap+0x32/0x59
+17                            &mm->mmap_sem            145          [<ffffffff802a6200>] sys_mprotect+0xcd/0x21d
+18
+19 ...............................................................................................................................................................................................
+20
+21                              dcache_lock:           621            623           0.52         118.26        1053.02           6745          91930           0.29         316.29      118423.41
+22                              -----------
+23                              dcache_lock            179          [<ffffffff80378274>] _atomic_dec_and_lock+0x34/0x54
+24                              dcache_lock            113          [<ffffffff802cc17b>] d_alloc+0x19a/0x1eb
+25                              dcache_lock             99          [<ffffffff802ca0dc>] d_rehash+0x1b/0x44
+26                              dcache_lock            104          [<ffffffff802cbca0>] d_instantiate+0x36/0x8a
+27                              -----------
+28                              dcache_lock            192          [<ffffffff80378274>] _atomic_dec_and_lock+0x34/0x54
+29                              dcache_lock             98          [<ffffffff802ca0dc>] d_rehash+0x1b/0x44
+30                              dcache_lock             72          [<ffffffff802cc17b>] d_alloc+0x19a/0x1eb
+31                              dcache_lock            112          [<ffffffff802cbca0>] d_instantiate+0x36/0x8a
 
 This excerpt shows the first two lock class statistics. Line 01 shows the
 output version - each time the format changes this will be updated. Line 02-04
-show the header with column descriptions. Lines 05-10 and 13-18 show the actual
+show the header with column descriptions. Lines 05-18 and 20-31 show the actual
 statistics. These statistics come in two parts; the actual stats separated by a
-short separator (line 08, 14) from the contention points.
+short separator (line 08, 13) from the contention points.
 
-The first lock (05-10) is a read/write lock, and shows two lines above the
+The first lock (05-18) is a read/write lock, and shows two lines above the
 short separator. The contention points don't match the column descriptors,
-they have two: contentions and [<IP>] symbol.
+they have two: contentions and [<IP>] symbol. The second set of contention
+points are the points we're contending with.
 
+The integer part of the time values is in us.
 
 View the top contending locks:
 
index afbe9ae7ee9682c6b4377efc8b7e8a80d3fe1087..d749d41f647b145df62780ef7820a1de23fee80d 100644 (file)
@@ -1,16 +1,27 @@
-<TITLE>V4L API</TITLE>
-<H1>Video For Linux APIs</H1>
-<table border=0>
-<tr>
-<td>
-<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html>
-V4L original API</a>
-</td><td>
-Obsoleted by V4L2 API
-</td></tr><tr><td>
-<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API>
-V4L2 API</a>
-</td><td>
-Should be used for new projects
-</td></tr>
-</table>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+  <meta content="text/html;charset=ISO-8859-2" http-equiv="Content-Type" />
+  <title>V4L API</title>
+ </head>
+ <body>
+  <h1>Video For Linux APIs</h1>
+  <table border="0">
+   <tr>
+    <td>
+     <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html">V4L original API</a>
+    </td>
+    <td>
+     Obsoleted by V4L2 API
+    </td>
+   </tr>
+   <tr>
+    <td>
+     <a href="http://www.linuxtv.org/downloads/video4linux/API/V4L2_API">V4L2 API</a>
+    </td>
+    <td>Should be used for new projects
+    </td>
+   </tr>
+  </table>
+ </body>
+</html>
index 60ba66836038215952c9be46dcbff58edb19b319..0d93fa1ac25e344311ca53d71adb859c24984b52 100644 (file)
 103 -> Grand X-Guard / Trust 814PCI                        [0304:0102]
 104 -> Nebula Electronics DigiTV                           [0071:0101]
 105 -> ProVideo PV143                                      [aa00:1430,aa00:1431,aa00:1432,aa00:1433,aa03:1433]
-106 -> PHYTEC VD-009-X1 MiniDIN (bt878)
-107 -> PHYTEC VD-009-X1 Combi (bt878)
+106 -> PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)
+107 -> PHYTEC VD-009-X1 VD-011 Combi (bt878)
 108 -> PHYTEC VD-009 MiniDIN (bt878)
 109 -> PHYTEC VD-009 Combi (bt878)
 110 -> IVC-100                                             [ff00:a132]
 150 -> Geovision GV-600                                    [008a:763c]
 151 -> Kozumi KTV-01C
 152 -> Encore ENL TV-FM-2                                  [1000:1801]
+153 -> PHYTEC VD-012 (bt878)
+154 -> PHYTEC VD-012-X1 (bt878)
+155 -> PHYTEC VD-012-X2 (bt878)
index 64823ccacd69013ae48401705e7704a39ce38136..35ea130e9898c21231347559f601ea572687cb08 100644 (file)
@@ -11,3 +11,4 @@
  10 -> DViCO FusionHDTV7 Dual Express                      [18ac:d618]
  11 -> DViCO FusionHDTV DVB-T Dual Express                 [18ac:db78]
  12 -> Leadtek Winfast PxDVR3200 H                         [107d:6681]
+ 13 -> Compro VideoMate E650F                              [185b:e800]
index a5227e308f4ab91146dc2426a2bd694d95d63043..0d08f1edcf6d1d978dbfd6265b17126bb87fe96f 100644 (file)
@@ -2,7 +2,7 @@
   1 -> Hauppauge WinTV 34xxx models                        [0070:3400,0070:3401]
   2 -> GDI Black Gold                                      [14c7:0106,14c7:0107]
   3 -> PixelView                                           [1554:4811]
-  4 -> ATI TV Wonder Pro                                   [1002:00f8]
+  4 -> ATI TV Wonder Pro                                   [1002:00f8,1002:00f9]
   5 -> Leadtek Winfast 2000XP Expert                       [107d:6611,107d:6613]
   6 -> AverTV Studio 303 (M126)                            [1461:000b]
   7 -> MSI TV-@nywhere Master                              [1462:8606]
@@ -74,3 +74,6 @@
  73 -> TeVii S420 DVB-S                                    [d420:9022]
  74 -> Prolink Pixelview Global Extreme                    [1554:4976]
  75 -> PROF 7300 DVB-S/S2                                  [B033:3033]
+ 76 -> SATTRADE ST4200 DVB-S/S2                            [b200:4200]
+ 77 -> TBS 8910 DVB-S                                      [8910:8888]
+ 78 -> Prof 6200 DVB-S                                     [b022:3022]
index 187cc48d092469a045ccd52fb16d4239bf6c447e..75bded8a4aa2e449b09c4454da01b3eeae76d022 100644 (file)
@@ -1,5 +1,5 @@
   0 -> Unknown EM2800 video grabber             (em2800)        [eb1a:2800]
-  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
+  1 -> Unknown EM2750/28xx video grabber        (em2820/em2840) [eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883]
   2 -> Terratec Cinergy 250 USB                 (em2820/em2840) [0ccd:0036]
   3 -> Pinnacle PCTV USB 2                      (em2820/em2840) [2304:0208]
   4 -> Hauppauge WinTV USB 2                    (em2820/em2840) [2040:4200,2040:4201]
@@ -12,9 +12,9 @@
  11 -> Terratec Hybrid XS                       (em2880)        [0ccd:0042]
  12 -> Kworld PVR TV 2800 RF                    (em2820/em2840)
  13 -> Terratec Prodigy XS                      (em2880)        [0ccd:0047]
- 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840) [eb1a:2821]
+ 14 -> Pixelview Prolink PlayTV USB 2.0         (em2820/em2840)
  15 -> V-Gear PocketTV                          (em2800)
- 16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b,2040:651f]
+ 16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
  18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
  19 -> PointNix Intra-Oral Camera               (em2860)
@@ -27,7 +27,6 @@
  26 -> Hercules Smart TV USB 2.0                (em2820/em2840)
  27 -> Pinnacle PCTV USB 2 (Philips FM1216ME)   (em2820/em2840)
  28 -> Leadtek Winfast USB II Deluxe            (em2820/em2840)
- 29 -> Pinnacle Dazzle DVC 100                  (em2820/em2840)
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
@@ -57,3 +56,5 @@
  56 -> Pinnacle Hybrid Pro (2)                  (em2882)        [2304:0226]
  57 -> Kworld PlusTV HD Hybrid 330              (em2883)        [eb1a:a316]
  58 -> Compro VideoMate ForYou/Stereo           (em2820/em2840) [185b:2041]
+ 60 -> Hauppauge WinTV HVR 850                  (em2883)        [2040:651f]
+ 61 -> Pixelview PlayTV Box 4 USB 2.0           (em2820/em2840)
index dc67eef38ff92071995b9c0d12f901ef4e3837b9..335aef4dcaebdaa0acf87477865a0b0cea9be377 100644 (file)
@@ -10,7 +10,7 @@
   9 -> Medion 5044
  10 -> Kworld/KuroutoShikou SAA7130-TVPCI
  11 -> Terratec Cinergy 600 TV                  [153b:1143]
- 12 -> Medion 7134                              [16be:0003]
+ 12 -> Medion 7134                              [16be:0003,16be:5000]
  13 -> Typhoon TV+Radio 90031
  14 -> ELSA EX-VISION 300TV                     [1048:226b]
  15 -> ELSA EX-VISION 500TV                     [1048:226a]
 150 -> Zogis Real Angel 220
 151 -> ADS Tech Instant HDTV                    [1421:0380]
 152 -> Asus Tiger Rev:1.00                      [1043:4857]
+153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
index 166d5960b1a97b83caac3e00484f9f8f00b5ae4f..35fae23f883b6090c438b2bd707beb09ec9b2a8c 100644 (file)
@@ -1,4 +1,3 @@
-
 cx8800 release notes
 ====================
 
@@ -10,21 +9,20 @@ current status
 
 video
        - Basically works.
-       - Some minor image quality glitches.
-       - For now only capture, overlay support isn't completed yet.
+       - For now, only capture and read(). Overlay isn't supported.
 
 audio
        - The chip specs for the on-chip TV sound decoder are next
          to useless :-/
        - Neverless the builtin TV sound decoder starts working now,
-         at least for PAL-BG.  Other TV norms need other code ...
+         at least for some standards.
          FOR ANY REPORTS ON THIS PLEASE MENTION THE TV NORM YOU ARE
          USING.
        - Most tuner chips do provide mono sound, which may or may not
          be useable depending on the board design.  With the Hauppauge
          cards it works, so there is mono sound available as fallback.
        - audio data dma (i.e. recording without loopback cable to the
-         sound card) should be possible, but there is no code yet ...
+         sound card) is supported via cx88-alsa.
 
 vbi
        - Code present. Works for NTSC closed caption. PAL and other
index 004818fab040ab0bb04078be639c5346a688f772..1c58a763014646182a17aa50efb5dc19b01425f3 100644 (file)
@@ -50,9 +50,14 @@ ov519                045e:028c       Micro$oft xbox cam
 spca508                0461:0815       Micro Innovation IC200
 sunplus                0461:0821       Fujifilm MV-1
 zc3xx          0461:0a00       MicroInnovation WebCam320
+stv06xx                046d:0840       QuickCam Express
+stv06xx                046d:0850       LEGO cam / QuickCam Web
+stv06xx                046d:0870       Dexxa WebCam USB
 spca500                046d:0890       Logitech QuickCam traveler
 vc032x         046d:0892       Logitech Orbicam
 vc032x         046d:0896       Logitech Orbicam
+vc032x         046d:0897       Logitech QuickCam for Dell notebooks
+zc3xx          046d:089d       Logitech QuickCam E2500
 zc3xx          046d:08a0       Logitech QC IM
 zc3xx          046d:08a1       Logitech QC IM 0x08A1 +sound
 zc3xx          046d:08a2       Labtec Webcam Pro
@@ -169,6 +174,9 @@ spca500             06bd:0404       Agfa CL20
 spca500                06be:0800       Optimedia
 sunplus                06d6:0031       Trust 610 LCD PowerC@m Zoom
 spca506                06e1:a190       ADS Instant VCD
+ov534          06f8:3002       Hercules Blog Webcam
+ov534          06f8:3003       Hercules Dualpix HD Weblog
+sonixj         06f8:3004       Hercules Classic Silver
 spca508                0733:0110       ViewQuest VQ110
 spca508                0130:0130       Clone Digital Webcam 11043
 spca501                0733:0401       Intel Create and Share
@@ -199,7 +207,8 @@ sunplus             08ca:2050       Medion MD 41437
 sunplus                08ca:2060       Aiptek PocketDV5300
 tv8532         0923:010f       ICM532 cams
 mars           093a:050f       Mars-Semi Pc-Camera
-pac207         093a:2460       PAC207 Qtec Webcam 100
+pac207         093a:2460       Qtec Webcam 100
+pac207         093a:2461       HP Webcam
 pac207         093a:2463       Philips SPC 220 NC
 pac207         093a:2464       Labtec Webcam 1200
 pac207         093a:2468       PAC207
@@ -213,10 +222,13 @@ pac7311           093a:2603       PAC7312
 pac7311                093a:2608       Trust WB-3300p
 pac7311                093a:260e       Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
 pac7311                093a:260f       SnakeCam
+pac7311                093a:2620       Apollo AC-905
 pac7311                093a:2621       PAC731x
+pac7311                093a:2622       Genius Eye 312
 pac7311                093a:2624       PAC7302
 pac7311                093a:2626       Labtec 2200
 pac7311                093a:262a       Webcam 300k
+pac7311                093a:262c       Philips SPC 230 NC
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
@@ -249,11 +261,13 @@ sonixj            0c45:60c0       Sangha Sn535
 sonixj         0c45:60ec       SN9C105+MO4000
 sonixj         0c45:60fb       Surfer NoName
 sonixj         0c45:60fc       LG-LIC300
+sonixj         0c45:60fe       Microdia Audio
 sonixj         0c45:6128       Microdia/Sonix SNP325
 sonixj         0c45:612a       Avant Camera
 sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
 sonixj         0c45:6130       Sonix Pccam
 sonixj         0c45:6138       Sn9c120 Mo4000
+sonixj         0c45:613a       Microdia Sonix PC Camera
 sonixj         0c45:613b       Surfer SN-206
 sonixj         0c45:613c       Sonix Pccam168
 sonixj         0c45:6143       Sonix Pccam168
@@ -263,6 +277,9 @@ etoms               102c:6251       Qcam xxxxxx VGA
 zc3xx          10fd:0128       Typhoon Webshot II USB 300k 0x0128
 spca561                10fd:7e50       FlyCam Usb 100
 zc3xx          10fd:8050       Typhoon Webshot II USB 300k
+ov534          1415:2000       Sony HD Eye for PS3 (SLEH 00201)
+pac207         145f:013a       Trust WB-1300N
+vc032x         15b8:6002       HP 2.0 Megapixel rz406aa
 spca501                1776:501c       Arowana 300K CMOS Camera
 t613           17a1:0128       TASCORP JPEG Webcam, NGS Cyclops
 vc032x         17ef:4802       Lenovo Vc0323+MI1310_SOC
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
new file mode 100644 (file)
index 0000000..eeae76c
--- /dev/null
@@ -0,0 +1,520 @@
+Overview of the V4L2 driver framework
+=====================================
+
+This text documents the various structures provided by the V4L2 framework and
+their relationships.
+
+
+Introduction
+------------
+
+The V4L2 drivers tend to be very complex due to the complexity of the
+hardware: most devices have multiple ICs, export multiple device nodes in
+/dev, and create also non-V4L2 devices such as DVB, ALSA, FB, I2C and input
+(IR) devices.
+
+Especially the fact that V4L2 drivers have to setup supporting ICs to
+do audio/video muxing/encoding/decoding makes it more complex than most.
+Usually these ICs are connected to the main bridge driver through one or
+more I2C busses, but other busses can also be used. Such devices are
+called 'sub-devices'.
+
+For a long time the framework was limited to the video_device struct for
+creating V4L device nodes and video_buf for handling the video buffers
+(note that this document does not discuss the video_buf framework).
+
+This meant that all drivers had to do the setup of device instances and
+connecting to sub-devices themselves. Some of this is quite complicated
+to do right and many drivers never did do it correctly.
+
+There is also a lot of common code that could never be refactored due to
+the lack of a framework.
+
+So this framework sets up the basic building blocks that all drivers
+need and this same framework should make it much easier to refactor
+common code into utility functions shared by all drivers.
+
+
+Structure of a driver
+---------------------
+
+All drivers have the following structure:
+
+1) A struct for each device instance containing the device state.
+
+2) A way of initializing and commanding sub-devices (if any).
+
+3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
+   /dev/vtxX) and keeping track of device-node specific data.
+
+4) Filehandle-specific structs containing per-filehandle data.
+
+This is a rough schematic of how it all relates:
+
+    device instances
+      |
+      +-sub-device instances
+      |
+      \-V4L2 device nodes
+         |
+         \-filehandle instances
+
+
+Structure of the framework
+--------------------------
+
+The framework closely resembles the driver structure: it has a v4l2_device
+struct for the device instance data, a v4l2_subdev struct to refer to
+sub-device instances, the video_device struct stores V4L2 device node data
+and in the future a v4l2_fh struct will keep track of filehandle instances
+(this is not yet implemented).
+
+
+struct v4l2_device
+------------------
+
+Each device instance is represented by a struct v4l2_device (v4l2-device.h).
+Very simple devices can just allocate this struct, but most of the time you
+would embed this struct inside a larger struct.
+
+You must register the device instance:
+
+       v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+Registration will initialize the v4l2_device struct and link dev->driver_data
+to v4l2_dev. Registration will also set v4l2_dev->name to a value derived from
+dev (driver name followed by the bus_id, to be precise). You may change the
+name after registration if you want.
+
+The first 'dev' argument is normally the struct device pointer of a pci_dev,
+usb_device or platform_device.
+
+You unregister with:
+
+       v4l2_device_unregister(struct v4l2_device *v4l2_dev);
+
+Unregistering will also automatically unregister all subdevs from the device.
+
+Sometimes you need to iterate over all devices registered by a specific
+driver. This is usually the case if multiple device drivers use the same
+hardware. E.g. the ivtvfb driver is a framebuffer driver that uses the ivtv
+hardware. The same is true for alsa drivers for example.
+
+You can iterate over all registered devices as follows:
+
+static int callback(struct device *dev, void *p)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+
+       /* test if this device was inited */
+       if (v4l2_dev == NULL)
+               return 0;
+       ...
+       return 0;
+}
+
+int iterate(void *p)
+{
+       struct device_driver *drv;
+       int err;
+
+       /* Find driver 'ivtv' on the PCI bus.
+          pci_bus_type is a global. For USB busses use usb_bus_type. */
+       drv = driver_find("ivtv", &pci_bus_type);
+       /* iterate over all ivtv device instances */
+       err = driver_for_each_device(drv, NULL, p, callback);
+       put_driver(drv);
+       return err;
+}
+
+Sometimes you need to keep a running counter of the device instance. This is
+commonly used to map a device instance to an index of a module option array.
+
+The recommended approach is as follows:
+
+static atomic_t drv_instance = ATOMIC_INIT(0);
+
+static int __devinit drv_probe(struct pci_dev *dev,
+                               const struct pci_device_id *pci_id)
+{
+       ...
+       state->instance = atomic_inc_return(&drv_instance) - 1;
+}
+
+
+struct v4l2_subdev
+------------------
+
+Many drivers need to communicate with sub-devices. These devices can do all
+sort of tasks, but most commonly they handle audio and/or video muxing,
+encoding or decoding. For webcams common sub-devices are sensors and camera
+controllers.
+
+Usually these are I2C devices, but not necessarily. In order to provide the
+driver with a consistent interface to these sub-devices the v4l2_subdev struct
+(v4l2-subdev.h) was created.
+
+Each sub-device driver must have a v4l2_subdev struct. This struct can be
+stand-alone for simple sub-devices or it might be embedded in a larger struct
+if more state information needs to be stored. Usually there is a low-level
+device struct (e.g. i2c_client) that contains the device data as setup
+by the kernel. It is recommended to store that pointer in the private
+data of v4l2_subdev using v4l2_set_subdevdata(). That makes it easy to go
+from a v4l2_subdev to the actual low-level bus-specific device data.
+
+You also need a way to go from the low-level struct to v4l2_subdev. For the
+common i2c_client struct the i2c_set_clientdata() call is used to store a
+v4l2_subdev pointer, for other busses you may have to use other methods.
+
+From the bridge driver perspective you load the sub-device module and somehow
+obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
+i2c_get_clientdata(). For other busses something similar needs to be done.
+Helper functions exists for sub-devices on an I2C bus that do most of this
+tricky work for you.
+
+Each v4l2_subdev contains function pointers that sub-device drivers can
+implement (or leave NULL if it is not applicable). Since sub-devices can do
+so many different things and you do not want to end up with a huge ops struct
+of which only a handful of ops are commonly implemented, the function pointers
+are sorted according to category and each category has its own ops struct.
+
+The top-level ops struct contains pointers to the category ops structs, which
+may be NULL if the subdev driver does not support anything from that category.
+
+It looks like this:
+
+struct v4l2_subdev_core_ops {
+       int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip);
+       int (*log_status)(struct v4l2_subdev *sd);
+       int (*init)(struct v4l2_subdev *sd, u32 val);
+       ...
+};
+
+struct v4l2_subdev_tuner_ops {
+       ...
+};
+
+struct v4l2_subdev_audio_ops {
+       ...
+};
+
+struct v4l2_subdev_video_ops {
+       ...
+};
+
+struct v4l2_subdev_ops {
+       const struct v4l2_subdev_core_ops  *core;
+       const struct v4l2_subdev_tuner_ops *tuner;
+       const struct v4l2_subdev_audio_ops *audio;
+       const struct v4l2_subdev_video_ops *video;
+};
+
+The core ops are common to all subdevs, the other categories are implemented
+depending on the sub-device. E.g. a video device is unlikely to support the
+audio ops and vice versa.
+
+This setup limits the number of function pointers while still making it easy
+to add new ops and categories.
+
+A sub-device driver initializes the v4l2_subdev struct using:
+
+       v4l2_subdev_init(subdev, &ops);
+
+Afterwards you need to initialize subdev->name with a unique name and set the
+module owner. This is done for you if you use the i2c helper functions.
+
+A device (bridge) driver needs to register the v4l2_subdev with the
+v4l2_device:
+
+       int err = v4l2_device_register_subdev(device, subdev);
+
+This can fail if the subdev module disappeared before it could be registered.
+After this function was called successfully the subdev->dev field points to
+the v4l2_device.
+
+You can unregister a sub-device using:
+
+       v4l2_device_unregister_subdev(subdev);
+
+Afterwards the subdev module can be unloaded and subdev->dev == NULL.
+
+You can call an ops function either directly:
+
+       err = subdev->ops->core->g_chip_ident(subdev, &chip);
+
+but it is better and easier to use this macro:
+
+       err = v4l2_subdev_call(subdev, core, g_chip_ident, &chip);
+
+The macro will to the right NULL pointer checks and returns -ENODEV if subdev
+is NULL, -ENOIOCTLCMD if either subdev->core or subdev->core->g_chip_ident is
+NULL, or the actual result of the subdev->ops->core->g_chip_ident ops.
+
+It is also possible to call all or a subset of the sub-devices:
+
+       v4l2_device_call_all(dev, 0, core, g_chip_ident, &chip);
+
+Any subdev that does not support this ops is skipped and error results are
+ignored. If you want to check for errors use this:
+
+       err = v4l2_device_call_until_err(dev, 0, core, g_chip_ident, &chip);
+
+Any error except -ENOIOCTLCMD will exit the loop with that error. If no
+errors (except -ENOIOCTLCMD) occured, then 0 is returned.
+
+The second argument to both calls is a group ID. If 0, then all subdevs are
+called. If non-zero, then only those whose group ID match that value will
+be called. Before a bridge driver registers a subdev it can set subdev->grp_id
+to whatever value it wants (it's 0 by default). This value is owned by the
+bridge driver and the sub-device driver will never modify or use it.
+
+The group ID gives the bridge driver more control how callbacks are called.
+For example, there may be multiple audio chips on a board, each capable of
+changing the volume. But usually only one will actually be used when the
+user want to change the volume. You can set the group ID for that subdev to
+e.g. AUDIO_CONTROLLER and specify that as the group ID value when calling
+v4l2_device_call_all(). That ensures that it will only go to the subdev
+that needs it.
+
+The advantage of using v4l2_subdev is that it is a generic struct and does
+not contain any knowledge about the underlying hardware. So a driver might
+contain several subdevs that use an I2C bus, but also a subdev that is
+controlled through GPIO pins. This distinction is only relevant when setting
+up the device, but once the subdev is registered it is completely transparent.
+
+
+I2C sub-device drivers
+----------------------
+
+Since these drivers are so common, special helper functions are available to
+ease the use of these drivers (v4l2-common.h).
+
+The recommended method of adding v4l2_subdev support to an I2C driver is to
+embed the v4l2_subdev struct into the state struct that is created for each
+I2C device instance. Very simple devices have no state struct and in that case
+you can just create a v4l2_subdev directly.
+
+A typical state struct would look like this (where 'chipname' is replaced by
+the name of the chip):
+
+struct chipname_state {
+       struct v4l2_subdev sd;
+       ...  /* additional state fields */
+};
+
+Initialize the v4l2_subdev struct as follows:
+
+       v4l2_i2c_subdev_init(&state->sd, client, subdev_ops);
+
+This function will fill in all the fields of v4l2_subdev and ensure that the
+v4l2_subdev and i2c_client both point to one another.
+
+You should also add a helper inline function to go from a v4l2_subdev pointer
+to a chipname_state struct:
+
+static inline struct chipname_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct chipname_state, sd);
+}
+
+Use this to go from the v4l2_subdev struct to the i2c_client struct:
+
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+And this to go from an i2c_client to a v4l2_subdev struct:
+
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+Finally you need to make a command function to make driver->command()
+call the right subdev_ops functions:
+
+static int subdev_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+If driver->command is never used then you can leave this out. Eventually the
+driver->command usage should be removed from v4l.
+
+Make sure to call v4l2_device_unregister_subdev(sd) when the remove() callback
+is called. This will unregister the sub-device from the bridge driver. It is
+safe to call this even if the sub-device was never registered.
+
+
+The bridge driver also has some helper functions it can use:
+
+struct v4l2_subdev *sd = v4l2_i2c_new_subdev(adapter, "module_foo", "chipid", 0x36);
+
+This loads the given module (can be NULL if no module needs to be loaded) and
+calls i2c_new_device() with the given i2c_adapter and chip/address arguments.
+If all goes well, then it registers the subdev with the v4l2_device. It gets
+the v4l2_device by calling i2c_get_adapdata(adapter), so you should make sure
+that adapdata is set to v4l2_device when you setup the i2c_adapter in your
+driver.
+
+You can also use v4l2_i2c_new_probed_subdev() which is very similar to
+v4l2_i2c_new_subdev(), except that it has an array of possible I2C addresses
+that it should probe. Internally it calls i2c_new_probed_device().
+
+Both functions return NULL if something went wrong.
+
+
+struct video_device
+-------------------
+
+The actual device nodes in the /dev directory are created using the
+video_device struct (v4l2-dev.h). This struct can either be allocated
+dynamically or embedded in a larger struct.
+
+To allocate it dynamically use:
+
+       struct video_device *vdev = video_device_alloc();
+
+       if (vdev == NULL)
+               return -ENOMEM;
+
+       vdev->release = video_device_release;
+
+If you embed it in a larger struct, then you must set the release()
+callback to your own function:
+
+       struct video_device *vdev = &my_vdev->vdev;
+
+       vdev->release = my_vdev_release;
+
+The release callback must be set and it is called when the last user
+of the video device exits.
+
+The default video_device_release() callback just calls kfree to free the
+allocated memory.
+
+You should also set these fields:
+
+- parent: set to the parent device (same device as was used to register
+  v4l2_device).
+- name: set to something descriptive and unique.
+- fops: set to the file_operations struct.
+- ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
+  (highly recommended to use this and it might become compulsory in the
+  future!), then set this to your v4l2_ioctl_ops struct.
+
+If you use v4l2_ioctl_ops, then you should set .unlocked_ioctl to
+__video_ioctl2 or .ioctl to video_ioctl2 in your file_operations struct.
+
+
+video_device registration
+-------------------------
+
+Next you register the video device: this will create the character device
+for you.
+
+       err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       if (err) {
+               video_device_release(vdev); // or kfree(my_vdev);
+               return err;
+       }
+
+Which device is registered depends on the type argument. The following
+types exist:
+
+VFL_TYPE_GRABBER: videoX for video input/output devices
+VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
+VFL_TYPE_RADIO: radioX for radio tuners
+VFL_TYPE_VTX: vtxX for teletext devices (deprecated, don't use)
+
+The last argument gives you a certain amount of control over the device
+kernel number used (i.e. the X in videoX). Normally you will pass -1 to
+let the v4l2 framework pick the first free number. But if a driver creates
+many devices, then it can be useful to have different video devices in
+separate ranges. For example, video capture devices start at 0, video
+output devices start at 16.
+
+So you can use the last argument to specify a minimum kernel number and
+the v4l2 framework will try to pick the first free number that is equal
+or higher to what you passed. If that fails, then it will just pick the
+first free number.
+
+Whenever a device node is created some attributes are also created for you.
+If you look in /sys/class/video4linux you see the devices. Go into e.g.
+video0 and you will see 'name' and 'index' attributes. The 'name' attribute
+is the 'name' field of the video_device struct. The 'index' attribute is
+a device node index that can be assigned by the driver, or that is calculated
+for you.
+
+If you call video_register_device(), then the index is just increased by
+1 for each device node you register. The first video device node you register
+always starts off with 0.
+
+Alternatively you can call video_register_device_index() which is identical
+to video_register_device(), but with an extra index argument. Here you can
+pass a specific index value (between 0 and 31) that should be used.
+
+Users can setup udev rules that utilize the index attribute to make fancy
+device names (e.g. 'mpegX' for MPEG video capture device nodes).
+
+After the device was successfully registered, then you can use these fields:
+
+- vfl_type: the device type passed to video_register_device.
+- minor: the assigned device minor number.
+- num: the device kernel number (i.e. the X in videoX).
+- index: the device index number (calculated or set explicitly using
+  video_register_device_index).
+
+If the registration failed, then you need to call video_device_release()
+to free the allocated video_device struct, or free your own struct if the
+video_device was embedded in it. The vdev->release() callback will never
+be called if the registration failed, nor should you ever attempt to
+unregister the device if the registration failed.
+
+
+video_device cleanup
+--------------------
+
+When the video device nodes have to be removed, either during the unload
+of the driver or because the USB device was disconnected, then you should
+unregister them:
+
+       video_unregister_device(vdev);
+
+This will remove the device nodes from sysfs (causing udev to remove them
+from /dev).
+
+After video_unregister_device() returns no new opens can be done.
+
+However, in the case of USB devices some application might still have one
+of these device nodes open. You should block all new accesses to read,
+write, poll, etc. except possibly for certain ioctl operations like
+queueing buffers.
+
+When the last user of the video device node exits, then the vdev->release()
+callback is called and you can do the final cleanup there.
+
+
+video_device helper functions
+-----------------------------
+
+There are a few useful helper functions:
+
+You can set/get driver private data in the video_device struct using:
+
+void *video_get_drvdata(struct video_device *dev);
+void video_set_drvdata(struct video_device *dev, void *data);
+
+Note that you can safely call video_set_drvdata() before calling
+video_register_device().
+
+And this function:
+
+struct video_device *video_devdata(struct file *file);
+
+returns the video_device belonging to the file struct.
+
+The final helper function combines video_get_drvdata with
+video_devdata:
+
+void *video_drvdata(struct file *file);
+
+You can go from a video_device struct to the v4l2_device struct using:
+
+struct v4l2_device *v4l2_dev = dev_get_drvdata(vdev->parent);
+
index 08d0ab7fa1615b093864bf30444a4427109b6d00..ceb32ee51f9de33077fcf95a3ff1845465b2a130 100644 (file)
@@ -1755,6 +1755,13 @@ L:       linuxppc-dev@ozlabs.org
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 
+FREESCALE IMX / MXC FRAMEBUFFER DRIVER
+P:     Sascha Hauer
+M:     kernel@pengutronix.de
+L:     linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+S:     Maintained
+
 FREESCALE SOC FS_ENET DRIVER
 P:     Pantelis Antoniou
 M:     pantelis.antoniou@gmail.com
index 09ff7d81809a79fe7ff04a4b29a66eb9cfe10648..d13a9694e159ca092dd6a2dc044729bd1ddc7760 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -205,13 +205,14 @@ ifeq ($(ARCH),x86_64)
         SRCARCH := x86
 endif
 
-# Where to locate arch specific headers
+# Additional ARCH settings for sparc
 ifeq ($(ARCH),sparc64)
-       hdr-arch  := sparc
-else
-       hdr-arch  := $(SRCARCH)
+       SRCARCH := sparc
 endif
 
+# Where to locate arch specific headers
+hdr-arch  := $(SRCARCH)
+
 KCONFIG_CONFIG ?= .config
 
 # SHELL used by kbuild
index 471e72dbaf8b123ce235b470303b56f2852209f0..2e13aa261929fd3a3689c41b0bfe6dcdf9805d5c 100644 (file)
@@ -6,6 +6,8 @@ config OPROFILE
        tristate "OProfile system profiling (EXPERIMENTAL)"
        depends on PROFILING
        depends on HAVE_OPROFILE
+       select TRACING
+       select RING_BUFFER
        help
          OProfile is a profiling system capable of profiling the
          whole system, include the kernel, kernel modules, libraries,
index e971ab000f9519c18cda4df33f26182d377aafa2..eda9b909aa05e84680d7eb0fa322c5fc4177dd1f 100644 (file)
@@ -96,9 +96,6 @@ static inline dma_addr_t __deprecated isa_page_to_bus(struct page *page)
        return page_to_phys(page);
 }
 
-/* This depends on working iommu.  */
-#define BIO_VMERGE_BOUNDARY    (alpha_mv.mv_pci_tbi ? PAGE_SIZE : 0)
-
 /* Maximum PIO space address supported?  */
 #define IO_SPACE_LIMIT 0xffff
 
index 9722f8bb506cb9ad27f64b47ab15ce428886a0ba..d6ebe39934b5f989e95b96e7f9919daf759440b2 100644 (file)
@@ -156,7 +156,6 @@ config ARCH_MTD_XIP
        bool
 
 config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
        def_bool y
 
 if OPROFILE
@@ -201,6 +200,7 @@ choice
 
 config ARCH_AAEC2000
        bool "Agilent AAEC-2000 based"
+       select CPU_ARM920T
        select ARM_AMBA
        select HAVE_CLK
        help
@@ -210,6 +210,7 @@ config ARCH_INTEGRATOR
        bool "ARM Ltd. Integrator family"
        select ARM_AMBA
        select HAVE_CLK
+       select COMMON_CLKDEV
        select ICST525
        help
          Support for ARM's Integrator platform.
@@ -218,6 +219,7 @@ config ARCH_REALVIEW
        bool "ARM Ltd. RealView family"
        select ARM_AMBA
        select HAVE_CLK
+       select COMMON_CLKDEV
        select ICST307
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -229,6 +231,7 @@ config ARCH_VERSATILE
        select ARM_AMBA
        select ARM_VIC
        select HAVE_CLK
+       select COMMON_CLKDEV
        select ICST307
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -243,22 +246,15 @@ config ARCH_AT91
          This enables support for systems based on the Atmel AT91RM9200,
          AT91SAM9 and AT91CAP9 processors.
 
-config ARCH_CLPS7500
-       bool "Cirrus CL-PS7500FE"
-       select TIMER_ACORN
-       select ISA
-       select NO_IOPORT
-       select ARCH_SPARSEMEM_ENABLE
-       help
-         Support for the Cirrus Logic PS7500FE system-on-a-chip.
-
 config ARCH_CLPS711X
        bool "Cirrus Logic CLPS711x/EP721x-based"
+       select CPU_ARM720T
        help
          Support for Cirrus Logic 711x/721x based boards.
 
 config ARCH_EBSA110
        bool "EBSA-110"
+       select CPU_SA110
        select ISA
        select NO_IOPORT
        help
@@ -269,16 +265,19 @@ config ARCH_EBSA110
 
 config ARCH_EP93XX
        bool "EP93xx-based"
+       select CPU_ARM920T
        select ARM_AMBA
        select ARM_VIC
        select GENERIC_GPIO
        select HAVE_CLK
+       select COMMON_CLKDEV
        select ARCH_REQUIRE_GPIOLIB
        help
          This enables support for the Cirrus EP93xx series of CPUs.
 
 config ARCH_FOOTBRIDGE
        bool "FootBridge"
+       select CPU_SA110
        select FOOTBRIDGE
        help
          Support for systems based on the DC21285 companion chip
@@ -286,18 +285,23 @@ config ARCH_FOOTBRIDGE
 
 config ARCH_NETX
        bool "Hilscher NetX based"
+       select CPU_ARM926T
        select ARM_VIC
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_TIME
        help
          This enables support for systems based on the Hilscher NetX Soc
 
 config ARCH_H720X
        bool "Hynix HMS720x-based"
+       select CPU_ARM720T
        select ISA_DMA_API
        help
          This enables support for systems based on the Hynix HMS720x
 
 config ARCH_IMX
        bool "IMX"
+       select CPU_ARM920T
        select GENERIC_GPIO
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -307,6 +311,7 @@ config ARCH_IMX
 config ARCH_IOP13XX
        bool "IOP13xx-based"
        depends on MMU
+       select CPU_XSC3
        select PLAT_IOP
        select PCI
        select ARCH_SUPPORTS_MSI
@@ -317,6 +322,7 @@ config ARCH_IOP13XX
 config ARCH_IOP32X
        bool "IOP32x-based"
        depends on MMU
+       select CPU_XSCALE
        select PLAT_IOP
        select PCI
        select GENERIC_GPIO
@@ -328,6 +334,7 @@ config ARCH_IOP32X
 config ARCH_IOP33X
        bool "IOP33x-based"
        depends on MMU
+       select CPU_XSCALE
        select PLAT_IOP
        select PCI
        select GENERIC_GPIO
@@ -338,6 +345,7 @@ config ARCH_IOP33X
 config ARCH_IXP23XX
        bool "IXP23XX-based"
        depends on MMU
+       select CPU_XSC3
        select PCI
        help
          Support for Intel's IXP23xx (XScale) family of processors.
@@ -345,6 +353,7 @@ config ARCH_IXP23XX
 config ARCH_IXP2000
        bool "IXP2400/2800-based"
        depends on MMU
+       select CPU_XSCALE
        select PCI
        help
          Support for Intel's IXP2400/2800 (XScale) family of processors.
@@ -352,6 +361,7 @@ config ARCH_IXP2000
 config ARCH_IXP4XX
        bool "IXP4xx-based"
        depends on MMU
+       select CPU_XSCALE
        select GENERIC_GPIO
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -361,6 +371,7 @@ config ARCH_IXP4XX
 
 config ARCH_L7200
        bool "LinkUp-L7200"
+       select CPU_ARM720T
        select FIQ
        help
          Say Y here if you intend to run this kernel on a LinkUp Systems
@@ -374,7 +385,9 @@ config ARCH_L7200
 
 config ARCH_KIRKWOOD
        bool "Marvell Kirkwood"
+       select CPU_FEROCEON
        select PCI
+       select GENERIC_GPIO
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select PLAT_ORION
@@ -384,13 +397,16 @@ config ARCH_KIRKWOOD
 
 config ARCH_KS8695
        bool "Micrel/Kendin KS8695"
+       select CPU_ARM922T
        select GENERIC_GPIO
+        select ARCH_REQUIRE_GPIOLIB
        help
          Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
          System-on-Chip devices.
 
 config ARCH_NS9XXX
        bool "NetSilicon NS9xxx"
+       select CPU_ARM926T
        select GENERIC_GPIO
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -403,6 +419,7 @@ config ARCH_NS9XXX
 
 config ARCH_LOKI
        bool "Marvell Loki (88RC8480)"
+       select CPU_FEROCEON
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select PLAT_ORION
@@ -411,7 +428,9 @@ config ARCH_LOKI
 
 config ARCH_MV78XX0
        bool "Marvell MV78xx0"
+       select CPU_FEROCEON
        select PCI
+       select GENERIC_GPIO
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select PLAT_ORION
@@ -432,6 +451,7 @@ config ARCH_MXC
 config ARCH_ORION5X
        bool "Marvell Orion"
        depends on MMU
+       select CPU_FEROCEON
        select PCI
        select GENERIC_GPIO
        select GENERIC_TIME
@@ -444,6 +464,7 @@ config ARCH_ORION5X
 
 config ARCH_PNX4008
        bool "Philips Nexperia PNX4008 Mobile"
+       select CPU_ARM926T
        select HAVE_CLK
        help
          This enables support for Philips PNX4008 mobile platform.
@@ -454,6 +475,7 @@ config ARCH_PXA
        select ARCH_MTD_XIP
        select GENERIC_GPIO
        select HAVE_CLK
+       select COMMON_CLKDEV
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
@@ -477,6 +499,7 @@ config ARCH_RPC
 
 config ARCH_SA1100
        bool "SA1100-based"
+       select CPU_SA1100
        select ISA
        select ARCH_SPARSEMEM_ENABLE
        select ARCH_MTD_XIP
@@ -498,8 +521,16 @@ config ARCH_S3C2410
          BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
          the Samsung SMDK2410 development board (and derivatives).
 
+config ARCH_S3C64XX
+       bool "Samsung S3C64XX"
+       select GENERIC_GPIO
+       select HAVE_CLK
+       help
+         Samsung S3C64XX series based systems
+
 config ARCH_SHARK
        bool "Shark"
+       select CPU_SA110
        select ISA
        select ISA_DMA
        select ZONE_DMA
@@ -510,6 +541,7 @@ config ARCH_SHARK
 
 config ARCH_LH7A40X
        bool "Sharp LH7A40X"
+       select CPU_ARM922T
        select ARCH_DISCONTIGMEM_ENABLE if !LH7A40X_CONTIGMEM
        select ARCH_SPARSEMEM_ENABLE if !LH7A40X_CONTIGMEM
        help
@@ -520,6 +552,7 @@ config ARCH_LH7A40X
 
 config ARCH_DAVINCI
        bool "TI DaVinci"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        select GENERIC_GPIO
@@ -541,6 +574,7 @@ config ARCH_OMAP
 
 config ARCH_MSM
        bool "Qualcomm MSM"
+       select CPU_V6
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
        help
@@ -549,6 +583,13 @@ config ARCH_MSM
          interface to the ARM9 modem processor which runs the baseband stack
          and controls some vital subsystems (clock and power control, etc).
 
+config ARCH_W90X900
+       bool "Nuvoton W90X900 CPU"
+       select CPU_ARM926T
+       help
+               Support for Nuvoton (Winbond logic dept.) ARM9 processor,You
+               can login www.mcuos.com or www.nuvoton.com to know more.
+
 endchoice
 
 source "arch/arm/mach-clps711x/Kconfig"
@@ -590,6 +631,7 @@ source "arch/arm/mach-orion5x/Kconfig"
 source "arch/arm/mach-kirkwood/Kconfig"
 
 source "arch/arm/plat-s3c24xx/Kconfig"
+source "arch/arm/plat-s3c64xx/Kconfig"
 source "arch/arm/plat-s3c/Kconfig"
 
 if ARCH_S3C2410
@@ -601,6 +643,11 @@ source "arch/arm/mach-s3c2442/Kconfig"
 source "arch/arm/mach-s3c2443/Kconfig"
 endif
 
+if ARCH_S3C64XX
+source "arch/arm/mach-s3c6400/Kconfig"
+source "arch/arm/mach-s3c6410/Kconfig"
+endif
+
 source "arch/arm/mach-lh7a40x/Kconfig"
 
 source "arch/arm/mach-imx/Kconfig"
@@ -627,6 +674,8 @@ source "arch/arm/mach-ks8695/Kconfig"
 
 source "arch/arm/mach-msm/Kconfig"
 
+source "arch/arm/mach-w90x900/Kconfig"
+
 # Definitions to make life easier
 config ARCH_ACORN
        bool
@@ -781,7 +830,7 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
        bool "Use local timer interrupts"
-       depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP)
+       depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || REALVIEW_EB_A9MP)
        default y
        help
          Enable support for local timers on SMP platforms, rather then the
index bd6e28115ebb36284050b290ea1d8800fbec3763..24e0f0187697009fb19de797f8e7f76042b94e9e 100644 (file)
@@ -76,6 +76,7 @@ tune-$(CONFIG_CPU_SA110)      :=-mtune=strongarm110
 tune-$(CONFIG_CPU_SA1100)      :=-mtune=strongarm1100
 tune-$(CONFIG_CPU_XSCALE)      :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
 tune-$(CONFIG_CPU_XSC3)                :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+tune-$(CONFIG_CPU_FEROCEON)    :=$(call cc-option,-mtune=marvell-f,-mtune=xscale)
 tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
 
 ifeq ($(CONFIG_AEABI),y)
@@ -96,7 +97,6 @@ textofs-y     := 0x00008000
 
  machine-$(CONFIG_ARCH_RPC)       := rpc
  machine-$(CONFIG_ARCH_EBSA110)           := ebsa110
- machine-$(CONFIG_ARCH_CLPS7500)   := clps7500
  machine-$(CONFIG_FOOTBRIDGE)     := footbridge
  machine-$(CONFIG_ARCH_SHARK)     := shark
  machine-$(CONFIG_ARCH_SA1100)    := sa1100
@@ -121,7 +121,10 @@ endif
  machine-$(CONFIG_ARCH_OMAP3)     := omap2
     plat-$(CONFIG_ARCH_OMAP)      := omap
  machine-$(CONFIG_ARCH_S3C2410)           := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
+ machine-$(CONFIG_ARCH_S3C24A0)           := s3c24a0
     plat-$(CONFIG_PLAT_S3C24XX)           := s3c24xx s3c
+ machine-$(CONFIG_ARCH_S3C64XX)           := s3c6400 s3c6410
+    plat-$(CONFIG_PLAT_S3C64XX)           := s3c64xx s3c
  machine-$(CONFIG_ARCH_LH7A40X)           := lh7a40x
  machine-$(CONFIG_ARCH_VERSATILE)  := versatile
  machine-$(CONFIG_ARCH_IMX)       := imx
@@ -139,11 +142,13 @@ endif
     plat-$(CONFIG_ARCH_MXC)       := mxc
  machine-$(CONFIG_ARCH_MX2)       := mx2
  machine-$(CONFIG_ARCH_MX3)       := mx3
+ machine-$(CONFIG_ARCH_MX1)       := mx1
  machine-$(CONFIG_ARCH_ORION5X)           := orion5x
     plat-$(CONFIG_PLAT_ORION)     := orion
  machine-$(CONFIG_ARCH_MSM)       := msm
  machine-$(CONFIG_ARCH_LOKI)       := loki
  machine-$(CONFIG_ARCH_MV78XX0)    := mv78xx0
+ machine-$(CONFIG_ARCH_W90X900)    := w90x900
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
index c47f2a3f8f8f32b3e9a168111c8d7bacb6182fb5..fbe5eef1f6c9c031b2763e1ba9bb734de941f91b 100644 (file)
@@ -23,10 +23,6 @@ ifeq ($(CONFIG_ARCH_L7200),y)
 OBJS           += head-l7200.o
 endif
 
-ifeq ($(CONFIG_ARCH_CLPS7500),y)
-HEAD           = head-clps7500.o
-endif
-
 ifeq ($(CONFIG_ARCH_P720T),y)
 # Borrow this code from SA1100
 OBJS           += head-sa1100.o
diff --git a/arch/arm/boot/compressed/head-clps7500.S b/arch/arm/boot/compressed/head-clps7500.S
deleted file mode 100644 (file)
index 4f3c78a..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * linux/arch/arm/boot/compressed/head-clps7500.S
- *
- * Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd
- */
-
-
-               /* There are three different ways the kernel can be
-                  booted on a 7500 system: from Angel (loaded in RAM), from
-                  16-bit ROM or from 32-bit Flash.  Luckily, a single kernel
-                  image does for them all. */
-               /* This branch is taken if the CPU memory width matches the
-                  actual device in use.  The default at power on is 16 bits
-                  so we must be prepared for a mismatch. */
-               .section ".start", "ax"
-2:
-               b       1f
-               .word   0xffff
-               .word   0xb632          @ mov r11, #0x03200000
-               .word   0xe3a0
-               .word   0x0000          @ mov r0, #0
-               .word   0xe3a0
-               .word   0x0080          @ strb r0, [r11, #0x80]
-               .word   0xe5cb
-               .word   0xf000          @ mov pc, #0
-               .word   0xe3a0
-1:
-               adr     r1, 2b
-               teq     r1, #0
-               bne     .Langel
-               /* This is a direct-from-ROM boot.  Copy the kernel into 
-                  RAM and run it there. */
-               mov     r0, #0x30
-               mcr     p15, 0, r0, c1, c0, 0
-               mov     r0, #0x13
-               msr     cpsr_cxsf, r0
-               mov     r12, #0x03000000        @ point to LEDs
-               orr     r12, r12, #0x00020000
-               orr     r12, r12, #0xba00
-               mov     r0, #0x5500
-               str     r0, [r12]
-               mov     r0, #0x10000000
-               orr     r0, r0, #0x8000
-               mov     r4, r0
-               ldr     r2, =_end
-2:
-               ldr     r3, [r1], #4
-               str     r3, [r0], #4
-               teq     r0, r2
-               bne     2b
-               mov     r0, #0xff00
-               str     r0, [r12]
-1:     
-               mov     r12, #0x03000000        @ point to LEDs
-               orr     r12, r12, #0x00020000
-               orr     r12, r12, #0xba00
-               mov     r0, #0xfe00
-               str     r0, [r12]
-
-               adr     lr, 1f
-               mov     r0, #0
-               mov     r1, #14         /* MACH_TYPE_CLPS7500 */
-               mov     pc, lr
-.Langel:
-#ifdef CONFIG_ANGELBOOT
-               /* Call Angel to switch into SVC mode. */
-               mov     r0, #0x17
-               swi     0x123456
-#endif
-               /* Ensure all interrupts are off and MMU disabled */
-               mrs     r0, cpsr
-               orr     r0, r0, #0xc0
-               msr     cpsr_cxsf, r0
-
-               adr     lr, 1b
-               orr     lr, lr, #0x10000000
-               mov     r0, #0x30               @ MMU off
-               mcr     p15, 0, r0, c1, c0, 0
-               mov     r0, r0
-               mov     pc, lr
-
-               .ltorg
-
-1:
-/* And the rest */
-#include "head.S"
index 84a1e0496a3c6ffb7b1adbfa38182341ca943c27..77d614232d815fd592e6798383e7eb4aa8be48ae 100644 (file)
@@ -624,6 +624,12 @@ proc_types:
                b       __armv4_mmu_cache_off
                b       __armv4_mmu_cache_flush
 
+               .word   0x56056930
+               .word   0xff0ffff0              @ PXA935
+               b       __armv4_mmu_cache_on
+               b       __armv4_mmu_cache_off
+               b       __armv4_mmu_cache_flush
+
                .word   0x56050000              @ Feroceon
                .word   0xff0f0000
                b       __armv4_mmu_cache_on
@@ -717,6 +723,9 @@ __armv7_mmu_cache_off:
                bl      __armv7_mmu_cache_flush
                mov     r0, #0
                mcr     p15, 0, r0, c8, c7, 0   @ invalidate whole TLB
+               mcr     p15, 0, r0, c7, c5, 6   @ invalidate BTC
+               mcr     p15, 0, r0, c7, c10, 4  @ DSB
+               mcr     p15, 0, r0, c7, c5, 4   @ ISB
                mov     pc, r12
 
 __arm6_mmu_cache_off:
@@ -778,12 +787,13 @@ __armv6_mmu_cache_flush:
 __armv7_mmu_cache_flush:
                mrc     p15, 0, r10, c0, c1, 5  @ read ID_MMFR1
                tst     r10, #0xf << 16         @ hierarchical cache (ARMv7)
-               beq     hierarchical
                mov     r10, #0
+               beq     hierarchical
                mcr     p15, 0, r10, c7, c14, 0 @ clean+invalidate D
                b       iflush
 hierarchical:
-               stmfd   sp!, {r0-r5, r7, r9-r11}
+               mcr     p15, 0, r10, c7, c10, 5 @ DMB
+               stmfd   sp!, {r0-r5, r7, r9, r11}
                mrc     p15, 1, r0, c0, c0, 1   @ read clidr
                ands    r3, r0, #0x7000000      @ extract loc from clidr
                mov     r3, r3, lsr #23         @ left align loc bit field
@@ -820,12 +830,14 @@ skip:
                cmp     r3, r10
                bgt     loop1
 finished:
+               ldmfd   sp!, {r0-r5, r7, r9, r11}
                mov     r10, #0                 @ swith back to cache level 0
                mcr     p15, 2, r10, c0, c0, 0  @ select current cache level in cssr
-               ldmfd   sp!, {r0-r5, r7, r9-r11}
 iflush:
+               mcr     p15, 0, r10, c7, c10, 4 @ DSB
                mcr     p15, 0, r10, c7, c5, 0  @ invalidate I+BTB
-               mcr     p15, 0, r10, c7, c10, 4 @ drain WB
+               mcr     p15, 0, r10, c7, c10, 4 @ DSB
+               mcr     p15, 0, r10, c7, c5, 4  @ ISB
                mov     pc, lr
 
 __armv5tej_mmu_cache_flush:
index 65ce8fff29db1583890fe54f438f6f03385e11a9..3fc08413fff05803a3f555de749917b56962b966 100644 (file)
@@ -86,6 +86,8 @@ static void putstr(const char *ptr)
 
 #define __ptr_t void *
 
+#define memzero(s,n) __memzero(s,n)
+
 /*
  * Optimised C version of memzero for the ARM.
  */
index 86b5e6982660da255a13148a9392dc4d73def0b4..a2cd9beaf37daeb85c20627255b808f0fdf883a6 100644 (file)
@@ -33,3 +33,6 @@ config SHARPSL_PM
 
 config SHARP_SCOOP
        bool
+
+config COMMON_CLKDEV
+       bool
index 325e4b6a6afbdc842df5a822cdc507998508d55b..7cb7961d81cb977ec2b56b45208188875980966f 100644 (file)
@@ -17,3 +17,4 @@ obj-$(CONFIG_SHARP_SCOOP)     += scoop.o
 obj-$(CONFIG_ARCH_IXP2000)     += uengine.o
 obj-$(CONFIG_ARCH_IXP23XX)     += uengine.o
 obj-$(CONFIG_PCI_HOST_ITE8152)  += it8152.o
+obj-$(CONFIG_COMMON_CLKDEV)    += clkdev.o
diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c
new file mode 100644 (file)
index 0000000..17a17b4
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *  arch/arm/common/clkdev.c
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+
+static struct clk *clk_find(const char *dev_id, const char *con_id)
+{
+       struct clk_lookup *p;
+       struct clk *clk = NULL;
+       int match, best = 0;
+
+       list_for_each_entry(p, &clocks, node) {
+               if ((p->dev_id && !dev_id) || (p->con_id && !con_id))
+                       continue;
+               match = 0;
+               if (p->dev_id)
+                       match += 2 * (strcmp(p->dev_id, dev_id) == 0);
+               if (p->con_id)
+                       match += 1 * (strcmp(p->con_id, con_id) == 0);
+               if (match == 0)
+                       continue;
+
+               if (match > best) {
+                       clk = p->clk;
+                       best = match;
+               }
+       }
+       return clk;
+}
+
+struct clk *clk_get(struct device *dev, const char *con_id)
+{
+       const char *dev_id = dev ? dev_name(dev) : NULL;
+       struct clk *clk;
+
+       mutex_lock(&clocks_mutex);
+       clk = clk_find(dev_id, con_id);
+       if (clk && !__clk_get(clk))
+               clk = NULL;
+       mutex_unlock(&clocks_mutex);
+
+       return clk ? clk : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+       __clk_put(clk);
+}
+EXPORT_SYMBOL(clk_put);
+
+void clkdev_add(struct clk_lookup *cl)
+{
+       mutex_lock(&clocks_mutex);
+       list_add_tail(&cl->node, &clocks);
+       mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clkdev_add);
+
+#define MAX_DEV_ID     20
+#define MAX_CON_ID     16
+
+struct clk_lookup_alloc {
+       struct clk_lookup cl;
+       char    dev_id[MAX_DEV_ID];
+       char    con_id[MAX_CON_ID];
+};
+
+struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
+       const char *dev_fmt, ...)
+{
+       struct clk_lookup_alloc *cla;
+
+       cla = kzalloc(sizeof(*cla), GFP_KERNEL);
+       if (!cla)
+               return NULL;
+
+       cla->cl.clk = clk;
+       if (con_id) {
+               strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
+               cla->cl.con_id = cla->con_id;
+       }
+
+       if (dev_fmt) {
+               va_list ap;
+
+               va_start(ap, dev_fmt);
+               vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
+               cla->cl.dev_id = cla->dev_id;
+               va_end(ap);
+       }
+
+       return &cla->cl;
+}
+EXPORT_SYMBOL(clkdev_alloc);
+
+/*
+ * clkdev_drop - remove a clock dynamically allocated
+ */
+void clkdev_drop(struct clk_lookup *cl)
+{
+       mutex_lock(&clocks_mutex);
+       list_del(&cl->node);
+       mutex_unlock(&clocks_mutex);
+       kfree(cl);
+}
+EXPORT_SYMBOL(clkdev_drop);
index 7c6b4b99a2df1c98027a6adaee4a87dbe6371554..2293f0ce061ea60719c8a7338c07f90996f96b94 100644 (file)
@@ -1108,6 +1108,7 @@ void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf)
        locomo_writel(bpwf | LOCOMO_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
        spin_unlock_irqrestore(&lchip->lock, flags);
 }
+EXPORT_SYMBOL(locomo_frontlight_set);
 
 /*
  *     LoCoMo "Register Access Bus."
index f1e4b8f60cab026e773514e61d3ee682f478fc01..ecf0bfbab107362e38d8debdd7437103e7e02202 100644 (file)
@@ -69,12 +69,12 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
        /*
         * Make sure we clear all existing interrupts
         */
-       writel(0, base + VIC_VECT_ADDR);
+       writel(0, base + VIC_PL190_VECT_ADDR);
        for (i = 0; i < 19; i++) {
                unsigned int value;
 
-               value = readl(base + VIC_VECT_ADDR);
-               writel(value, base + VIC_VECT_ADDR);
+               value = readl(base + VIC_PL190_VECT_ADDR);
+               writel(value, base + VIC_PL190_VECT_ADDR);
        }
 
        for (i = 0; i < 16; i++) {
@@ -82,7 +82,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
                writel(VIC_VECT_CNTL_ENABLE | i, reg);
        }
 
-       writel(32, base + VIC_DEF_VECT_ADDR);
+       writel(32, base + VIC_PL190_DEF_VECT_ADDR);
 
        for (i = 0; i < 32; i++) {
                unsigned int irq = irq_start + i;
index 2307587a38a9ec89ca60251429c62cced8281053..b6c5cbbf4c85dcc4c26265edc00d3f46e3b7961f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26
-# Sat Jul 26 22:28:46 2008
+# Linux kernel version: 2.6.28-rc8
+# Wed Dec 24 23:35:45 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -22,8 +22,6 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
 CONFIG_ARCH_MTD_XIP=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
@@ -48,8 +46,7 @@ CONFIG_SYSVIPC_SYSCTL=y
 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_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 # CONFIG_BLK_DEV_INITRD is not set
@@ -58,13 +55,12 @@ CONFIG_SYSCTL=y
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_KALLSYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
+# CONFIG_COMPAT_BRK is not set
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
@@ -73,6 +69,7 @@ CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
+CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
@@ -80,15 +77,10 @@ CONFIG_SLAB=y
 # CONFIG_PROFILING is not set
 # CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
-# 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
@@ -112,14 +104,15 @@ CONFIG_BLOCK=y
 #
 CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_DEFAULT_AS=y
 # CONFIG_DEFAULT_DEADLINE is not set
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
 
 #
 # System Type
@@ -129,7 +122,6 @@ CONFIG_CLASSIC_RCU=y
 # 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
@@ -160,7 +152,8 @@ CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
 
 #
 # Intel PXA2xx/PXA3xx Implementations
@@ -169,8 +162,10 @@ CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_LUBBOCK is not set
 # CONFIG_MACH_LOGICPD_PXA270 is not set
 # CONFIG_MACH_MAINSTONE is not set
+# CONFIG_MACH_MP900C is not set
 # CONFIG_ARCH_PXA_IDP is not set
 # CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_VIPER is not set
 CONFIG_ARCH_PXA_ESERIES=y
 CONFIG_MACH_E330=y
 CONFIG_MACH_E350=y
@@ -178,7 +173,8 @@ CONFIG_MACH_E740=y
 CONFIG_MACH_E750=y
 CONFIG_MACH_E400=y
 CONFIG_MACH_E800=y
-# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_TRIZEPS_PXA is not set
+# CONFIG_MACH_H5000 is not set
 # CONFIG_MACH_EM_X270 is not set
 # CONFIG_MACH_COLIBRI is not set
 # CONFIG_MACH_ZYLONITE is not set
@@ -186,12 +182,15 @@ CONFIG_MACH_E800=y
 # CONFIG_MACH_TAVOREVB is not set
 # CONFIG_MACH_SAAR is not set
 # CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_CM_X300 is not set
 # CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_MIOA701 is not set
 # CONFIG_MACH_PCM027 is not set
 # CONFIG_ARCH_PXA_PALM is not set
 # CONFIG_PXA_EZX is not set
 CONFIG_PXA25x=y
 # CONFIG_PXA_PWM is not set
+CONFIG_PXA_HAVE_BOARD_IRQS=y
 
 #
 # Boot options
@@ -222,6 +221,7 @@ CONFIG_CPU_CP15_MMU=y
 # CONFIG_OUTER_CACHE is not set
 CONFIG_IWMMXT=y
 CONFIG_XSCALE_PMU=y
+CONFIG_COMMON_CLKDEV=y
 
 #
 # Bus support
@@ -237,6 +237,7 @@ CONFIG_PCMCIA_IOCTL=y
 #
 # PC-card bridges
 #
+CONFIG_PCMCIA_PXA2XX=m
 
 #
 # Kernel Features
@@ -245,25 +246,30 @@ CONFIG_TICK_ONESHOT=y
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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=4096
 # CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -277,9 +283,10 @@ CONFIG_KEXEC=y
 CONFIG_ATAGS_PROC=y
 
 #
-# CPU Frequency scaling
+# CPU Power Management
 #
 # CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -296,6 +303,8 @@ CONFIG_FPE_NWFPE=y
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
 
@@ -309,10 +318,6 @@ CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
 # CONFIG_APM_EMULATION is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -339,7 +344,7 @@ CONFIG_IP_FIB_HASH=y
 # 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_TUNNEL is not set
 CONFIG_INET_XFRM_MODE_TRANSPORT=y
 CONFIG_INET_XFRM_MODE_TUNNEL=y
 CONFIG_INET_XFRM_MODE_BEET=y
@@ -350,25 +355,7 @@ CONFIG_INET_TCP_DIAG=y
 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_IPV6 is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
@@ -376,6 +363,7 @@ CONFIG_IPV6_NDISC_NODETYPE=y
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
@@ -421,25 +409,18 @@ CONFIG_IRDA_FAST_RR=y
 #
 # 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_PXA_FICP=y
-# CONFIG_MCS_FIR is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
 CONFIG_CFG80211=m
 CONFIG_NL80211=y
+CONFIG_WIRELESS_OLD_REGULATORY=y
 CONFIG_WIRELESS_EXT=y
 CONFIG_WIRELESS_EXT_SYSFS=y
 CONFIG_MAC80211=m
@@ -448,7 +429,9 @@ CONFIG_MAC80211=m
 # Rate control algorithm selection
 #
 CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_RC_MINSTREL is not set
 CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
 CONFIG_MAC80211_RC_DEFAULT="pid"
 # CONFIG_MAC80211_MESH is not set
 # CONFIG_MAC80211_LEDS is not set
@@ -539,11 +522,12 @@ CONFIG_MTD_NAND=m
 # 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_GPIO is not set
 CONFIG_MTD_NAND_IDS=m
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_SHARPSL is not set
+CONFIG_MTD_NAND_TMIO=m
 # CONFIG_MTD_NAND_PLATFORM is not set
-# CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
@@ -556,13 +540,13 @@ CONFIG_BLK_DEV=y
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_93CX6 is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -632,37 +616,25 @@ CONFIG_NETDEVICES=y
 CONFIG_WLAN_80211=y
 # CONFIG_PCMCIA_RAYCS is not set
 # CONFIG_LIBERTAS is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
 CONFIG_HERMES=m
 CONFIG_PCMCIA_HERMES=m
 # CONFIG_PCMCIA_SPECTRUM is not set
 # CONFIG_ATMEL is not set
 # CONFIG_AIRO_CS is not set
 # CONFIG_PCMCIA_WL3501 is not set
-# CONFIG_USB_ZD1201 is not set
-# CONFIG_USB_NET_RNDIS_WLAN is not set
-# CONFIG_RTL8187 is not set
 # CONFIG_MAC80211_HWSIM is not set
 # CONFIG_P54_COMMON is not set
 # CONFIG_IWLWIFI_LEDS is not set
 # CONFIG_HOSTAP is not set
 # 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 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_NET_PCMCIA=y
 # CONFIG_PCMCIA_3C589 is not set
 # CONFIG_PCMCIA_3C574 is not set
 # CONFIG_PCMCIA_FMVJ18X is not set
-CONFIG_PCMCIA_PCNET=m
+# CONFIG_PCMCIA_PCNET is not set
 # CONFIG_PCMCIA_NMCLAN is not set
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
@@ -714,13 +686,11 @@ CONFIG_INPUT_TOUCHSCREEN=y
 # 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_WM97XX=m
 CONFIG_TOUCHSCREEN_WM9705=y
 CONFIG_TOUCHSCREEN_WM9712=y
 CONFIG_TOUCHSCREEN_WM9713=y
 # CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
-# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -749,11 +719,13 @@ CONFIG_DEVKMEM=y
 #
 # Non-8250 serial port support
 #
-# CONFIG_SERIAL_PXA is not set
+CONFIG_SERIAL_PXA=y
+# CONFIG_SERIAL_PXA_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
+# CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
 # CONFIG_R3964 is not set
 
@@ -772,6 +744,10 @@ CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_GPIO_SYSFS is not set
 
+#
+# Memory mapped GPIO expanders:
+#
+
 #
 # I2C GPIO expanders:
 #
@@ -786,12 +762,14 @@ CONFIG_GPIOLIB=y
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -799,8 +777,13 @@ CONFIG_SSB_POSSIBLE=y
 #
 CONFIG_MFD_CORE=y
 # CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_UCB1400_CORE is not set
+CONFIG_MFD_TMIO=y
+CONFIG_MFD_T7L66XB=y
+CONFIG_MFD_TC6387XB=y
 CONFIG_MFD_TC6393XB=y
 
 #
@@ -827,6 +810,7 @@ CONFIG_MFD_TC6393XB=y
 CONFIG_FB=y
 # CONFIG_FIRMWARE_EDID is not set
 # CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
@@ -851,8 +835,10 @@ CONFIG_FB_PXA=y
 # CONFIG_FB_PXA_PARAMETERS is not set
 # CONFIG_FB_MBX is not set
 CONFIG_FB_W100=y
-# CONFIG_FB_AM200EPD is not set
+# CONFIG_FB_TMIO is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 # CONFIG_LCD_ILI9320 is not set
@@ -886,6 +872,7 @@ CONFIG_FONT_MINI_4x6=y
 # CONFIG_FONT_10x18 is not set
 # CONFIG_LOGO is not set
 CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
 CONFIG_SND=m
 CONFIG_SND_TIMER=m
 CONFIG_SND_PCM=m
@@ -899,14 +886,18 @@ CONFIG_SND_SUPPORT_OLD_API=y
 CONFIG_SND_VERBOSE_PROCFS=y
 CONFIG_SND_VERBOSE_PRINTK=y
 # CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=m
 CONFIG_SND_DRIVERS=y
 # 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
+# CONFIG_SND_AC97_POWER_SAVE is not set
 CONFIG_SND_ARM=y
+CONFIG_SND_PXA2XX_LIB=m
+CONFIG_SND_PXA2XX_LIB_AC97=y
 # CONFIG_SND_PXA2XX_AC97 is not set
-# CONFIG_SND_USB is not set
 # CONFIG_SND_PCMCIA is not set
 CONFIG_SND_SOC=m
 CONFIG_SND_SOC_AC97_BUS=y
@@ -920,133 +911,19 @@ CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 # CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
 
 #
-# USB Input Devices
+# Special HID drivers
 #
-CONFIG_USB_HID=m
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-CONFIG_USB_SUPPORT=y
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# 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=y
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_C67X00_HCD is not set
-# CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
-# CONFIG_USB_SL811_HCD is not set
-# CONFIG_USB_R8A66597_HCD is not set
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_WDM is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-# CONFIG_USB_STORAGE is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Imaging devices
-#
-# CONFIG_USB_MDC800 is not set
-# CONFIG_USB_MICROTEK is not set
-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_ISIGHTFW is not set
-CONFIG_USB_GADGET=y
-# CONFIG_USB_GADGET_DEBUG_FILES is not set
-CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_AMD5536UDC is not set
-# CONFIG_USB_GADGET_ATMEL_USBA is not set
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-CONFIG_USB_GADGET_PXA25X=y
-CONFIG_USB_PXA25X=y
-CONFIG_USB_PXA25X_SMALL=y
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# 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 is not set
-# CONFIG_USB_ZERO is not set
-CONFIG_USB_ETH=m
-# CONFIG_USB_ETH_RNDIS is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
-# CONFIG_USB_MIDI_GADGET is not set
-# CONFIG_USB_G_PRINTER is not set
-# CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_HID_COMPAT=y
+# CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
 
 #
-# MMC/SD Card Drivers
+# MMC/SD/SDIO Card Drivers
 #
 CONFIG_MMC_BLOCK=y
 CONFIG_MMC_BLOCK_BOUNCE=y
@@ -1054,14 +931,18 @@ CONFIG_MMC_BLOCK_BOUNCE=y
 # CONFIG_MMC_TEST is not set
 
 #
-# MMC/SD Host Controller Drivers
+# MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_PXA is not set
 # CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_TMIO=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
 CONFIG_RTC_LIB=y
 # CONFIG_RTC_CLASS is not set
 # CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
 # CONFIG_UIO is not set
 
 #
@@ -1070,11 +951,17 @@ CONFIG_RTC_LIB=y
 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_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_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_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
 CONFIG_DNOTIFY=y
@@ -1106,6 +993,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
@@ -1142,6 +1030,7 @@ CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1228,13 +1117,15 @@ CONFIG_FRAME_WARN=1024
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_MEMORY_INIT is not set
 CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR 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_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_DEBUG_USER is not set
@@ -1244,15 +1135,23 @@ CONFIG_HAVE_ARCH_KGDB=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
+# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
 CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
 CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
 # CONFIG_CRYPTO_GF128MUL is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_CRYPTD is not set
@@ -1324,14 +1223,17 @@ CONFIG_CRYPTO_ARC4=m
 #
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
 CONFIG_CRC_CCITT=y
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
diff --git a/arch/arm/configs/h5000_defconfig b/arch/arm/configs/h5000_defconfig
new file mode 100644 (file)
index 0000000..649baa3
--- /dev/null
@@ -0,0 +1,996 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc6
+# Tue Sep 16 16:13:48 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_ARCH_MTD_XIP=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 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+# 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_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+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_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 is not set
+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 is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+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=y
+# 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 is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Intel PXA2xx/PXA3xx Implementations
+#
+# CONFIG_ARCH_GUMSTIX is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_ARCH_PXA_ESERIES is not set
+CONFIG_MACH_H5000=y
+# CONFIG_MACH_TRIZEPS4 is not set
+# CONFIG_MACH_EM_X270 is not set
+# CONFIG_MACH_COLIBRI is not set
+# CONFIG_MACH_ZYLONITE is not set
+# CONFIG_MACH_LITTLETON is not set
+# CONFIG_MACH_TAVOREVB is not set
+# CONFIG_MACH_SAAR is not set
+# CONFIG_MACH_ARMCORE is not set
+# CONFIG_MACH_MAGICIAN is not set
+# CONFIG_MACH_PCM027 is not set
+# CONFIG_ARCH_PXA_PALM is not set
+# CONFIG_PXA_EZX is not set
+CONFIG_PXA25x=y
+# CONFIG_PXA_PWM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+# CONFIG_IWMMXT is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# 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 is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_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=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="keepinitrd"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# 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=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_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 is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_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=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 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 is not set
+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=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+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_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PXA2XX is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_SHARP_SL 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 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 is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 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 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 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
+# CONFIG_INPUT_APMPOWER 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_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 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+# 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 is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# 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_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 is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# 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 is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA25X=y
+CONFIG_USB_PXA25X=y
+CONFIG_USB_PXA25X_SMALL=y
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# 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 is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_MMC 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
+
+#
+# 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_RTC_DRV_SA1100=y
+# 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
+
+#
+# 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 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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_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 is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# 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_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES 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 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_SYSCTL_SYSCALL_CHECK=y
+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_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_HASH=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 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=y
+# 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=y
+# 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=y
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index e3357ba10f1f16200dd3cd92f46060addc5898e4..ab8b1e0d0dac7aaa4d82ed0442468b796db2b8a1 100644 (file)
@@ -1,11 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.26-rc5
-# Sun Jun 22 15:51:25 2008
+# Linux kernel version: 2.6.28-rc7
+# Thu Dec  4 15:27:39 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
-CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_GPIO is not set
 CONFIG_GENERIC_TIME=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
@@ -22,8 +22,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -49,14 +48,17 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_GROUP_SCHED is not set
 # CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
-# CONFIG_NAMESPACES 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 is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
+# CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
 CONFIG_SYSCTL_SYSCALL=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -73,9 +75,12 @@ CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
+CONFIG_AIO=y
 CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_PCI_QUIRKS=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
@@ -85,8 +90,7 @@ CONFIG_KPROBES=y
 CONFIG_KRETPROBES=y
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_DMA_ATTRS is not set
-CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
@@ -97,12 +101,13 @@ 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_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
@@ -117,6 +122,7 @@ CONFIG_DEFAULT_CFQ=y
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="cfq"
 CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
 
 #
 # System Type
@@ -128,7 +134,6 @@ CONFIG_CLASSIC_RCU=y
 # 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
@@ -158,7 +163,7 @@ CONFIG_ARCH_KIRKWOOD=y
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
 
 #
 # Marvell Kirkwood Implementations
@@ -199,6 +204,7 @@ CONFIG_ARM_THUMB=y
 # CONFIG_CPU_DCACHE_DISABLE is not set
 CONFIG_OUTER_CACHE=y
 CONFIG_CACHE_FEROCEON_L2=y
+# CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH is not set
 
 #
 # Bus support
@@ -217,25 +223,30 @@ CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_PREEMPT=y
 CONFIG_HZ=100
 CONFIG_AEABI=y
 # CONFIG_OABI_COMPAT is not set
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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=4096
 # CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -247,6 +258,11 @@ CONFIG_CMDLINE=""
 # CONFIG_XIP_KERNEL is not set
 # CONFIG_KEXEC is not set
 
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
 #
 # Floating point emulation
 #
@@ -260,6 +276,8 @@ CONFIG_CMDLINE=""
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
 
@@ -268,10 +286,6 @@ CONFIG_BINFMT_ELF=y
 #
 # CONFIG_PM is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
-
-#
-# Networking
-#
 CONFIG_NET=y
 
 #
@@ -322,6 +336,15 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
+CONFIG_NET_DSA=y
+# CONFIG_NET_DSA_TAG_DSA is not set
+CONFIG_NET_DSA_TAG_EDSA=y
+# CONFIG_NET_DSA_TAG_TRAILER is not set
+CONFIG_NET_DSA_MV88E6XXX=y
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+CONFIG_NET_DSA_MV88E6123_61_65=y
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
@@ -343,12 +366,12 @@ CONFIG_NET_PKTGEN=m
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
 # CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
 CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
@@ -365,6 +388,8 @@ 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
@@ -453,7 +478,7 @@ CONFIG_M25PXX_USE_FAST_READ=y
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
 CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_VERIFY_WRITE=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_IDS=y
@@ -561,6 +586,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
 CONFIG_ATA=y
 # CONFIG_ATA_NONSTANDARD is not set
 CONFIG_SATA_PMP=y
@@ -619,7 +645,6 @@ CONFIG_SATA_MV=y
 # CONFIG_PATA_SIS is not set
 # CONFIG_PATA_VIA is not set
 # CONFIG_PATA_WINBOND is not set
-# CONFIG_PATA_PLATFORM is not set
 # CONFIG_PATA_SCH is not set
 # CONFIG_MD is not set
 # CONFIG_FUSION is not set
@@ -627,11 +652,14 @@ CONFIG_SATA_MV=y
 #
 # IEEE 1394 (FireWire) support
 #
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
 # CONFIG_I2O 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
@@ -639,7 +667,23 @@ CONFIG_NETDEVICES=y
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
@@ -650,12 +694,16 @@ CONFIG_MII=y
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
+# CONFIG_SMC911X is not set
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
@@ -676,14 +724,12 @@ CONFIG_NET_PCI=y
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
 CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
-CONFIG_E1000=y
-CONFIG_E1000_NAPI=y
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000 is not set
 # CONFIG_E1000E is not set
-# CONFIG_E1000E_ENABLED is not set
 # CONFIG_IP1000 is not set
 # CONFIG_IGB is not set
 # CONFIG_NS83820 is not set
@@ -699,6 +745,8 @@ CONFIG_E1000_NAPI=y
 CONFIG_MV643XX_ETH=y
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_JME is not set
 # CONFIG_NETDEV_10000 is not set
 # CONFIG_TR is not set
 
@@ -765,7 +813,11 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 # Character devices
 #
-# CONFIG_VT is not set
+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 is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_NOZOMI is not set
@@ -775,7 +827,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_NR_UARTS=4
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
 # CONFIG_SERIAL_8250_EXTENDED is not set
@@ -800,44 +852,64 @@ CONFIG_DEVPORT=y
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
 
 #
 # I2C Hardware Bus support
 #
+
+#
+# PC SMBus host controller drivers
+#
 # CONFIG_I2C_ALI1535 is not set
 # CONFIG_I2C_ALI1563 is not set
 # CONFIG_I2C_ALI15X3 is not set
 # CONFIG_I2C_AMD756 is not set
 # CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_GPIO is not set
 # CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISCH is not set
 # CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_I2C_SIMTEC is not set
 # CONFIG_I2C_SIS5595 is not set
 # CONFIG_I2C_SIS630 is not set
 # CONFIG_I2C_SIS96X 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_VIA is not set
 # CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MV64XXX=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
 # CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
 # CONFIG_I2C_PCA_PLATFORM is not set
-CONFIG_I2C_MV64XXX=y
+# 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_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
@@ -864,20 +936,26 @@ CONFIG_SPI_ORION=y
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
 # CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=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_MFD_ASIC3 is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
 
 #
 # Multimedia devices
@@ -910,8 +988,10 @@ CONFIG_SSB_POSSIBLE=y
 # CONFIG_DISPLAY_SUPPORT is not set
 
 #
-# Sound
+# Console display driver support
 #
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
@@ -922,9 +1002,36 @@ CONFIG_HID=y
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
+# CONFIG_HID_PID is not set
 # CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_BRIGHT=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DELL=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -940,8 +1047,9 @@ CONFIG_USB_DEVICEFS=y
 CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_OTG is not set
-# CONFIG_USB_OTG_WHITELIST is not set
-# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
 
 #
 # USB Host Controller Drivers
@@ -956,20 +1064,23 @@ CONFIG_USB_EHCI_TT_NEWSCHED=y
 # CONFIG_USB_UHCI_HCD is not set
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
 
 #
 # USB Device Class drivers
 #
 # CONFIG_USB_ACM is not set
-CONFIG_USB_PRINTER=y
+CONFIG_USB_PRINTER=m
 # CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# see USB_STORAGE Help for more information
 #
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -992,7 +1103,6 @@ CONFIG_USB_STORAGE_JUMPSHOT=y
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_MON is not set
 
 #
 # USB port drivers
@@ -1005,7 +1115,7 @@ CONFIG_USB_STORAGE_JUMPSHOT=y
 # 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_SEVSEG is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
@@ -1023,8 +1133,12 @@ CONFIG_USB_STORAGE_JUMPSHOT=y
 # CONFIG_USB_IOWARRIOR is not set
 # CONFIG_USB_TEST is not set
 # CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
 # CONFIG_USB_GADGET is not set
+# CONFIG_UWB is not set
 # CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
 CONFIG_NEW_LEDS=y
 # CONFIG_LEDS_CLASS is not set
 
@@ -1038,6 +1152,8 @@ CONFIG_NEW_LEDS=y
 # CONFIG_LEDS_TRIGGERS 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
 
 #
@@ -1056,7 +1172,6 @@ CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_DRV_DS1374 is not set
 # CONFIG_RTC_DRV_DS1672 is not set
 # CONFIG_RTC_DRV_MAX6900 is not set
-CONFIG_RTC_DRV_MV=y
 # CONFIG_RTC_DRV_RS5C372 is not set
 # CONFIG_RTC_DRV_ISL1208 is not set
 # CONFIG_RTC_DRV_X1205 is not set
@@ -1064,29 +1179,39 @@ CONFIG_RTC_DRV_MV=y
 # CONFIG_RTC_DRV_PCF8583 is not set
 # CONFIG_RTC_DRV_M41T80 is not set
 # CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
 
 #
 # SPI RTC drivers
 #
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
 # CONFIG_RTC_DRV_MAX6902 is not set
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
 
 #
 # Platform RTC drivers
 #
 # CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 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_M48T35 is not set
 # CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
 # CONFIG_RTC_DRV_V3020 is not set
 
 #
 # on-CPU RTC drivers
 #
+CONFIG_RTC_DRV_MV=y
 CONFIG_DMADEVICES=y
 
 #
@@ -1099,6 +1224,8 @@ CONFIG_DMA_ENGINE=y
 # DMA Clients
 #
 # CONFIG_NET_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_REGULATOR is not set
 # CONFIG_UIO is not set
 
 #
@@ -1109,11 +1236,12 @@ CONFIG_EXT2_FS=y
 # 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_EXT4_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_FILE_LOCKING=y
 CONFIG_XFS_FS=y
 # CONFIG_XFS_QUOTA is not set
 # CONFIG_XFS_POSIX_ACL is not set
@@ -1131,7 +1259,7 @@ CONFIG_INOTIFY_USER=y
 #
 # CD-ROM/DVD Filesystems
 #
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 CONFIG_UDF_FS=m
@@ -1140,9 +1268,9 @@ CONFIG_UDF_NLS=y
 #
 # DOS/FAT/NT Filesystems
 #
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
@@ -1152,6 +1280,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
@@ -1182,6 +1311,7 @@ CONFIG_JFFS2_RTIME=y
 CONFIG_CRAMFS=y
 # 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
@@ -1192,13 +1322,13 @@ CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
-# CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1210,24 +1340,8 @@ CONFIG_SUNRPC=y
 #
 # 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_PARTITION_ADVANCED 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
@@ -1284,11 +1398,14 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_DEBUG_SLAB is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
 # CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
@@ -1300,21 +1417,40 @@ CONFIG_DETECT_SOFTLOCKUP=y
 # 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_BUGVERBOSE=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
 # 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_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_KPROBES_SANITY_TEST is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_LKDTM is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER 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_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_ERRORS=y
 # CONFIG_DEBUG_STACK_USAGE is not set
@@ -1326,6 +1462,7 @@ CONFIG_DEBUG_LL=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_ASYNC_CORE=y
 CONFIG_CRYPTO=y
@@ -1333,8 +1470,12 @@ CONFIG_CRYPTO=y
 #
 # Crypto core or helper
 #
+# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_AEAD=m
 CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_RNG=m
 CONFIG_CRYPTO_MANAGER=m
 # CONFIG_CRYPTO_GF128MUL is not set
 # CONFIG_CRYPTO_NULL is not set
@@ -1373,6 +1514,10 @@ CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # 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
@@ -1403,6 +1548,11 @@ CONFIG_CRYPTO_PCBC=m
 #
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 # CONFIG_CRYPTO_DEV_HIFN_795X is not set
 
@@ -1410,10 +1560,9 @@ 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=y
+# CONFIG_CRC_T10DIF is not set
 CONFIG_CRC_ITU_T=m
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
index 6077f2cb88e4cecfce760d26237fd984ac6db594..d25c41bab06cccccf20cd3836c4aa03de289134d 100644 (file)
@@ -1,39 +1,67 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17-rc4
-# Thu May 25 15:42:51 2006
+# Linux kernel version: 2.6.27-simtec-micrel1
+# Fri Dec  5 10:30:27 2008
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
 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"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# 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=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_UID16=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -41,30 +69,50 @@ 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 is not set
+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_SLOB is not set
-CONFIG_OBSOLETE_INTERMODULE=y
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
 
 #
 # IO Schedulers
@@ -78,60 +126,77 @@ CONFIG_DEFAULT_AS=y
 # 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_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 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=y
+# 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 is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_REALVIEW is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_AAEC2000 is not set
-# CONFIG_ARCH_AT91 is not set
-CONFIG_ARCH_KS8695=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
 
 #
 # Kendin/Micrel KS8695 Implementations
 #
 CONFIG_MACH_KS8695=y
-# CONFIG_MACH_DSM320 is not set
-# CONFIG_MACH_CM4002 is not set
-# CONFIG_MACH_CM4008 is not set
-# CONFIG_MACH_CM40xx is not set
-# CONFIG_MACH_LITE300 is not set
-# CONFIG_MACH_SE4200 is not set
-# CONFIG_MACH_MANGA_KS8695 is not set
+CONFIG_MACH_DSM320=y
 
 #
 # Processor Type
 #
 CONFIG_CPU_32=y
 CONFIG_CPU_ARM922T=y
-CONFIG_CPU_32v4=y
+CONFIG_CPU_32v4T=y
 CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_PABRT_NOIFAR=y
 CONFIG_CPU_CACHE_V4WT=y
 CONFIG_CPU_CACHE_VIVT=y
 CONFIG_CPU_COPY_V4WB=y
 CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
 
 #
 # Processor Features
@@ -140,16 +205,16 @@ CONFIG_CPU_TLB_V4WBI=y
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_OUTER_CACHE is not set
 
 #
 # Bus support
 #
 CONFIG_PCI=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_LEGACY=y
 CONFIG_PCI_DEBUG=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
 CONFIG_PCCARD=y
 # CONFIG_PCMCIA_DEBUG is not set
 CONFIG_PCMCIA=y
@@ -173,9 +238,12 @@ CONFIG_PCCARD_NONSTATIC=y
 #
 # Kernel Features
 #
+# CONFIG_TICK_ONESHOT is not set
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
-# CONFIG_AEABI is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
 # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
@@ -184,7 +252,14 @@ CONFIG_FLATMEM_MANUAL=y
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
 # CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -194,6 +269,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
 
 #
 # Floating point emulation
@@ -202,8 +278,7 @@ CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev
 #
 # At least one emulation must be selected
 #
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_NWFPE is not set
 # CONFIG_FPE_FASTFPE is not set
 
 #
@@ -212,34 +287,33 @@ CONFIG_FPE_NWFPE=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_APM is not set
-
-#
-# Networking
-#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_FIB_HASH=y
 CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=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
@@ -250,28 +324,21 @@ CONFIG_IP_PNP_BOOTP=y
 # 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_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -282,13 +349,8 @@ CONFIG_TCP_CONG_BIC=y
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -296,9 +358,21 @@ CONFIG_TCP_CONG_BIC=y
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -307,36 +381,40 @@ CONFIG_TCP_CONG_BIC=y
 #
 # 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
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
 # CONFIG_MTD_CONCAT is not set
 CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY 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
@@ -355,22 +433,25 @@ 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 is not set
-CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
 # CONFIG_MTD_CFI_STAA is not set
 CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=4
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -388,29 +469,15 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 # CONFIG_MTD_NAND is not set
-
-#
-# OneNAND Flash Device Drivers
-#
 # CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# UBI - Unsorted block images
 #
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -422,13 +489,17 @@ CONFIG_MTD_CFI_UTIL=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
 #
@@ -436,127 +507,85 @@ CONFIG_BLK_DEV_INITRD=y
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
 # CONFIG_FUSION is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
-# I2O device support
+# Enable only one of the two stacks, unless you know what you are doing
 #
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 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
-
-#
-# ARCnet devices
-#
+# CONFIG_VETH is not set
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-CONFIG_ARM_KS8695_ETHER=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
-
-#
-# Tulip family network device support
-#
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 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_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# PCMCIA network device support
-#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_PRISM54=m
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_HOSTAP is not set
 # CONFIG_NET_PCMCIA is not set
-
-#
-# Wan interfaces
-#
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 
 #
 # Input device support
 #
 CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -566,7 +595,6 @@ CONFIG_INPUT_MOUSEDEV=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -576,6 +604,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # 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
 
@@ -589,9 +618,13 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # Character devices
 #
 CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
 
 #
 # Serial drivers
@@ -609,132 +642,113 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
 # CONFIG_NVRAM is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-
 #
 # PCMCIA character devices
 #
 # CONFIG_SYNCLINK_CS is not set
 # CONFIG_CARDMAN_4000 is not set
 # CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
-
-#
-# SPI support
-#
 # CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
-
-#
-# Misc devices
-#
+# CONFIG_WATCHDOG is not set
 
 #
-# LED devices
+# Sonics Silicon Backplane
 #
-# CONFIG_NEW_LEDS is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# LED drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 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
 
 #
-# LED Triggers
+# Multimedia devices
 #
 
 #
-# Multimedia devices
+# Multimedia core support
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia drivers
 #
-# CONFIG_DVB is not set
+# CONFIG_DAB is not set
 
 #
 # Graphics support
 #
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
 # CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
-# Console display driver support
+# Display device support
 #
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
-# Sound
+# Console display driver support
 #
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
 # CONFIG_SOUND is not set
-
-#
-# USB support
-#
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW 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 is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# Enable Host or Gadget support to see Inventra options
 #
 
 #
-# USB Gadget Support
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
 
 #
-# Real Time Clock
+# Voltage and Current regulators
 #
-CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
+# 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
 
 #
 # File systems
@@ -743,16 +757,16 @@ 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_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
@@ -774,10 +788,11 @@ CONFIG_DNOTIFY=y
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -790,67 +805,113 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=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=y
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-# CONFIG_NFS_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
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
+# 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 is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
 CONFIG_FRAME_POINTER=y
-# CONFIG_UNWIND_INFO is not set
-CONFIG_FORCED_INLINING=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE 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=y
 # CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
 CONFIG_DEBUG_LL=y
 # CONFIG_DEBUG_ICEDCC is not set
 
@@ -859,21 +920,103 @@ CONFIG_DEBUG_LL=y
 #
 # 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_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_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
 
 #
-# Cryptographic options
+# Ciphers
 #
-# CONFIG_CRYPTO is not set
+# 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
 
 #
-# Hardware crypto devices
+# Compression
 #
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/mx31moboard_defconfig b/arch/arm/configs/mx31moboard_defconfig
new file mode 100644 (file)
index 0000000..e90f86d
--- /dev/null
@@ -0,0 +1,790 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Fri Oct 24 11:41:22 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_ARCH_MTD_XIP=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 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 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_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 is not set
+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 is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# 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=y
+# 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 is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX2 is not set
+CONFIG_ARCH_MX3=y
+
+#
+# MX3 Options
+#
+# CONFIG_MACH_MX31ADS is not set
+# CONFIG_MACH_PCM037 is not set
+# CONFIG_MACH_MX31LITE is not set
+CONFIG_MACH_MX31MOBOARD=y
+# CONFIG_MXC_IRQ_PRIOR is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_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=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+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_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="noinitrd console=ttymxc0,115200 root=/dev/mtdblock2 rw ip=off"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+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 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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_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=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# 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=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# 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=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# 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 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_ARM_INTEGRATOR 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 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 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 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_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_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 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+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 is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# 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_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 is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_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
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS 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 is not set
+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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_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_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 is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+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 is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/mx31pdk_defconfig b/arch/arm/configs/mx31pdk_defconfig
new file mode 100644 (file)
index 0000000..95ffc0d
--- /dev/null
@@ -0,0 +1,773 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc2
+# Sun Oct 26 15:55:29 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_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC 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=17
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_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_AIO=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 is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=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 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_INTEGRITY 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
+# CONFIG_FREEZER 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_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=y
+# 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 is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX2 is not set
+CONFIG_ARCH_MX3=y
+
+#
+# MX3 Options
+#
+# CONFIG_MACH_MX31ADS is not set
+# CONFIG_MACH_PCM037 is not set
+# CONFIG_MACH_MX31LITE is not set
+CONFIG_MACH_MX31_3DS=y
+# CONFIG_MXC_IRQ_PRIOR is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_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_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_UNEVICTABLE_LRU is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM 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_NET_KEY=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_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_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER 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_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_PHONET is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV 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 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_DUMMY is not set
+# CONFIG_BONDING 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 is not set
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP 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 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_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+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_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_MFD_WM8400 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 is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY 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
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# 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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_FS 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 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_DYNAMIC_PRINTK_DEBUG 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_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC 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_PCBC is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC 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_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 is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD 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
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# 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/neocore926_defconfig b/arch/arm/configs/neocore926_defconfig
new file mode 100644 (file)
index 0000000..325f1e1
--- /dev/null
@@ -0,0 +1,1302 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc1
+# Tue Jul 29 10:46:54 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+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=17
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# 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_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_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 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 is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY 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=y
+# 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 is not set
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+CONFIG_ARCH_AT91SAM9263=y
+# CONFIG_ARCH_AT91SAM9RL is not set
+# CONFIG_ARCH_AT91SAM9G20 is not set
+# CONFIG_ARCH_AT91CAP9 is not set
+# CONFIG_ARCH_AT91X40 is not set
+CONFIG_AT91_PMC_UNIT=y
+
+#
+# AT91SAM9263 Board Type
+#
+# CONFIG_MACH_AT91SAM9263EK is not set
+# CONFIG_MACH_USB_A9263 is not set
+CONFIG_MACH_NEOCORE926=y
+
+#
+# AT91 Board Options
+#
+CONFIG_MTD_AT91_DATAFLASH_CARD=y
+
+#
+# AT91 Feature Selections
+#
+# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set
+CONFIG_AT91_TIMER_HZ=100
+CONFIG_AT91_EARLY_DBGU=y
+# CONFIG_AT91_EARLY_USART0 is not set
+# CONFIG_AT91_EARLY_USART1 is not set
+# CONFIG_AT91_EARLY_USART2 is not set
+# CONFIG_AT91_EARLY_USART3 is not set
+# CONFIG_AT91_EARLY_USART4 is not set
+# CONFIG_AT91_EARLY_USART5 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=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=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_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=y
+# 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 is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# 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=y
+CONFIG_NFTL_RW=y
+# 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=y
+
+#
+# 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=y
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_ATMEL_ECC_HW=y
+# CONFIG_MTD_NAND_ATMEL_ECC_SOFT is not set
+# CONFIG_MTD_NAND_ATMEL_ECC_NONE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# 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=y
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=y
+CONFIG_ATMEL_TCLIB=y
+CONFIG_ATMEL_TCB_CLKSRC=y
+CONFIG_ATMEL_TCB_CLKSRC_BLOCK=0
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ATMEL_SSC 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 is not set
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# 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=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+CONFIG_MACB=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# 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 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=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=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_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_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=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_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=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 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 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_PDC is not set
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_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=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_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_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
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG 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_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 is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+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_ATMEL=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+# CONFIG_BACKLIGHT_ATMEL_PWM is not set
+# CONFIG_BACKLIGHT_CORGI 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=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# 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_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# 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_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 is not set
+
+#
+# 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_AT91=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
+# CONFIG_UIO 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 is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+# 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 is not set
+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=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_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_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 is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+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_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_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_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 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 is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 0884f2370c3ae649ac15009a8677e7d486040146..61d0fc5b2417f486fa3d0e71dcaec59a210a339e 100644 (file)
@@ -728,9 +728,9 @@ CONFIG_RTC_CLASS=m
 #
 # RTC interfaces
 #
-CONFIG_RTC_INTF_SYSFS=m
-CONFIG_RTC_INTF_PROC=m
-CONFIG_RTC_INTF_DEV=m
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
 
 #
 # RTC drivers
diff --git a/arch/arm/configs/omap3_pandora_defconfig b/arch/arm/configs/omap3_pandora_defconfig
new file mode 100644 (file)
index 0000000..09543f4
--- /dev/null
@@ -0,0 +1,1409 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc7
+# Fri Dec  5 11:54:09 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_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=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_AIO=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_CLK=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
+# CONFIG_FREEZER 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_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_MSM 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_RESET_CLOCKS is not set
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=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_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OVERO is not set
+CONFIG_MACH_OMAP3_PANDORA=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_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_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+# CONFIG_LEDS is not set
+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 is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE 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_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA 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
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS 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_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_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_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_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_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=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=800
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+CONFIG_INPUT_JOYDEV=y
+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_GPIO is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 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=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_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_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
+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_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+CONFIG_GPIO_TWL4030=y
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+CONFIG_TWL4030_CORE=y
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C 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 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_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_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BRIGHT is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DELL is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# 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_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_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_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST 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_VBUS_DRAW=2
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+CONFIG_USB_GADGET_OMAP=y
+CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_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_USB_CDC_COMPOSITE is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO 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/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_OMAP is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 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_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO 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_EXT4_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_FILE_LOCKING=y
+# 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_PROC_PAGE_MONITOR=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 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 is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG 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_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_RNG=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
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 948a212fb1cccbb80eaeeb23a5877c6aef82d528..b77d054169eeb0c8b9e8dd6e1658258b7f622aea 100644 (file)
@@ -316,7 +316,82 @@ CONFIG_BINFMT_MISC=y
 #
 # CONFIG_PM is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
-# CONFIG_NET is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+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=y
+# 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_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_NET_DSA 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
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -332,6 +407,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
 # CONFIG_MTD is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
@@ -390,6 +467,54 @@ CONFIG_SCSI_LOWLEVEL=y
 # 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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
 
 #
 # Input device support
@@ -816,6 +941,27 @@ CONFIG_TMPFS=y
 # 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=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 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
index 14826f0dabde9300232a283c01f9b5153075dd17..59e4463c2da23dd0f82947cfb66c36c135ec7202 100644 (file)
@@ -1069,9 +1069,9 @@ CONFIG_RTC_CLASS=m
 #
 # RTC interfaces
 #
-CONFIG_RTC_INTF_SYSFS=m
-CONFIG_RTC_INTF_PROC=m
-CONFIG_RTC_INTF_DEV=m
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
 
 #
index 0c09b23167ec1f69b961322a5f051e2a8709347e..cd29824d791c7bf55457608912b3ca51716a2bd2 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc3
-# Wed Oct 25 14:12:00 2006
+# Linux kernel version: 2.6.28-rc2
+# Mon Nov 10 14:41:47 2008
 #
 CONFIG_ARM=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_GENERIC_GPIO is not set
+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_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
-# CONFIG_CPUSETS 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_INITRAMFS_SOURCE=""
+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 is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
 CONFIG_UID16=y
-# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
-CONFIG_KALLSYMS_ALL=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_SLAB=y
+CONFIG_AIO=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_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_CLK=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_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 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_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 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
@@ -92,6 +119,8 @@ CONFIG_DEFAULT_DEADLINE=y
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
 
 #
 # System Type
@@ -103,19 +132,26 @@ CONFIG_ARCH_REALVIEW=y
 # 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_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 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
@@ -123,13 +159,29 @@ CONFIG_ARCH_REALVIEW=y
 # 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 is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
 
 #
 # RealView platform type
 #
 CONFIG_MACH_REALVIEW_EB=y
-CONFIG_REALVIEW_MPCORE=y
+# CONFIG_REALVIEW_EB_A9MP is not set
+CONFIG_REALVIEW_EB_ARM11MP=y
+# CONFIG_REALVIEW_EB_ARM11MP_REVB is not set
+CONFIG_MACH_REALVIEW_PB11MP=y
+# CONFIG_MACH_REALVIEW_PB1176 is not set
+# CONFIG_MACH_REALVIEW_PBA8 is not set
+CONFIG_REALVIEW_HIGH_PHYS_OFFSET=y
 
 #
 # Processor Type
@@ -138,12 +190,15 @@ CONFIG_CPU_32=y
 # CONFIG_CPU_ARM926T is not set
 CONFIG_CPU_V6=y
 CONFIG_CPU_32v6K=y
+# CONFIG_CPU_V7 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
 
@@ -153,9 +208,10 @@ CONFIG_CPU_CP15_MMU=y
 CONFIG_ARM_THUMB=y
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
-# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
 CONFIG_HAS_TLS_REG=y
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_L2X0=y
 CONFIG_ARM_GIC=y
 CONFIG_ICST307=y
 
@@ -163,32 +219,44 @@ CONFIG_ICST307=y
 # Bus support
 #
 CONFIG_ARM_AMBA=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
 # Kernel Features
 #
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
 CONFIG_SMP=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 CONFIG_NR_CPUS=4
 CONFIG_HOTPLUG_CPU=y
 CONFIG_LOCAL_TIMERS=y
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=100
-# CONFIG_AEABI is not set
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -198,6 +266,12 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -206,8 +280,7 @@ CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=tt
 #
 # At least one emulation must be selected
 #
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_NWFPE is not set
 # CONFIG_FPE_FASTFPE is not set
 CONFIG_VFP=y
 
@@ -215,28 +288,29 @@ CONFIG_VFP=y
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-# CONFIG_APM is not set
-
-#
-# Networking
-#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -255,36 +329,25 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_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
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
@@ -294,10 +357,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
 # CONFIG_NET_SCHED is not set
 
 #
@@ -305,9 +364,14 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # 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_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -316,38 +380,37 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+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
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_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
@@ -373,7 +436,6 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
 
 #
 # Mapping drivers for chip access
@@ -397,115 +459,73 @@ CONFIG_MTD_ARM_INTEGRATOR=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 # CONFIG_MTD_NAND is not set
-
-#
-# OneNAND Flash Device Drivers
-#
 # CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# UBI - Unsorted block images
 #
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+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_RAM is not set
-CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE 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
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# PHY device support
-#
+# CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+# CONFIG_AX88796 is not set
 CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
+CONFIG_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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR 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_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 
 #
@@ -513,6 +533,7 @@ CONFIG_SMC91X=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -522,7 +543,6 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -538,9 +558,16 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_STOWAWAY 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_VSXXXAA 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
 
@@ -558,9 +585,11 @@ CONFIG_SERIO_LIBPS2=y
 # 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
 
 #
@@ -579,97 +608,91 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=16
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
 # CONFIG_I2C is not set
-
-#
-# SPI support
-#
 # CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
-
-#
-# Misc devices
-#
-# CONFIG_SGI_IOC4 is not set
-# CONFIG_TIFM_CORE is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
 
 #
-# LED devices
+# Sonics Silicon Backplane
 #
-# CONFIG_NEW_LEDS is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# LED drivers
+# Multifunction device drivers
 #
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 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_WM8400 is not set
 
 #
-# LED Triggers
+# Multimedia devices
 #
 
 #
-# Multimedia devices
+# Multimedia core support
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia drivers
 #
-# CONFIG_DVB is not set
+# CONFIG_DAB is not set
 
 #
 # Graphics support
 #
-# CONFIG_FIRMWARE_EDID is not set
+# 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_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
 # CONFIG_FB_MACMODES is not set
 # CONFIG_FB_BACKLIGHT is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
 CONFIG_FB_ARMCLCD=y
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Console display driver support
@@ -677,28 +700,17 @@ CONFIG_FB_ARMCLCD=y
 # 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
-
-#
-# Logo configuration
-#
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_LOGO_LINUX_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
 CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
+CONFIG_SOUND_OSS_CORE=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
@@ -712,100 +724,65 @@ 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_AC97_CODEC=m
-CONFIG_SND_AC97_BUS=m
-# 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_ARMAACI=m
-
-#
-# Open Sound System
-#
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+# CONFIG_SND_DRIVERS is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_ARMAACI=y
+# CONFIG_SND_SOC is not set
 # CONFIG_SOUND_PRIME is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
-# CONFIG_USB is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
+CONFIG_AC97_BUS=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_ARMMMCI=y
-# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
 
 #
-# Real Time Clock
+# MMC/SD/SDIO Card Drivers
 #
-CONFIG_RTC_LIB=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-# CONFIG_RTC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
 
 #
-# RTC interfaces
+# MMC/SD/SDIO Host Controller Drivers
 #
-CONFIG_RTC_INTF_SYSFS=y
-CONFIG_RTC_INTF_PROC=y
-CONFIG_RTC_INTF_DEV=y
-CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_MMC_ARMMMCI=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
 
 #
-# RTC drivers
+# Voltage and Current regulators
 #
-# CONFIG_RTC_DRV_DS1553 is not set
-# CONFIG_RTC_DRV_DS1742 is not set
-# CONFIG_RTC_DRV_M48T86 is not set
-CONFIG_RTC_DRV_PL031=y
-# CONFIG_RTC_DRV_TEST is not set
-# CONFIG_RTC_DRV_V3020 is not set
+# 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
 
 #
 # File systems
 #
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
+CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
-# CONFIG_INOTIFY_USER is not set
+CONFIG_INOTIFY_USER=y
 # CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
@@ -831,11 +808,11 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
 # CONFIG_CONFIGFS_FS is not set
 
 #
@@ -848,29 +825,28 @@ CONFIG_RAMFS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -878,17 +854,12 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
@@ -929,64 +900,177 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_KOI8_R is not set
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
+# CONFIG_DLM is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-# CONFIG_ENABLE_MUST_CHECK 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_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_RT_MUTEXES is not set
 # CONFIG_RT_MUTEX_TESTER is not set
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_RWSEMS=y
+# 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_FS is not set
 # CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
 # CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
 CONFIG_FRAME_POINTER=y
-# CONFIG_UNWIND_INFO is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_HEADERS_CHECK is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+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_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC 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_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# 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_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 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
 
 #
-# Cryptographic options
+# Random Number Generation
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 907e54344dad05af00744830cd6aae993b3a436a..7e253f58ed18a34af0e5997a5ab497cc07ef3fdb 100644 (file)
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc2
-# Thu Sep 29 14:50:10 2005
+# Linux kernel version: 2.6.28-rc2
+# Mon Nov 10 14:39:48 2008
 #
 CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_GENERIC_GPIO is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_MMU=y
-CONFIG_UID16=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_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
-# CONFIG_EXPERIMENTAL is not set
-CONFIG_CLEAN_COMPILE=y
+CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
-CONFIG_INITRAMFS_SOURCE=""
+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=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 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
 # CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_AIO=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_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=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_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 is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
 
 #
 # System Type
 #
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+CONFIG_ARCH_REALVIEW=y
+# 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_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX 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 is not set
-# CONFIG_ARCH_VERSATILE is not set
-CONFIG_ARCH_REALVIEW=y
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
 
 #
 # RealView platform type
 #
 CONFIG_MACH_REALVIEW_EB=y
+# CONFIG_REALVIEW_EB_A9MP is not set
+CONFIG_REALVIEW_EB_ARM11MP=y
+# CONFIG_REALVIEW_EB_ARM11MP_REVB is not set
+CONFIG_MACH_REALVIEW_PB11MP=y
+CONFIG_MACH_REALVIEW_PB1176=y
+# CONFIG_MACH_REALVIEW_PBA8 is not set
 
 #
 # Processor Type
 #
 CONFIG_CPU_32=y
-CONFIG_CPU_ARM926T=y
-# CONFIG_CPU_V6 is not set
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5TJ=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_COPY_V4WB=y
-CONFIG_CPU_TLB_V4WBI=y
+# CONFIG_CPU_ARM926T is not set
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+# CONFIG_CPU_V7 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
@@ -107,8 +206,9 @@ CONFIG_CPU_TLB_V4WBI=y
 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_CPU_BPREDICT_DISABLE is not set
+CONFIG_OUTER_CACHE=y
+CONFIG_CACHE_L2X0=y
 CONFIG_ARM_GIC=y
 CONFIG_ICST307=y
 
@@ -116,20 +216,41 @@ CONFIG_ICST307=y
 # Bus support
 #
 CONFIG_ARM_AMBA=y
-CONFIG_ISA_DMA_API=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
 # CONFIG_PCCARD is not set
 
 #
 # Kernel Features
 #
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_SMP is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -139,6 +260,12 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=ttyAMA0 mem=128M"
 # CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
 
 #
 # Floating point emulation
@@ -147,26 +274,24 @@ CONFIG_CMDLINE="root=/dev/nfs nfsroot=10.1.69.3:/work/nfsroot ip=dhcp console=tt
 #
 # At least one emulation must be selected
 #
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_VFP is not set
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
 
 #
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
 
 #
 # Power management options
 #
 # CONFIG_PM is not set
-
-#
-# Networking
-#
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
 
 #
@@ -175,6 +300,11 @@ CONFIG_NET=y
 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 is not set
@@ -186,34 +316,56 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_IP_PNP_RARP is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
 # CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=y
 CONFIG_INET_TCP_DIAG=y
 # CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_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_NET_DSA 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
-# CONFIG_NET_CLS_ROUTE 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_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -222,30 +374,37 @@ CONFIG_TCP_CONG_BIC=y
 #
 # Generic Driver Options
 #
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
+# 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_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
@@ -266,7 +425,6 @@ CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_AMDSTD_RETRY=0
 # CONFIG_MTD_CFI_STAA is not set
 CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
@@ -279,7 +437,6 @@ CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
 # CONFIG_MTD_PHYSMAP is not set
 CONFIG_MTD_ARM_INTEGRATOR=y
-# CONFIG_MTD_EDB7312 is not set
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -288,7 +445,7 @@ CONFIG_MTD_ARM_INTEGRATOR=y
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_PHRAM is not set
 # CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -296,121 +453,81 @@ CONFIG_MTD_ARM_INTEGRATOR=y
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
 # CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
 # CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
 
 #
-# Parallel port support
+# UBI - Unsorted block images
 #
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
+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_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
 # CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-CONFIG_IOSCHED_DEADLINE=y
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
 
 #
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
 # CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
 # CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# PHY device support
-#
+# CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+# CONFIG_AX88796 is not set
 CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
+CONFIG_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_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR 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
-
-#
-# ISDN subsystem
-#
 # 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
@@ -420,7 +537,6 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
 
@@ -433,11 +549,19 @@ CONFIG_KEYBOARD_ATKBD=y
 # 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_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_VSXXXAA 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
 
@@ -455,8 +579,11 @@ CONFIG_SERIO_LIBPS2=y
 # 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
 
 #
@@ -475,73 +602,91 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=16
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-
-#
-# I2C support
-#
+# CONFIG_TCG_TPM is not set
 # CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
 
 #
-# Hardware Monitoring support
+# Sonics Silicon Backplane
 #
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
 
 #
-# Misc devices
+# Multifunction device drivers
 #
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 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_WM8400 is not set
 
 #
-# Multimedia Capabilities Port drivers
+# Multimedia devices
 #
 
 #
-# Multimedia devices
+# Multimedia core support
 #
 # CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
 
 #
-# Digital Video Broadcasting Devices
+# Multimedia drivers
 #
-# CONFIG_DVB is not set
+# 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_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=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_ARMCLCD=y
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
 
 #
 # Console display driver support
@@ -549,27 +694,17 @@ CONFIG_FB_ARMCLCD=y
 # 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
-
-#
-# Logo configuration
-#
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 CONFIG_LOGO_LINUX_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
 CONFIG_SOUND=y
-
-#
-# Advanced Linux Sound Architecture
-#
+CONFIG_SOUND_OSS_CORE=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
@@ -577,59 +712,71 @@ CONFIG_SND_PCM=y
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=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_ARMAACI is not set
-
-#
-# Open Sound System
-#
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+# CONFIG_SND_DRIVERS is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_ARMAACI=y
+# CONFIG_SND_SOC is not set
 # CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
 
 #
-# USB support
+# MMC/SD/SDIO Card Drivers
 #
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
 
 #
-# USB Gadget Support
+# MMC/SD/SDIO Host Controller Drivers
 #
-# CONFIG_USB_GADGET is not set
+CONFIG_MMC_ARMMMCI=y
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
 
 #
-# MMC/SD Card support
+# Voltage and Current regulators
 #
-# CONFIG_MMC is not set
+# 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
 
 #
 # File systems
 #
 # CONFIG_EXT2_FS is not set
 # CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+# CONFIG_EXT4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_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_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_FUSE_FS is not set
@@ -654,51 +801,59 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
 #
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_HFSPLUS_FS is not set
-# CONFIG_JFFS_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 is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
+CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFSD 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_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
 CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
@@ -739,26 +894,71 @@ CONFIG_NLS_ISO8859_1=y
 # 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_DEBUG_KERNEL=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
 # CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
 # CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES 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_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# 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_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+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_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
 CONFIG_DEBUG_USER=y
 CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_DEBUG_LL is not set
 
 #
@@ -766,21 +966,106 @@ CONFIG_DEBUG_ERRORS=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# 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_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 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
 
 #
-# Cryptographic options
+# Compression
 #
-# CONFIG_CRYPTO is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
 
 #
-# Hardware crypto devices
+# Random Number Generation
 #
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
 
 #
 # Library routines
 #
+CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/s3c6400_defconfig b/arch/arm/configs/s3c6400_defconfig
new file mode 100644 (file)
index 0000000..cf3c1b5
--- /dev/null
@@ -0,0 +1,845 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc3
+# Mon Nov  3 10:10:30 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+CONFIG_MMU=y
+CONFIG_NO_IOPORT=y
+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_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 is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# 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=y
+# CONFIG_UTS_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=y
+# 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_AIO=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 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_CLK=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 is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+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
+# CONFIG_FREEZER 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_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_S3C64XX=y
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+CONFIG_PLAT_S3C64XX=y
+CONFIG_CPU_S3C6400_INIT=y
+CONFIG_CPU_S3C6400_CLOCK=y
+CONFIG_S3C64XX_SETUP_I2C0=y
+CONFIG_S3C64XX_SETUP_I2C1=y
+CONFIG_PLAT_S3C=y
+
+#
+# Boot options
+#
+CONFIG_S3C_BOOT_ERROR_RESET=y
+
+#
+# Power management
+#
+CONFIG_S3C_LOWLEVEL_UART_PORT=0
+CONFIG_S3C_GPIO_SPACE=0
+CONFIG_S3C_GPIO_TRACK=y
+CONFIG_S3C_GPIO_PULL_UPDOWN=y
+CONFIG_S3C_GPIO_CFG_S3C24XX=y
+CONFIG_S3C_GPIO_CFG_S3C64XX=y
+CONFIG_S3C_DEV_HSMMC=y
+CONFIG_S3C_DEV_HSMMC1=y
+CONFIG_S3C_DEV_I2C1=y
+CONFIG_CPU_S3C6410=y
+CONFIG_S3C6410_SETUP_SDHCI=y
+CONFIG_MACH_SMDK6410=y
+CONFIG_SMDK6410_SD_CH0=y
+# CONFIG_SMDK6410_SD_CH1 is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+CONFIG_CPU_32v6K=y
+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
+CONFIG_ARM_VIC=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="console=ttySAC0,115200 root=/dev/ram init=/bin/bash initrd=0x51000000,4M"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# 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=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_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_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_ELANTECH is not set
+# 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 is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_CONSOLE is not set
+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_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_UARTS=4
+# CONFIG_SERIAL_SAMSUNG_DEBUG is not set
+CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_SERIAL_S3C6400=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_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_S3C2410=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=y
+# 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_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY 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_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_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_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_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_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_S3C=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY 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
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_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
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# 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=y
+# 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=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_PI_LIST=y
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# 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_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_S3C_PORT=y
+CONFIG_DEBUG_S3C_UART=0
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF 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_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/w90p910_defconfig b/arch/arm/configs/w90p910_defconfig
new file mode 100644 (file)
index 0000000..56bda7c
--- /dev/null
@@ -0,0 +1,626 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc8-git8
+# Sat Nov 15 10:05:00 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_GENERIC_GPIO is not set
+# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+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 is not set
+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=17
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+CONFIG_USER_NS=y
+# 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_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_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 is not set
+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 is not set
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_LSF=y
+CONFIG_BLK_DEV_BSG=y
+# 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 is not set
+# CONFIG_ARCH_MSM7X00A is not set
+CONFIG_ARCH_W90X900=y
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+CONFIG_CPU_W90P910=y
+
+#
+# W90P910 Machines
+#
+CONFIG_MACH_W90P910EVB=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_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=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CMDLINE="root=/dev/ram0 console=ttyS0,115200n8 initrd=0xa00000,4000000 mem=64M"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# 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
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# 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=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD 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 is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# 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_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_W90X900=y
+# CONFIG_SERIAL_W90X900_PORT1 is not set
+# CONFIG_SERIAL_W90X900_PORT2 is not set
+# CONFIG_SERIAL_W90X900_PORT3 is not set
+# CONFIG_SERIAL_W90X900_PORT4 is not set
+CONFIG_SERIAL_W90X900_CONSOLE=y
+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 is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 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
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_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
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS 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=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# 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_OMFS_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
+
+#
+# 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 is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE 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 is not set
+
+#
+# Library routines
+#
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+# CONFIG_CRC32 is not set
+# 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
index de6c59f814a1f4511457d548dc268702a3a1b94c..6cbd8fdc9f1fee5e83ffbe50fc125242503f0bae 100644 (file)
 #ifndef _ASMARM_CACHEFLUSH_H
 #define _ASMARM_CACHEFLUSH_H
 
-#include <linux/sched.h>
 #include <linux/mm.h>
 
 #include <asm/glue.h>
 #include <asm/shmparam.h>
+#include <asm/cachetype.h>
 
 #define CACHE_COLOUR(vaddr)    ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
 
@@ -295,16 +295,6 @@ static inline void outer_flush_range(unsigned long start, unsigned long end)
 
 #endif
 
-/*
- * flush_cache_vmap() is used when creating mappings (eg, via vmap,
- * vmalloc, ioremap etc) in kernel space for pages.  Since the
- * direct-mappings of these pages may contain cached data, we need
- * to do a full cache flush to ensure that writebacks don't corrupt
- * data placed into these pages via the new mappings.
- */
-#define flush_cache_vmap(start, end)           flush_cache_all()
-#define flush_cache_vunmap(start, end)         flush_cache_all()
-
 /*
  * Copy user data from/to a page which is mapped into a different
  * processes address space.  Really, we want to allow our "user
@@ -444,4 +434,29 @@ static inline void flush_ioremap_region(unsigned long phys, void __iomem *virt,
        dmac_inv_range(start, start + size);
 }
 
+/*
+ * flush_cache_vmap() is used when creating mappings (eg, via vmap,
+ * vmalloc, ioremap etc) in kernel space for pages.  On non-VIPT
+ * caches, since the direct-mappings of these pages may contain cached
+ * data, we need to do a full cache flush to ensure that writebacks
+ * don't corrupt data placed into these pages via the new mappings.
+ */
+static inline void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+       if (!cache_is_vipt_nonaliasing())
+               flush_cache_all();
+       else
+               /*
+                * set_pte_at() called from vmap_pte_range() does not
+                * have a DSB after cleaning the cache line.
+                */
+               dsb();
+}
+
+static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
+{
+       if (!cache_is_vipt_nonaliasing())
+               flush_cache_all();
+}
+
 #endif
diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h
new file mode 100644 (file)
index 0000000..b6ec7c6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  arch/arm/include/asm/clkdev.h
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#ifndef __ASM_CLKDEV_H
+#define __ASM_CLKDEV_H
+
+struct clk;
+
+struct clk_lookup {
+       struct list_head        node;
+       const char              *dev_id;
+       const char              *con_id;
+       struct clk              *clk;
+};
+
+struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
+       const char *dev_fmt, ...);
+
+void clkdev_add(struct clk_lookup *cl);
+void clkdev_drop(struct clk_lookup *cl);
+
+#endif
index 4ed149cbb32a401c26a6d91f062aa25151d994bf..22cb14ec3438e9d74b1fa8f626bb65945c2d4607 100644 (file)
@@ -69,7 +69,9 @@ extern void dma_cache_maint(const void *kaddr, size_t size, int rw);
  */
 static inline int dma_supported(struct device *dev, u64 mask)
 {
-       return dev->dma_mask && *dev->dma_mask != 0;
+       if (mask < ISA_DMA_THRESHOLD)
+               return 0;
+       return 1;
 }
 
 static inline int dma_set_mask(struct device *dev, u64 dma_mask)
index 75154b1931173adc897597c228e21972594583d8..df5638f3643aea42d72d0a04d20284ca36995c70 100644 (file)
@@ -1,12 +1,7 @@
 #ifndef __ASM_ARM_DMA_H
 #define __ASM_ARM_DMA_H
 
-typedef unsigned int dmach_t;
-
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/scatterlist.h>
-#include <mach/dma.h>
+#include <asm/memory.h>
 
 /*
  * This is the maximum virtual address which can be DMA'd from.
@@ -15,6 +10,19 @@ typedef unsigned int dmach_t;
 #define MAX_DMA_ADDRESS        0xffffffff
 #endif
 
+#ifdef CONFIG_ISA_DMA_API
+/*
+ * This is used to support drivers written for the x86 ISA DMA API.
+ * It should not be re-used except for that purpose.
+ */
+#include <linux/spinlock.h>
+#include <asm/system.h>
+#include <asm/scatterlist.h>
+
+typedef unsigned int dmach_t;
+
+#include <mach/isa-dma.h>
+
 /*
  * DMA modes
  */
@@ -140,4 +148,6 @@ extern int isa_dma_bridge_buggy;
 #define isa_dma_bridge_buggy    (0)
 #endif
 
-#endif /* _ARM_DMA_H */
+#endif /* CONFIG_ISA_DMA_API */
+
+#endif /* __ASM_ARM_DMA_H */
index 9c5afbd71a69a4bbdaf6e8d8c806e07f3f199db1..f9ee69e4f53ecfccde11f5bfd609d253570542a5 100644 (file)
 #define IOMD_KARTRX    (0x004)
 #define IOMD_KCTRL     (0x008)
 
-#ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_IOLINES   (0x00C)
-#endif
-
 #define IOMD_IRQSTATA  (0x010)
 #define IOMD_IRQREQA   (0x014)
 #define IOMD_IRQCLRA   (0x014)
 #define IOMD_IRQMASKA  (0x018)
 
-#ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_SUSMODE   (0x01C)
-#endif
-
 #define IOMD_IRQSTATB  (0x020)
 #define IOMD_IRQREQB   (0x024)
 #define IOMD_IRQMASKB  (0x028)
 #define IOMD_FIQREQ    (0x034)
 #define IOMD_FIQMASK   (0x038)
 
-#ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_CLKCTL    (0x03C)
-#endif
-
 #define IOMD_T0CNTL    (0x040)
 #define IOMD_T0LTCHL   (0x040)
 #define IOMD_T0CNTH    (0x044)
 #define IOMD_T1GO      (0x058)
 #define IOMD_T1LATCH   (0x05c)
 
-#ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_IRQSTATC  (0x060)
-#define IOMD_IRQREQC   (0x064)
-#define IOMD_IRQMASKC  (0x068)
-
-#define IOMD_VIDMUX    (0x06c)
-
-#define IOMD_IRQSTATD  (0x070)
-#define IOMD_IRQREQD   (0x074)
-#define IOMD_IRQMASKD  (0x078)
-#endif
-
 #define IOMD_ROMCR0    (0x080)
 #define IOMD_ROMCR1    (0x084)
 #ifdef CONFIG_ARCH_RPC
 #define IOMD_MOUSEY    (0x0A4)
 #endif
 
-#ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_MSEDAT    (0x0A8)
-#define IOMD_MSECTL    (0x0Ac)
-#endif
-
 #ifdef CONFIG_ARCH_RPC
 #define IOMD_DMATCR    (0x0C0)
 #endif
 #ifdef CONFIG_ARCH_RPC
 #define IOMD_DMAEXT    (0x0CC)
 #endif
-#ifdef CONFIG_ARCH_CLPS7500
-#define IOMD_ASTCR     (0x0CC)
-#define IOMD_DRAMCR    (0x0D0)
-#define IOMD_SELFREF   (0x0D4)
-#define IOMD_ATODICR   (0x0E0)
-#define IOMD_ATODSR    (0x0E4)
-#define IOMD_ATODCC    (0x0E8)
-#define IOMD_ATODCNT1  (0x0EC)
-#define IOMD_ATODCNT2  (0x0F0)
-#define IOMD_ATODCNT3  (0x0F4)
-#define IOMD_ATODCNT4  (0x0F8)
-#endif
 
 #ifdef CONFIG_ARCH_RPC
 #define DMA_EXT_IO0    1
index 263f2c362a306166e92812963b42c10992d79fb1..f87328d4a180e284d99b061de2fb9697719efebe 100644 (file)
 #define VIC_INT_SOFT                   0x18
 #define VIC_INT_SOFT_CLEAR             0x1c
 #define VIC_PROTECT                    0x20
-#define VIC_VECT_ADDR                  0x30
-#define VIC_DEF_VECT_ADDR              0x34
+#define VIC_PL190_VECT_ADDR            0x30    /* PL190 only */
+#define VIC_PL190_DEF_VECT_ADDR                0x34    /* PL190 only */
 
-#define VIC_VECT_ADDR0                 0x100   /* 0 to 15 */
-#define VIC_VECT_CNTL0                 0x200   /* 0 to 15 */
+#define VIC_VECT_ADDR0                 0x100   /* 0 to 15 (0..31 PL192) */
+#define VIC_VECT_CNTL0                 0x200   /* 0 to 15 (0..31 PL192) */
 #define VIC_ITCR                       0x300   /* VIC test control register */
 
 #define VIC_VECT_CNTL_ENABLE           (1 << 5)
 
+#define VIC_PL192_VECT_ADDR            0xF00
+
 #ifndef __ASSEMBLY__
 void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources);
 #endif
index 81f4c899a555b5949df821f313af262ba5303c49..bda489f9f01739c4543ca9c2f99b1ede6a739a9f 100644 (file)
@@ -16,6 +16,7 @@
 #define HWCAP_IWMMXT   512
 #define HWCAP_CRUNCH   1024
 #define HWCAP_THUMBEE  2048
+#define HWCAP_NEON     4096
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 /*
index a8094451be57285cca1b802e93860b0c9c860774..d2a59cfc30ce3f790ccc3b01a781f4fdf75c8baf 100644 (file)
@@ -79,6 +79,14 @@ extern void __iounmap(volatile void __iomem *addr);
  */
 extern void __readwrite_bug(const char *fn);
 
+/*
+ * A typesafe __io() helper
+ */
+static inline void __iomem *__typesafe_io(unsigned long addr)
+{
+       return (void __iomem *)addr;
+}
+
 /*
  * Now, pick up the machine-defined IO definitions
  */
index a0009aa5d157686f151bbc726ae59da1ddafd4e0..328f14a8b79034a3d71e713780a0d8caed9279d6 100644 (file)
@@ -7,10 +7,6 @@
 #define irq_canonicalize(i)    (i)
 #endif
 
-#ifndef NR_IRQS
-#define NR_IRQS        128
-#endif
-
 /*
  * Use this value to indicate lack of interrupt
  * capability
index 77764301844b52946996f4a3287185c0fc349e05..0202a7c20e629fb7be94f58b9705e5268db6554e 100644 (file)
  * private definitions which should NOT be used outside memory.h
  * files.  Use virt_to_phys/phys_to_virt/__pa/__va instead.
  */
-#ifndef __virt_to_phys
 #define __virt_to_phys(x)      ((x) - PAGE_OFFSET + PHYS_OFFSET)
 #define __phys_to_virt(x)      ((x) - PHYS_OFFSET + PAGE_OFFSET)
-#endif
 
 /*
  * Convert a physical address to a Page Frame Number and back
@@ -180,6 +178,11 @@ static inline void *phys_to_virt(unsigned long x)
  * memory.  Use of these is *deprecated* (and that doesn't mean
  * use the __ prefixed forms instead.)  See dma-mapping.h.
  */
+#ifndef __virt_to_bus
+#define __virt_to_bus  __virt_to_phys
+#define __bus_to_virt  __phys_to_virt
+#endif
+
 static inline __deprecated unsigned long virt_to_bus(void *x)
 {
        return __virt_to_bus((unsigned long)x);
index 0559f37c2a27c09d11a378b2c8a2527ad2895d71..263fed05ea33d92ac281a58f681eb9310c3a4c50 100644 (file)
@@ -14,6 +14,7 @@
 #define __ASM_ARM_MMU_CONTEXT_H
 
 #include <linux/compiler.h>
+#include <linux/sched.h>
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/proc-fns.h>
index d8fbe2d9b8b9b3621bbe910b56ccde369123f73f..d79d66d2cf715ffa4f25b7c3f0b06ced68db6cff 100644 (file)
@@ -15,7 +15,6 @@
 #ifndef __ARM_MTD_XIP_H__
 #define __ARM_MTD_XIP_H__
 
-#include <mach/hardware.h>
 #include <mach/mtd-xip.h>
 
 /* fill instruction prefetch */
index bed1c0a0036865c40aab88e95b8500e701e940ce..f341c9dbd662a113cac8b595e466fa63268dfdf2 100644 (file)
 #error Unknown user operations model
 #endif
 
+struct page;
+
 struct cpu_user_fns {
-       void (*cpu_clear_user_page)(void *p, unsigned long user);
-       void (*cpu_copy_user_page)(void *to, const void *from,
-                                  unsigned long user);
+       void (*cpu_clear_user_highpage)(struct page *page, unsigned long vaddr);
+       void (*cpu_copy_user_highpage)(struct page *to, struct page *from,
+                       unsigned long vaddr);
 };
 
 #ifdef MULTI_USER
 extern struct cpu_user_fns cpu_user;
 
-#define __cpu_clear_user_page  cpu_user.cpu_clear_user_page
-#define __cpu_copy_user_page   cpu_user.cpu_copy_user_page
+#define __cpu_clear_user_highpage      cpu_user.cpu_clear_user_highpage
+#define __cpu_copy_user_highpage       cpu_user.cpu_copy_user_highpage
 
 #else
 
-#define __cpu_clear_user_page  __glue(_USER,_clear_user_page)
-#define __cpu_copy_user_page   __glue(_USER,_copy_user_page)
+#define __cpu_clear_user_highpage      __glue(_USER,_clear_user_highpage)
+#define __cpu_copy_user_highpage       __glue(_USER,_copy_user_highpage)
 
-extern void __cpu_clear_user_page(void *p, unsigned long user);
-extern void __cpu_copy_user_page(void *to, const void *from,
-                                unsigned long user);
+extern void __cpu_clear_user_highpage(struct page *page, unsigned long vaddr);
+extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
+                       unsigned long vaddr);
 #endif
 
-#define clear_user_page(addr,vaddr,pg)  __cpu_clear_user_page(addr, vaddr)
-#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
+#define clear_user_highpage(page,vaddr)                \
+        __cpu_clear_user_highpage(page, vaddr)
+
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+#define copy_user_highpage(to,from,vaddr,vma)  \
+       __cpu_copy_user_highpage(to, from, vaddr)
 
-#define clear_page(page)       memzero((void *)(page), PAGE_SIZE)
+#define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
 
 #undef STRICT_MM_TYPECHECKS
index 6ff33790f47b16d91054c4907edb09616a21f5d8..1845892260e762fad61c6f093529bdd5ab7a920f 100644 (file)
@@ -64,7 +64,7 @@ struct thread_struct {
 ({                                                                     \
        unsigned long *stack = (unsigned long *)sp;                     \
        set_fs(USER_DS);                                                \
-       memzero(regs->uregs, sizeof(regs->uregs));                      \
+       memset(regs->uregs, 0, sizeof(regs->uregs));                    \
        if (current->personality & ADDR_LIMIT_32BIT)                    \
                regs->ARM_cpsr = USR_MODE;                              \
        else                                                            \
index a65413ba121de131eca860b555cab65071b83a61..f2cd18a0932b786d0283d371ab9172f91db40fe1 100644 (file)
@@ -209,9 +209,11 @@ struct meminfo {
        struct membank bank[NR_BANKS];
 };
 
+extern struct meminfo meminfo;
+
 #define for_each_nodebank(iter,mi,no)                  \
-       for (iter = 0; iter < mi->nr_banks; iter++)     \
-               if (mi->bank[iter].node == no)
+       for (iter = 0; iter < (mi)->nr_banks; iter++)   \
+               if ((mi)->bank[iter].node == no)
 
 #define bank_pfn_start(bank)   __phys_to_pfn((bank)->start)
 #define bank_pfn_end(bank)     __phys_to_pfn((bank)->start + (bank)->size)
index 727b5c042e522c9053873501803946a95433838b..fad70da5911df7ad0283e330703b4584172048e4 100644 (file)
@@ -114,7 +114,7 @@ extern void local_timer_interrupt(void);
 /*
  * Stop a local timer interrupt.
  */
-extern void local_timer_stop(unsigned int cpu);
+extern void local_timer_stop(void);
 
 /*
  * Platform provides this to acknowledge a local timer IRQ
@@ -123,7 +123,7 @@ extern int local_timer_ack(void);
 
 #else
 
-static inline void local_timer_stop(unsigned int cpu)
+static inline void local_timer_stop(void)
 {
 }
 
@@ -132,7 +132,7 @@ static inline void local_timer_stop(unsigned int cpu)
 /*
  * Setup a local timer interrupt for a CPU.
  */
-extern void local_timer_setup(unsigned int cpu);
+extern void local_timer_setup(void);
 
 /*
  * show local interrupt info
index e50c4a39b699779f9af151397eeeb022ff2da0f5..cf4f3aad0fc1c2154c6cf3839ff21bb1c46d6499 100644 (file)
@@ -21,7 +21,6 @@ extern void * memmove(void *, const void *, __kernel_size_t);
 #define __HAVE_ARCH_MEMCHR
 extern void * memchr(const void *, int, __kernel_size_t);
 
-#define __HAVE_ARCH_MEMZERO
 #define __HAVE_ARCH_MEMSET
 extern void * memset(void *, int, __kernel_size_t);
 
@@ -39,12 +38,4 @@ extern void __memzero(void *ptr, __kernel_size_t n);
                (__p);                                                  \
        })
 
-#define memzero(p,n)                                                   \
-       ({                                                              \
-               void *__p = (p); size_t __n = n;                        \
-               if ((__n) != 0)                                         \
-                       __memzero((__p),(__n));                         \
-               (__p);                                                  \
-        })
-
 #endif
index 568020b34e3e9b1c5883afb935228d2d53d58a40..811be55f338e947ba362c8c932d2cf76d0dffd5e 100644 (file)
@@ -3,8 +3,6 @@
 
 #ifdef __KERNEL__
 
-#include <asm/memory.h>
-
 #define CPU_ARCH_UNKNOWN       0
 #define CPU_ARCH_ARMv3         1
 #define CPU_ARCH_ARMv4         2
index e98ec60b34002b4f2457982c8312600efd7216be..7897464e0c24260fe002e0ffac839444c35d5079 100644 (file)
@@ -11,7 +11,8 @@
 /*
  * User space memory access functions
  */
-#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/thread_info.h>
 #include <asm/errno.h>
 #include <asm/memory.h>
 #include <asm/domain.h>
@@ -400,7 +401,7 @@ static inline unsigned long __must_check copy_from_user(void *to, const void __u
        if (access_ok(VERIFY_READ, from, n))
                n = __copy_from_user(to, from, n);
        else /* security hole - plug it */
-               memzero(to, n);
+               memset(to, 0, n);
        return n;
 }
 
index 23af3c972c9a7d202c0a71a340e29067d4ac8d74..531e1860e546dbf5e5a13016a16cf30aea061c96 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/cryptohash.h>
 #include <linux/delay.h>
index 6c90479e897487dc033de1db6b61ad80377050ca..c638427662291c2fbd28d259b6121286d245d1d3 100644 (file)
@@ -95,7 +95,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        return ret;
 }
 
-/* run from kstop_machine */
+/* run from ftrace_init with irqs disabled */
 int __init ftrace_dyn_arch_init(void *data)
 {
        ftrace_mcount_set(data);
index bde52df1c668e994c3d8c4d6c53ff01f01cacad3..991952c644d1e597afba81c82eb5337ea4c9182b 100644 (file)
@@ -18,7 +18,7 @@
 __switch_data:
        .long   __mmap_switched
        .long   __data_loc                      @ r4
-       .long   __data_start                    @ r5
+       .long   _data                           @ r5
        .long   __bss_start                     @ r6
        .long   _end                            @ r7
        .long   processor_id                    @ r4
index b8d965dcd6fdbfaec4172dc541030e15b5b653c9..dab48f27263f0e20c2e3bdbaf2f1c5ffaf1a1c1f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 
 #include <asm/pgtable.h>
+#include <asm/sections.h>
 
 #ifdef CONFIG_XIP_KERNEL
 /*
@@ -29,9 +30,8 @@
  * MODULES_VADDR is redefined here and not in asm/memory.h to avoid
  * recompiling the whole kernel when CONFIG_XIP_KERNEL is turned on/off.
  */
-extern void _etext;
 #undef MODULES_VADDR
-#define MODULES_VADDR  (((unsigned long)&_etext + ~PGDIR_MASK) & PGDIR_MASK)
+#define MODULES_VADDR  (((unsigned long)_etext + ~PGDIR_MASK) & PGDIR_MASK)
 #endif
 
 #ifdef CONFIG_MMU
index 1f1eecca7f55a4ef2ff3b502c360309da00d3010..7049815d66d566e7d89c08fd3c25e33b8c48c995 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/cputype.h>
 #include <asm/elf.h>
 #include <asm/procinfo.h>
+#include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/cacheflush.h>
@@ -59,9 +60,8 @@ static int __init fpe_setup(char *line)
 __setup("fpe=", fpe_setup);
 #endif
 
-extern void paging_init(struct meminfo *, struct machine_desc *desc);
+extern void paging_init(struct machine_desc *desc);
 extern void reboot_setup(char *str);
-extern void _text, _etext, __data_start, _edata, _end;
 
 unsigned int processor_id;
 EXPORT_SYMBOL(processor_id);
@@ -112,7 +112,6 @@ static struct stack stacks[NR_CPUS];
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
 
-static struct meminfo meminfo __initdata = { 0, };
 static const char *cpu_name;
 static const char *machine_name;
 static char __initdata command_line[COMMAND_LINE_SIZE];
@@ -367,21 +366,34 @@ static struct machine_desc * __init setup_machine(unsigned int nr)
        return list;
 }
 
-static void __init arm_add_memory(unsigned long start, unsigned long size)
+static int __init arm_add_memory(unsigned long start, unsigned long size)
 {
-       struct membank *bank;
+       struct membank *bank = &meminfo.bank[meminfo.nr_banks];
+
+       if (meminfo.nr_banks >= NR_BANKS) {
+               printk(KERN_CRIT "NR_BANKS too low, "
+                       "ignoring memory at %#lx\n", start);
+               return -EINVAL;
+       }
 
        /*
         * Ensure that start/size are aligned to a page boundary.
         * Size is appropriately rounded down, start is rounded up.
         */
        size -= start & ~PAGE_MASK;
-
-       bank = &meminfo.bank[meminfo.nr_banks++];
-
        bank->start = PAGE_ALIGN(start);
        bank->size  = size & PAGE_MASK;
        bank->node  = PHYS_TO_NID(start);
+
+       /*
+        * Check whether this memory region has non-zero size or
+        * invalid node number.
+        */
+       if (bank->size == 0 || bank->node >= MAX_NUMNODES)
+               return -EINVAL;
+
+       meminfo.nr_banks++;
+       return 0;
 }
 
 /*
@@ -472,10 +484,10 @@ request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
        struct resource *res;
        int i;
 
-       kernel_code.start   = virt_to_phys(&_text);
-       kernel_code.end     = virt_to_phys(&_etext - 1);
-       kernel_data.start   = virt_to_phys(&__data_start);
-       kernel_data.end     = virt_to_phys(&_end - 1);
+       kernel_code.start   = virt_to_phys(_text);
+       kernel_code.end     = virt_to_phys(_etext - 1);
+       kernel_data.start   = virt_to_phys(_data);
+       kernel_data.end     = virt_to_phys(_end - 1);
 
        for (i = 0; i < mi->nr_banks; i++) {
                if (mi->bank[i].size == 0)
@@ -539,14 +551,7 @@ __tagtable(ATAG_CORE, parse_tag_core);
 
 static int __init parse_tag_mem32(const struct tag *tag)
 {
-       if (meminfo.nr_banks >= NR_BANKS) {
-               printk(KERN_WARNING
-                      "Ignoring memory bank 0x%08x size %dKB\n",
-                       tag->u.mem.start, tag->u.mem.size / 1024);
-               return -EINVAL;
-       }
-       arm_add_memory(tag->u.mem.start, tag->u.mem.size);
-       return 0;
+       return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
 }
 
 __tagtable(ATAG_MEM, parse_tag_mem32);
@@ -710,15 +715,15 @@ void __init setup_arch(char **cmdline_p)
                parse_tags(tags);
        }
 
-       init_mm.start_code = (unsigned long) &_text;
-       init_mm.end_code   = (unsigned long) &_etext;
-       init_mm.end_data   = (unsigned long) &_edata;
-       init_mm.brk        = (unsigned long) &_end;
+       init_mm.start_code = (unsigned long) _text;
+       init_mm.end_code   = (unsigned long) _etext;
+       init_mm.end_data   = (unsigned long) _edata;
+       init_mm.brk        = (unsigned long) _end;
 
        memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
        boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
        parse_cmdline(cmdline_p, from);
-       paging_init(&meminfo, mdesc);
+       paging_init(mdesc);
        request_standard_resources(&meminfo, mdesc);
 
 #ifdef CONFIG_SMP
@@ -772,6 +777,8 @@ static const char *hwcap_str[] = {
        "java",
        "iwmmxt",
        "crunch",
+       "thumbee",
+       "neon",
        NULL
 };
 
index e42a749a56dd5c85abc823e2666ff7b4683c2da0..019237d21622ba2cde3669d4915dca02a590ea26 100644 (file)
@@ -181,7 +181,7 @@ int __cpuexit __cpu_disable(void)
        /*
         * Stop the local timer for this CPU.
         */
-       local_timer_stop(cpu);
+       local_timer_stop();
 
        /*
         * Flush user cache and TLB mappings, and then remove this CPU
@@ -284,7 +284,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
        /*
         * Setup local timer for this CPU.
         */
-       local_timer_setup(cpu);
+       local_timer_setup();
 
        calibrate_delay();
 
index df3f6b7ebcea17238f7c80e8c4a4381915691d13..9cb7aaca159fa6aa714b29367871a24beb988c07 100644 (file)
@@ -25,7 +25,7 @@
 /*
  * Access to the ThumbEE Handler Base register
  */
-static inline unsigned long teehbr_read()
+static inline unsigned long teehbr_read(void)
 {
        unsigned long v;
        asm("mrc        p14, 6, %0, c1, c0, 0\n" : "=r" (v));
index 4898bdcfe7dd638b5c4d9962f3932244a1249a38..00216071eaf72d2bf87ddccbfe4f6a95e4ce2d4f 100644 (file)
@@ -119,7 +119,7 @@ SECTIONS
 #endif
 
        .data : AT(__data_loc) {
-               __data_start = .;       /* address in memory */
+               _data = .;              /* address in memory */
 
                /*
                 * first, the init task union, aligned
index 30351cd4560dfcc7052a8be4eaa84620643878a3..866f84a586ff7281b7aa70ab9af4a89d80a88079 100644 (file)
@@ -38,7 +38,6 @@ else
 endif
 
 lib-$(CONFIG_ARCH_RPC)         += ecard.o io-acorn.o floppydma.o
-lib-$(CONFIG_ARCH_CLPS7500)    += io-acorn.o
 lib-$(CONFIG_ARCH_L7200)       += io-acorn.o
 lib-$(CONFIG_ARCH_SHARK)       += io-shark.o
 
index 761eefa762437de156387da70fbe006004c950cb..650d5923ab83cd849c38db3a64c55fccf36a631a 100644 (file)
@@ -25,7 +25,7 @@
        add     r2, r2, r3              @ 1 (r2 = r2 - (4 - r3))
 /*
  * The pointer is now aligned and the length is adjusted.  Try doing the
- * memzero again.
+ * memset again.
  */
 
 ENTRY(memset)
index a8e462f58bc9c4087cd064a7560377b85d8d938d..20ec83896c375992bfcae3c00c6b3952ae975643 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support (must be linked before board specific support)
-obj-y += core.o clock.o
+obj-y += core.o
 
 # Specific board support
 obj-$(CONFIG_MACH_AAED2000) += aaed2000.o
diff --git a/arch/arm/mach-aaec2000/clock.c b/arch/arm/mach-aaec2000/clock.c
deleted file mode 100644 (file)
index e10ee15..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *  linux/arch/arm/mach-aaec2000/clock.c
- *
- *  Copyright (C) 2005 Nicolas Bellido Y Ortega
- *
- *  Based on linux/arch/arm/mach-integrator/clock.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/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-
-#include "clock.h"
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-       mutex_unlock(&clocks_mutex);
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-       module_put(clk->owner);
-}
-EXPORT_SYMBOL(clk_put);
-
-int clk_enable(struct clk *clk)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       return clk->rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       return rate;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_register(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_del(&clk->node);
-       mutex_unlock(&clocks_mutex);
-}
-EXPORT_SYMBOL(clk_unregister);
-
-static int __init clk_init(void)
-{
-       return 0;
-}
-arch_initcall(clk_init);
diff --git a/arch/arm/mach-aaec2000/clock.h b/arch/arm/mach-aaec2000/clock.h
deleted file mode 100644 (file)
index d4bb74f..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- *  linux/arch/arm/mach-aaec2000/clock.h
- *
- *  Copyright (C) 2005 Nicolas Bellido Y Ortega
- *
- *  Based on linux/arch/arm/mach-integrator/clock.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-struct module;
-
-struct clk {
-       struct list_head        node;
-       unsigned long           rate;
-       struct module           *owner;
-       const char              *name;
-       void                    *data;
-};
-
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
index dfb26bc23d1a8838d8a8fd8a5a5bd37079f45051..50e13965dfed159e3f4b0009b60c29353e31ceef 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/signal.h>
+#include <linux/clk.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -30,7 +31,6 @@
 #include <asm/mach/map.h>
 
 #include "core.h"
-#include "clock.h"
 
 /*
  * Common I/O mapping:
@@ -229,9 +229,28 @@ static struct amba_device *amba_devs[] __initdata = {
        &clcd_device,
 };
 
-static struct clk aaec2000_clcd_clk = {
-       .name = "CLCDCLK",
-};
+void clk_disable(struct clk *clk)
+{
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       return 0;
+}
+
+int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       return dev && strcmp(dev_name(dev), "mb:16") == 0 ? NULL : ERR_PTR(-ENOENT);
+}
+
+void clk_put(struct clk *clk)
+{
+}
 
 void __init aaec2000_set_clcd_plat_data(struct aaec2000_clcd_info *clcd)
 {
@@ -265,8 +284,6 @@ static int __init aaec2000_init(void)
 {
        int i;
 
-       clk_register(&aaec2000_clcd_clk);
-
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
diff --git a/arch/arm/mach-aaec2000/include/mach/dma.h b/arch/arm/mach-aaec2000/include/mach/dma.h
deleted file mode 100644 (file)
index 2da846c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- *  arch/arm/mach-aaec2000/include/mach/dma.h
- *
- *  Copyright (c) 2005 Nicolas Bellido Y Ortega
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
index c87c24de1110b1f1d33bf46234699fcba23aa14b..ab4fe5d20eaf2fbad0750fc59fbf25125826a284 100644 (file)
@@ -6,15 +6,13 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
 /*
  * We don't actually have real ISA nor PCI buses, but there is so many
  * drivers out there that might just work if we fake them...
  */
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 56ae900a482e28d1bd697bd030f316fc809c2a0a..c00822543d9f78a307c4a7c7f3c576db75c2efb4 100644 (file)
@@ -14,9 +14,6 @@
 
 #define PHYS_OFFSET    UL(0xf0000000)
 
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
 /*
  * The nodes are the followings:
  *
index 5aafb2e2ca7a538335957df1508009f5784f0230..323b47f2b52f20d7478eafa4a068940ba1c2bb91 100644 (file)
@@ -7,36 +7,43 @@ choice
 
 config ARCH_AT91RM9200
        bool "AT91RM9200"
+       select CPU_ARM920T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
 config ARCH_AT91SAM9260
        bool "AT91SAM9260 or AT91SAM9XE"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
 config ARCH_AT91SAM9261
        bool "AT91SAM9261"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
 config ARCH_AT91SAM9263
        bool "AT91SAM9263"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
 config ARCH_AT91SAM9RL
        bool "AT91SAM9RL"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
 config ARCH_AT91SAM9G20
        bool "AT91SAM9G20"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
 config ARCH_AT91CAP9
        bool "AT91CAP9"
+       select CPU_ARM926T
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
 
@@ -235,6 +242,12 @@ config MACH_USB_A9263
          Select this if you are using a Calao Systems USB-A9263.
          <http://www.calao-systems.com>
 
+config MACH_NEOCORE926
+       bool "Adeneo NEOCORE926"
+       depends on ARCH_AT91SAM9263
+       help
+         Select this if you are using the Adeneo Neocore 926 board.
+
 endif
 
 # ----------------------------------------------------------
@@ -302,7 +315,7 @@ comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
        bool "Enable DataFlash Card support"
-       depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_ECBAT91 || MACH_SAM9_L9260 || MACH_AT91CAP9ADK)
+       depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK || MACH_AT91SAM9G20EK || MACH_ECBAT91 || MACH_SAM9_L9260 || MACH_AT91CAP9ADK || MACH_NEOCORE926)
        help
          Enable support for the DataFlash card.
 
index cca612d97ca2f895321b61e1d0d6ce7a97462af5..c69ff237fd14878498eeb56e452fa55e6b8da9ec 100644 (file)
@@ -11,12 +11,12 @@ obj-$(CONFIG_AT91_PMC_UNIT) += clock.o
 
 # CPU-specific support
 obj-$(CONFIG_ARCH_AT91RM9200)  += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9RL)  += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o
-obj-$(CONFIG_ARCH_AT91CAP9)    += at91cap9.o at91sam926x_time.o at91cap9_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9RL)  += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o  sam9_smc.o
+obj-$(CONFIG_ARCH_AT91CAP9)    += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91X40)     += at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -47,6 +47,7 @@ obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
 # AT91SAM9263 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o
 obj-$(CONFIG_MACH_USB_A9263)   += board-usb-a9263.o
+obj-$(CONFIG_MACH_NEOCORE926)  += board-neocore926.o
 
 # AT91SAM9RL board-specific support
 obj-$(CONFIG_MACH_AT91SAM9RLEK)        += board-sam9rlek.o
index 0fc0adaebd583ed0718366f354fb970078d35c2d..0a38c69fdbc450f3d09ed7545ef60af14e45fb50 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+
+#include <mach/cpu.h>
 #include <mach/at91cap9.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
@@ -317,6 +319,12 @@ void __init at91cap9_initialize(unsigned long main_clock)
 
        /* Register GPIO subsystem */
        at91_gpio_init(at91cap9_gpio, 4);
+
+       /* Remember the silicon revision */
+       if (cpu_is_at91cap9_revB())
+               system_rev = 0xB;
+       else if (cpu_is_at91cap9_revC())
+               system_rev = 0xC;
 }
 
 /* --------------------------------------------------------------------
index 5ebd4273d353d5f71ac27b9d519c283c319d0874..9eca2209cde630dd656491ef5c964461f2c8b5b2 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/irq.h>
 
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -21,6 +22,7 @@
 #include <video/atmel_lcdc.h>
 
 #include <mach/board.h>
+#include <mach/cpu.h>
 #include <mach/gpio.h>
 #include <mach/at91cap9.h>
 #include <mach/at91cap9_matrix.h>
@@ -69,6 +71,9 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data)
        if (!data)
                return;
 
+       if (cpu_is_at91cap9_revB())
+               set_irq_type(AT91CAP9_ID_UHP, IRQ_TYPE_LEVEL_HIGH);
+
        /* Enable VBus control for UHP ports */
        for (i = 0; i < data->ports; i++) {
                if (data->vbus_pin[i])
@@ -151,8 +156,13 @@ static struct platform_device at91_usba_udc_device = {
 
 void __init at91_add_device_usba(struct usba_platform_data *data)
 {
-       at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS |
-                                         AT91_MATRIX_UDPHS_BYPASS_LOCK);
+       if (cpu_is_at91cap9_revB()) {
+               set_irq_type(AT91CAP9_ID_UDPHS, IRQ_TYPE_LEVEL_HIGH);
+               at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS |
+                                                 AT91_MATRIX_UDPHS_BYPASS_LOCK);
+       }
+       else
+               at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS);
 
        /*
         * Invalid pins are 0 on AT91, but the usba driver is shared
@@ -406,28 +416,13 @@ static struct platform_device at91cap9_nand_device = {
 
 void __init at91_add_device_nand(struct atmel_nand_data *data)
 {
-       unsigned long csa, mode;
+       unsigned long csa;
 
        if (!data)
                return;
 
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
-
-       /* set the bus interface characteristics */
-       at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(1)
-                       | AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(1));
-
-       at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(6)
-                       | AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(6));
-
-       at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(8) | AT91_SMC_NRDCYCLE_(8));
-
-       if (data->bus_width_16)
-               mode = AT91_SMC_DBW_16;
-       else
-               mode = AT91_SMC_DBW_8;
-       at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(1));
+       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
 
        /* enable pin */
        if (data->enable_pin)
@@ -865,6 +860,9 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
        if (!data)
                return;
 
+       if (cpu_is_at91cap9_revB())
+               set_irq_type(AT91CAP9_ID_LCDC, IRQ_TYPE_LEVEL_HIGH);
+
        at91_set_A_periph(AT91_PIN_PC1, 0);     /* LCDHSYNC */
        at91_set_A_periph(AT91_PIN_PC2, 0);     /* LCDDOTCK */
        at91_set_A_periph(AT91_PIN_PC3, 0);     /* LCDDEN */
index a72e798a2a40eede144f22d85eb5204f0114ea18..d140eae53ded281bcc9f33fc6b991b1086c5fd55 100644 (file)
@@ -141,6 +141,15 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
        /* Use "raw" primitives so we behave correctly on RT kernels. */
        raw_local_irq_save(flags);
 
+       /*
+        * According to Thomas Gleixner irqs are already disabled here.  Simply
+        * removing raw_local_irq_save above (and the matching
+        * raw_local_irq_restore) was not accepted.  See
+        * http://thread.gmane.org/gmane.linux.ports.arm.kernel/41174
+        * So for now (2008-11-20) just warn once if irqs were not disabled ...
+        */
+       WARN_ON_ONCE(!raw_irqs_disabled_flags(flags));
+
        /* The alarm IRQ uses absolute time (now+delta), not the relative
         * time (delta) in our calling convention.  Like all clockevents
         * using such "match" hardware, we have a race to defend against.
index 7774d17dde74352f425a085e9071ea5ff025b44d..fdde1ea21b0729738ade6357b728a634ff505fc6 100644 (file)
@@ -313,7 +313,7 @@ static struct platform_device at91sam9260_nand_device = {
 
 void __init at91_add_device_nand(struct atmel_nand_data *data)
 {
-       unsigned long csa, mode;
+       unsigned long csa;
 
        if (!data)
                return;
@@ -321,42 +321,6 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
        at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
-       if (cpu_is_at91sam9260()) {
-               /* Timing for sam9260 */
-               /* set the bus interface characteristics */
-               at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(1) | AT91_SMC_NCS_WRSETUP_(0)
-                               | AT91_SMC_NRDSETUP_(1) | AT91_SMC_NCS_RDSETUP_(0));
-
-               at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3)
-                               | AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
-
-               at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
-
-               if (data->bus_width_16)
-                       mode = AT91_SMC_DBW_16;
-               else
-                       mode = AT91_SMC_DBW_8;
-               at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2));
-       }
-
-       if (cpu_is_at91sam9g20()) {
-               /* Timing for sam9g20 */
-               /* set the bus interface characteristics */
-               at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(0)
-                               | AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(0));
-
-               at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(4)
-                               | AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(4));
-
-               at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(7) | AT91_SMC_NRDCYCLE_(7));
-
-               if (data->bus_width_16)
-                       mode = AT91_SMC_DBW_16;
-               else
-                       mode = AT91_SMC_DBW_8;
-               at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(3));
-       }
-
        /* enable pin */
        if (data->enable_pin)
                at91_set_gpio_output(data->enable_pin, 1);
index 6b89172310c7f566ddbbccb802aeb48315d02df9..17289756f80ffe8c5eb6d34bd561ea2fe119a0f5 100644 (file)
@@ -223,7 +223,7 @@ static struct platform_device atmel_nand_device = {
 
 void __init at91_add_device_nand(struct atmel_nand_data *data)
 {
-       unsigned long csa, mode;
+       unsigned long csa;
 
        if (!data)
                return;
@@ -231,21 +231,6 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
        at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
-       /* set the bus interface characteristics */
-       at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(1) | AT91_SMC_NCS_WRSETUP_(0)
-                       | AT91_SMC_NRDSETUP_(1) | AT91_SMC_NCS_RDSETUP_(0));
-
-       at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3)
-                       | AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
-
-       at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
-
-       if (data->bus_width_16)
-               mode = AT91_SMC_DBW_16;
-       else
-               mode = AT91_SMC_DBW_8;
-       at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2));
-
        /* enable pin */
        if (data->enable_pin)
                at91_set_gpio_output(data->enable_pin, 1);
index 8b884083f76d8e08b1abbd14e0df8a56aaa8ee1b..b753cb879d8e6ae5ee7621492709fae1895eaebd 100644 (file)
@@ -382,7 +382,7 @@ static struct platform_device at91sam9263_nand_device = {
 
 void __init at91_add_device_nand(struct atmel_nand_data *data)
 {
-       unsigned long csa, mode;
+       unsigned long csa;
 
        if (!data)
                return;
@@ -390,21 +390,6 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
        at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
 
-       /* set the bus interface characteristics */
-       at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(1) | AT91_SMC_NCS_WRSETUP_(0)
-                       | AT91_SMC_NRDSETUP_(1) | AT91_SMC_NCS_RDSETUP_(0));
-
-       at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3)
-                       | AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
-
-       at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
-
-       if (data->bus_width_16)
-               mode = AT91_SMC_DBW_16;
-       else
-               mode = AT91_SMC_DBW_8;
-       at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2));
-
        /* enable pin */
        if (data->enable_pin)
                at91_set_gpio_output(data->enable_pin, 1);
index 87deb1e1b529854fd74c330adce5f02daa5f5599..145324f4ec5671fca146f160196dc54b5cd0cfb6 100644 (file)
@@ -232,17 +232,6 @@ void __init at91_add_device_nand(struct atmel_nand_data *data)
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
        at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
 
-       /* set the bus interface characteristics */
-       at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(1) | AT91_SMC_NCS_WRSETUP_(0)
-                       | AT91_SMC_NRDSETUP_(1) | AT91_SMC_NCS_RDSETUP_(0));
-
-       at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3)
-                       | AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
-
-       at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
-
-       at91_sys_write(AT91_SMC_MODE(3), AT91_SMC_DBW_8 | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2));
-
        /* enable pin */
        if (data->enable_pin)
                at91_set_gpio_output(data->enable_pin, 1);
index cdddca54b938ce79fd7ec2b182a96b22df0d3ff1..d3ba29c5d8c83722b7276b7d98ed51cfecfac4a7 100644 (file)
@@ -39,7 +39,9 @@
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -151,6 +153,32 @@ static struct atmel_nand_data __initdata cam60_nand_data = {
        .partition_info = nand_partitions,
 };
 
+static struct sam9_smc_config __initdata cam60_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init cam60_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &cam60_nand_smc_config);
+
+       at91_add_device_nand(&cam60_nand_data);
+}
+
 
 static void __init cam60_board_init(void)
 {
@@ -165,7 +193,7 @@ static void __init cam60_board_init(void)
        at91_set_gpio_output(AT91_PIN_PB18, 1);
        at91_add_device_usbh(&cam60_usbh_data);
        /* NAND */
-       at91_add_device_nand(&cam60_nand_data);
+       cam60_add_device_nand();
 }
 
 MACHINE_START(CAM60, "KwikByte CAM60")
index 201b89392dcc4ec91555b9d139ee87757b8a1004..83a1a0fef47be359b7138f4584d734a6f1ff5ae0 100644 (file)
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
 
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91cap9_matrix.h>
 #include <mach/at91sam9_smc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -195,6 +194,43 @@ static struct atmel_nand_data __initdata cap9adk_nand_data = {
 #endif
 };
 
+static struct sam9_smc_config __initdata cap9adk_nand_smc_config = {
+       .ncs_read_setup         = 1,
+       .nrd_setup              = 2,
+       .ncs_write_setup        = 1,
+       .nwe_setup              = 2,
+
+       .ncs_read_pulse         = 6,
+       .nrd_pulse              = 4,
+       .ncs_write_pulse        = 6,
+       .nwe_pulse              = 4,
+
+       .read_cycle             = 8,
+       .write_cycle            = 8,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+       .tdf_cycles             = 1,
+};
+
+static void __init cap9adk_add_device_nand(void)
+{
+       unsigned long csa;
+
+       csa = at91_sys_read(AT91_MATRIX_EBICSA);
+       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
+
+       /* setup bus-width (8 or 16) */
+       if (cap9adk_nand_data.bus_width_16)
+               cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
+       else
+               cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &cap9adk_nand_smc_config);
+
+       at91_add_device_nand(&cap9adk_nand_data);
+}
+
 
 /*
  * NOR flash
@@ -234,6 +270,24 @@ static struct platform_device cap9adk_nor_flash = {
        .num_resources  = ARRAY_SIZE(nor_flash_resources),
 };
 
+static struct sam9_smc_config __initdata cap9adk_nor_smc_config = {
+       .ncs_read_setup         = 2,
+       .nrd_setup              = 4,
+       .ncs_write_setup        = 2,
+       .nwe_setup              = 4,
+
+       .ncs_read_pulse         = 10,
+       .nrd_pulse              = 8,
+       .ncs_write_pulse        = 10,
+       .nwe_pulse              = 8,
+
+       .read_cycle             = 16,
+       .write_cycle            = 16,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16,
+       .tdf_cycles             = 1,
+};
+
 static __init void cap9adk_add_device_nor(void)
 {
        unsigned long csa;
@@ -241,18 +295,8 @@ static __init void cap9adk_add_device_nor(void)
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
        at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
 
-       /* set the bus interface characteristics */
-       at91_sys_write(AT91_SMC_SETUP(0), AT91_SMC_NWESETUP_(4) | AT91_SMC_NCS_WRSETUP_(2)
-                       | AT91_SMC_NRDSETUP_(4) | AT91_SMC_NCS_RDSETUP_(2));
-
-       at91_sys_write(AT91_SMC_PULSE(0), AT91_SMC_NWEPULSE_(8) | AT91_SMC_NCS_WRPULSE_(10)
-                       | AT91_SMC_NRDPULSE_(8) | AT91_SMC_NCS_RDPULSE_(10));
-
-       at91_sys_write(AT91_SMC_CYCLE(0), AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
-
-       at91_sys_write(AT91_SMC_MODE(0), AT91_SMC_READMODE | AT91_SMC_WRITEMODE
-                       | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
-                       | AT91_SMC_DBW_16 | AT91_SMC_TDF_(1));
+       /* configure chip-select 0 (NOR) */
+       sam9_smc_configure(0, &cap9adk_nor_smc_config);
 
        platform_device_register(&cap9adk_nor_flash);
 }
@@ -330,10 +374,8 @@ static void __init cap9adk_board_init(void)
        /* Serial */
        at91_add_device_serial();
        /* USB Host */
-       set_irq_type(AT91CAP9_ID_UHP, IRQ_TYPE_LEVEL_HIGH);
        at91_add_device_usbh(&cap9adk_usbh_data);
        /* USB HS */
-       set_irq_type(AT91CAP9_ID_UDPHS, IRQ_TYPE_LEVEL_HIGH);
        at91_add_device_usba(&cap9adk_usba_udc_data);
        /* SPI */
        at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices));
@@ -344,13 +386,12 @@ static void __init cap9adk_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&cap9adk_macb_data);
        /* NAND */
-       at91_add_device_nand(&cap9adk_nand_data);
+       cap9adk_add_device_nand();
        /* NOR Flash */
        cap9adk_add_device_nor();
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* LCD Controller */
-       set_irq_type(AT91CAP9_ID_LCDC, IRQ_TYPE_LEVEL_HIGH);
        at91_add_device_lcdc(&cap9adk_lcdc_data);
        /* AC97 */
        at91_add_device_ac97(&cap9adk_ac97_data);
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
new file mode 100644 (file)
index 0000000..9ba7ba2
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * linux/arch/arm/mach-at91/board-neocore926.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2007 Atmel Corporation
+ *  Copyright (C) 2008 ADENEO.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/fb.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init neocore926_map_io(void)
+{
+       /* Initialize processor: 20 MHz crystal */
+       at91sam9263_initialize(20000000);
+
+       /* DGBU on ttyS0. (Rx & Tx only) */
+       at91_register_uart(0, 0, 0);
+
+       /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+       at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+       /* set serial console to ttyS0 (ie, DBGU) */
+       at91_set_serial_console(0);
+}
+
+static void __init neocore926_init_irq(void)
+{
+       at91sam9263_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata neocore926_usbh_data = {
+       .ports          = 2,
+       .vbus_pin       = { AT91_PIN_PA24, AT91_PIN_PA21 },
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata neocore926_udc_data = {
+       .vbus_pin       = AT91_PIN_PA25,
+       .pullup_pin     = 0,            /* pull-up driven by UDC */
+};
+
+
+/*
+ * ADS7846 Touchscreen
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+static int ads7843_pendown_state(void)
+{
+       return !at91_get_gpio_value(AT91_PIN_PA15);     /* Touchscreen PENIRQ */
+}
+
+static struct ads7846_platform_data ads_info = {
+       .model                  = 7843,
+       .x_min                  = 150,
+       .x_max                  = 3830,
+       .y_min                  = 190,
+       .y_max                  = 3830,
+       .vref_delay_usecs       = 100,
+       .x_plate_ohms           = 450,
+       .y_plate_ohms           = 250,
+       .pressure_max           = 15000,
+       .debounce_max           = 1,
+       .debounce_rep           = 0,
+       .debounce_tol           = (~0),
+       .get_pendown_state      = ads7843_pendown_state,
+};
+
+static void __init neocore926_add_device_ts(void)
+{
+       at91_set_B_periph(AT91_PIN_PA15, 1);    /* External IRQ1, with pullup */
+       at91_set_gpio_input(AT91_PIN_PC13, 1);  /* Touchscreen BUSY signal */
+}
+#else
+static void __init neocore926_add_device_ts(void) {}
+#endif
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info neocore926_spi_devices[] = {
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+       {       /* DataFlash card */
+               .modalias       = "mtd_dataflash",
+               .chip_select    = 0,
+               .max_speed_hz   = 15 * 1000 * 1000,
+               .bus_num        = 0,
+       },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+       {
+               .modalias       = "ads7846",
+               .chip_select    = 1,
+               .max_speed_hz   = 125000 * 16,
+               .bus_num        = 0,
+               .platform_data  = &ads_info,
+               .irq            = AT91SAM9263_ID_IRQ1,
+       },
+#endif
+};
+
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata neocore926_mmc_data = {
+       .wire4          = 1,
+       .det_pin        = AT91_PIN_PE18,
+       .wp_pin         = AT91_PIN_PE19,
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata neocore926_macb_data = {
+       .phy_irq_pin    = AT91_PIN_PE31,
+       .is_rmii        = 1,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata neocore926_nand_partition[] = {
+       {
+               .name   = "Linux Kernel",       /* "Partition 1", */
+               .offset = 0,
+               .size   = SZ_8M,
+       },
+       {
+               .name   = "Filesystem",         /* "Partition 2", */
+               .offset = MTDPART_OFS_NXTBLK,
+               .size   = SZ_32M,
+       },
+       {
+               .name   = "Free",               /* "Partition 3", */
+               .offset = MTDPART_OFS_NXTBLK,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+       *num_partitions = ARRAY_SIZE(neocore926_nand_partition);
+       return neocore926_nand_partition;
+}
+
+static struct atmel_nand_data __initdata neocore926_nand_data = {
+       .ale                    = 21,
+       .cle                    = 22,
+       .rdy_pin                = AT91_PIN_PB19,
+       .rdy_pin_active_low     = 1,
+       .enable_pin             = AT91_PIN_PD15,
+       .partition_info         = nand_partitions,
+};
+
+static struct sam9_smc_config __initdata neocore926_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 4,
+       .nrd_pulse              = 4,
+       .ncs_write_pulse        = 4,
+       .nwe_pulse              = 4,
+
+       .read_cycle             = 6,
+       .write_cycle            = 6,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init neocore926_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &neocore926_nand_smc_config);
+
+       at91_add_device_nand(&neocore926_nand_data);
+}
+
+
+/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+       {
+               .name           = "TX09D50VM1CCA @ 60",
+               .refresh        = 60,
+               .xres           = 240,          .yres           = 320,
+               .pixclock       = KHZ2PICOS(5000),
+
+               .left_margin    = 1,            .right_margin   = 33,
+               .upper_margin   = 1,            .lower_margin   = 0,
+               .hsync_len      = 5,            .vsync_len      = 1,
+
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+       .manufacturer   = "HIT",
+       .monitor        = "TX09D70VM1CCA",
+
+       .modedb         = at91_tft_vga_modes,
+       .modedb_len     = ARRAY_SIZE(at91_tft_vga_modes),
+       .hfmin          = 15000,
+       .hfmax          = 64000,
+       .vfmin          = 50,
+       .vfmax          = 150,
+};
+
+#define AT91SAM9263_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
+                                       | ATMEL_LCDC_DISTYPE_TFT \
+                                       | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+static void at91_lcdc_power_control(int on)
+{
+       at91_set_gpio_value(AT91_PIN_PA30, on);
+}
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata neocore926_lcdc_data = {
+       .lcdcon_is_backlight            = true,
+       .default_bpp                    = 16,
+       .default_dmacon                 = ATMEL_LCDC_DMAEN,
+       .default_lcdcon2                = AT91SAM9263_DEFAULT_LCDCON2,
+       .default_monspecs               = &at91fb_default_monspecs,
+       .atmel_lcdfb_power_control      = at91_lcdc_power_control,
+       .guard_time                     = 1,
+       .lcd_wiring_mode                = ATMEL_LCDC_WIRING_RGB555,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata neocore926_lcdc_data;
+#endif
+
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button neocore926_buttons[] = {
+       {       /* BP1, "leftclic" */
+               .code           = BTN_LEFT,
+               .gpio           = AT91_PIN_PC5,
+               .active_low     = 1,
+               .desc           = "left_click",
+               .wakeup         = 1,
+       },
+       {       /* BP2, "rightclic" */
+               .code           = BTN_RIGHT,
+               .gpio           = AT91_PIN_PC4,
+               .active_low     = 1,
+               .desc           = "right_click",
+               .wakeup         = 1,
+       },
+};
+
+static struct gpio_keys_platform_data neocore926_button_data = {
+       .buttons        = neocore926_buttons,
+       .nbuttons       = ARRAY_SIZE(neocore926_buttons),
+};
+
+static struct platform_device neocore926_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &neocore926_button_data,
+       }
+};
+
+static void __init neocore926_add_device_buttons(void)
+{
+       at91_set_GPIO_periph(AT91_PIN_PC5, 0);  /* left button */
+       at91_set_deglitch(AT91_PIN_PC5, 1);
+       at91_set_GPIO_periph(AT91_PIN_PC4, 0);  /* right button */
+       at91_set_deglitch(AT91_PIN_PC4, 1);
+
+       platform_device_register(&neocore926_button_device);
+}
+#else
+static void __init neocore926_add_device_buttons(void) {}
+#endif
+
+
+/*
+ * AC97
+ */
+static struct atmel_ac97_data neocore926_ac97_data = {
+       .reset_pin      = AT91_PIN_PA13,
+};
+
+
+static void __init neocore926_board_init(void)
+{
+       /* Serial */
+       at91_add_device_serial();
+
+       /* USB Host */
+       at91_add_device_usbh(&neocore926_usbh_data);
+
+       /* USB Device */
+       at91_add_device_udc(&neocore926_udc_data);
+
+       /* SPI */
+       at91_set_gpio_output(AT91_PIN_PE20, 1);         /* select spi0 clock */
+       at91_add_device_spi(neocore926_spi_devices, ARRAY_SIZE(neocore926_spi_devices));
+
+       /* Touchscreen */
+       neocore926_add_device_ts();
+
+       /* MMC */
+       at91_add_device_mmc(1, &neocore926_mmc_data);
+
+       /* Ethernet */
+       at91_add_device_eth(&neocore926_macb_data);
+
+       /* NAND */
+       neocore926_add_device_nand();
+
+       /* I2C */
+       at91_add_device_i2c(NULL, 0);
+
+       /* LCD Controller */
+       at91_add_device_lcdc(&neocore926_lcdc_data);
+
+       /* Push Buttons */
+       neocore926_add_device_buttons();
+
+       /* AC97 */
+       at91_add_device_ac97(&neocore926_ac97_data);
+}
+
+MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
+       /* Maintainer: ADENEO */
+       .phys_io        = AT91_BASE_SYS,
+       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = neocore926_map_io,
+       .init_irq       = neocore926_init_irq,
+       .init_machine   = neocore926_board_init,
+MACHINE_END
index cfb4571a2e275d00c52a587a8ed21d71d9d7b59a..4cff9a7e61d2d70b8af645e11bc38df30bfdd72a 100644 (file)
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -147,13 +149,34 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 /*
  * MCI (SD/MMC)
  */
@@ -227,7 +250,7 @@ static void __init ek_board_init(void)
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* Ethernet */
index 99bb4cc23a0950af07d18712b077696c2f6842c9..b4834697753499278b85aea36c710d990dd9ce49 100644 (file)
@@ -38,7 +38,9 @@
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -148,13 +150,34 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 
 /*
  * MCI (SD/MMC)
@@ -178,7 +201,7 @@ static void __init ek_board_init(void)
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* MMC */
index b49eb6e4918acc52ba87fe400634fd3ec2ed1f80..93a0f8b100eb24e725326cc0cb1f497526d6224d 100644 (file)
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -195,6 +198,38 @@ static struct atmel_nand_data __initdata ek_nand_data = {
 #endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* setup bus-width (8 or 16) */
+       if (ek_nand_data.bus_width_16)
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+       else
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 
 /*
  * MCI (SD/MMC)
@@ -303,7 +338,7 @@ static void __init ek_board_init(void)
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* MMC */
index 4977409d4fc6bcb72e3f17fa8a5646526040b9e5..d5266da553112651228679c4beb42944b89a2d42 100644 (file)
@@ -47,7 +47,9 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -76,7 +78,7 @@ static void __init ek_init_irq(void)
  * DM9000 ethernet device
  */
 #if defined(CONFIG_DM9000)
-static struct resource at91sam9261_dm9000_resource[] = {
+static struct resource dm9000_resource[] = {
        [0] = {
                .start  = AT91_CHIPSELECT_2,
                .end    = AT91_CHIPSELECT_2 + 3,
@@ -98,27 +100,42 @@ static struct dm9000_plat_data dm9000_platdata = {
        .flags          = DM9000_PLATF_16BITONLY,
 };
 
-static struct platform_device at91sam9261_dm9000_device = {
+static struct platform_device dm9000_device = {
        .name           = "dm9000",
        .id             = 0,
-       .num_resources  = ARRAY_SIZE(at91sam9261_dm9000_resource),
-       .resource       = at91sam9261_dm9000_resource,
+       .num_resources  = ARRAY_SIZE(dm9000_resource),
+       .resource       = dm9000_resource,
        .dev            = {
                .platform_data  = &dm9000_platdata,
        }
 };
 
+/*
+ * SMC timings for the DM9000.
+ * Note: These timings were calculated for MASTER_CLOCK = 100000000 according to the DM9000 timings.
+ */
+static struct sam9_smc_config __initdata dm9000_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 2,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 2,
+
+       .ncs_read_pulse         = 8,
+       .nrd_pulse              = 4,
+       .ncs_write_pulse        = 8,
+       .nwe_pulse              = 4,
+
+       .read_cycle             = 16,
+       .write_cycle            = 16,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16,
+       .tdf_cycles             = 1,
+};
+
 static void __init ek_add_device_dm9000(void)
 {
-       /*
-        * Configure Chip-Select 2 on SMC for the DM9000.
-        * Note: These timings were calculated for MASTER_CLOCK = 100000000
-        *  according to the DM9000 timings.
-        */
-       at91_sys_write(AT91_SMC_SETUP(2), AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(0) | AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(0));
-       at91_sys_write(AT91_SMC_PULSE(2), AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(8) | AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(8));
-       at91_sys_write(AT91_SMC_CYCLE(2), AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
-       at91_sys_write(AT91_SMC_MODE(2), AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16 | AT91_SMC_TDF_(1));
+       /* Configure chip-select 2 (DM9000) */
+       sam9_smc_configure(2, &dm9000_smc_config);
 
        /* Configure Reset signal as output */
        at91_set_gpio_output(AT91_PIN_PC10, 0);
@@ -126,7 +143,7 @@ static void __init ek_add_device_dm9000(void)
        /* Configure Interrupt pin as input, no pull-up */
        at91_set_gpio_input(AT91_PIN_PC11, 0);
 
-       platform_device_register(&at91sam9261_dm9000_device);
+       platform_device_register(&dm9000_device);
 }
 #else
 static void __init ek_add_device_dm9000(void) {}
@@ -197,6 +214,39 @@ static struct atmel_nand_data __initdata ek_nand_data = {
 #endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* setup bus-width (8 or 16) */
+       if (ek_nand_data.bus_width_16)
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+       else
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
+
 /*
  * ADS7846 Touchscreen
  */
@@ -525,7 +575,7 @@ static void __init ek_board_init(void)
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* DM9000 ethernet */
        ek_add_device_dm9000();
 
index 8354015c6a23268817caeccfe58f26646d8a7c60..57d52528f2247950b90c9b4010af813595eeedcc 100644 (file)
@@ -46,7 +46,9 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -203,6 +205,38 @@ static struct atmel_nand_data __initdata ek_nand_data = {
 #endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* setup bus-width (8 or 16) */
+       if (ek_nand_data.bus_width_16)
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+       else
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 
 /*
  * I2C devices
@@ -385,7 +419,7 @@ static void __init ek_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* I2C */
        at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
        /* LCD Controller */
index b588ead14d68a4cb569f1ca8384c166a32bffb33..81439fe6fb3d7bc368ce1656870aa1d476d98b67 100644 (file)
@@ -37,7 +37,9 @@
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -156,6 +158,38 @@ static struct atmel_nand_data __initdata ek_nand_data = {
 #endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 2,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 2,
+
+       .ncs_read_pulse         = 4,
+       .nrd_pulse              = 4,
+       .ncs_write_pulse        = 4,
+       .nwe_pulse              = 4,
+
+       .read_cycle             = 7,
+       .write_cycle            = 7,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+       .tdf_cycles             = 3,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* setup bus-width (8 or 16) */
+       if (ek_nand_data.bus_width_16)
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+       else
+               ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 
 /*
  * MCI (SD/MMC)
@@ -195,7 +229,7 @@ static void __init ek_board_init(void)
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* MMC */
index 2708518643084f78d6eacd5d1e04c3a214ec53b9..9b937ee4815a804cd8b92dc5e32aca82e9c04d29 100644 (file)
@@ -29,8 +29,9 @@
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
-#include <mach/at91sam9_smc.h>
+#include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -103,9 +104,34 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PD17,
        .enable_pin     = AT91_PIN_PB6,
        .partition_info = nand_partitions,
-       .bus_width_16   = 0,
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 
 /*
  * SPI devices
@@ -188,7 +214,7 @@ static void __init ek_board_init(void)
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
        /* MMC */
index 7c350357333a0b708cc143d1efcb3df01ee61f05..d13304c0bc45eff75eabe5bb9310cf724bfcd74c 100644 (file)
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -121,13 +123,34 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
 /*
  * GPIO Buttons
  */
@@ -189,7 +212,7 @@ static void __init ek_board_init(void)
        /* USB Device */
        at91_add_device_udc(&ek_udc_data);
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* Ethernet */
index 391b566c4571153ad345b67c1e6b903ab008df0e..d96405b7d5785908dd6d438b4a32b98c95c40825 100644 (file)
 #include <mach/hardware.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
 
+#include "sam9_smc.h"
 #include "generic.h"
 
 
@@ -134,13 +136,35 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PA22,
        .enable_pin     = AT91_PIN_PD15,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+       .ncs_read_setup         = 0,
+       .nrd_setup              = 1,
+       .ncs_write_setup        = 0,
+       .nwe_setup              = 1,
+
+       .ncs_read_pulse         = 3,
+       .nrd_pulse              = 3,
+       .ncs_write_pulse        = 3,
+       .nwe_pulse              = 3,
+
+       .read_cycle             = 5,
+       .write_cycle            = 5,
+
+       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
+       .tdf_cycles             = 2,
+};
+
+static void __init ek_add_device_nand(void)
+{
+       /* configure chip-select 3 (NAND) */
+       sam9_smc_configure(3, &ek_nand_smc_config);
+
+       at91_add_device_nand(&ek_nand_data);
+}
+
+
 /*
  * GPIO Buttons
  */
@@ -206,7 +230,7 @@ static void __init ek_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* NAND */
-       at91_add_device_nand(&ek_nand_data);
+       ek_add_device_nand();
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* Push Buttons */
index 2e3f2894b70496535660883a29fd21cd0bf76deb..9561e33b8a9af76ecd3eb91670254f549065b639 100644 (file)
@@ -23,6 +23,7 @@
 #define                AT91_PMC_PCK            (1 <<  0)               /* Processor Clock */
 #define                AT91RM9200_PMC_UDP      (1 <<  1)               /* USB Devcice Port Clock [AT91RM9200 only] */
 #define                AT91RM9200_PMC_MCKUDP   (1 <<  2)               /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
+#define                AT91CAP9_PMC_DDR        (1 <<  2)               /* DDR Clock [AT91CAP9 revC only] */
 #define                AT91RM9200_PMC_UHP      (1 <<  4)               /* USB Host Port Clock [AT91RM9200 only] */
 #define                AT91SAM926x_PMC_UHP     (1 <<  6)               /* USB Host Port Clock [AT91SAM926x only] */
 #define                AT91CAP9_PMC_UHP        (1 <<  6)               /* USB Host Port Clock [AT91CAP9 only] */
 #define                AT91_PMC_LOCKB          (1 <<  2)               /* PLLB Lock */
 #define                AT91_PMC_MCKRDY         (1 <<  3)               /* Master Clock */
 #define                AT91_PMC_LOCKU          (1 <<  6)               /* UPLL Lock [AT91CAP9 only] */
+#define                AT91_PMC_OSCSEL         (1 <<  7)               /* Slow Clock Oscillator [AT91CAP9 revC only] */
 #define                AT91_PMC_PCK0RDY        (1 <<  8)               /* Programmable Clock 0 */
 #define                AT91_PMC_PCK1RDY        (1 <<  9)               /* Programmable Clock 1 */
 #define                AT91_PMC_PCK2RDY        (1 << 10)               /* Programmable Clock 2 */
 #define                AT91_PMC_PCK3RDY        (1 << 11)               /* Programmable Clock 3 */
 #define        AT91_PMC_IMR            (AT91_PMC + 0x6c)       /* Interrupt Mask Register */
 
+#define AT91_PMC_PROT          (AT91_PMC + 0xe4)       /* Protect Register [AT91CAP9 revC only] */
+#define                AT91_PMC_PROTKEY        0x504d4301      /* Activation Code */
+
+#define AT91_PMC_VER           (AT91_PMC + 0xfc)       /* PMC Module Version [AT91CAP9 only] */
+
 #endif
index 4a4b64135a922a16ebb72e3c38e0c09acfc39361..d8c1ededaa75aea4ab8835ade94c2dda544068f7 100644 (file)
 #define AT91_RTT       (0xfffffd20 - AT91_BASE_SYS)
 #define AT91_PIT       (0xfffffd30 - AT91_BASE_SYS)
 #define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd50 - AT91_BASE_SYS)
+#define AT91_GPBR      (cpu_is_at91cap9_revB() ?       \
+                       (0xfffffd50 - AT91_BASE_SYS) :  \
+                       (0xfffffd60 - AT91_BASE_SYS))
 
 #define AT91_USART0    AT91CAP9_BASE_US0
 #define AT91_USART1    AT91CAP9_BASE_US1
index dbfd9f73f80bb4aa531e8a6ec063de0082fb2195..c554c3e4d5532c09a96eef3270c3e5a71f68fb99 100644 (file)
@@ -49,6 +49,17 @@ static inline unsigned long at91_arch_identify(void)
        return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH);
 }
 
+#ifdef CONFIG_ARCH_AT91CAP9
+#include <mach/at91_pmc.h>
+
+#define ARCH_REVISION_CAP9_B   0x399
+#define ARCH_REVISION_CAP9_C   0x601
+
+static inline unsigned long at91cap9_rev_identify(void)
+{
+       return (at91_sys_read(AT91_PMC_VER));
+}
+#endif
 
 #ifdef CONFIG_ARCH_AT91RM9200
 #define cpu_is_at91rm9200()    (at91_cpu_identify() == ARCH_ID_AT91RM9200)
@@ -90,8 +101,12 @@ static inline unsigned long at91_arch_identify(void)
 
 #ifdef CONFIG_ARCH_AT91CAP9
 #define cpu_is_at91cap9()      (at91_cpu_identify() == ARCH_ID_AT91CAP9)
+#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
+#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C)
 #else
 #define cpu_is_at91cap9()      (0)
+#define cpu_is_at91cap9_revB() (0)
+#define cpu_is_at91cap9_revC() (0)
 #endif
 
 /*
diff --git a/arch/arm/mach-at91/include/mach/dma.h b/arch/arm/mach-at91/include/mach/dma.h
deleted file mode 100644 (file)
index e4f90c1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/dma.h
- *
- *  Copyright (C) 2003 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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
- */
index 1611bd03f52892ca846f56f4adc8801e4c85e362..0b0cccc46e68497dd399c6ab283f4009ad5c92a7 100644 (file)
@@ -23,8 +23,8 @@
 
 #define IO_SPACE_LIMIT         0xFFFFFFFF
 
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 
 #ifndef __ASSEMBLY__
index 9dd1b8c79b08cad32628745d1956d742c9c7712e..14f4ef4b6a9ebd7c94c863e19b8dd02e3bc39074 100644 (file)
 
 #define PHYS_OFFSET    (AT91_SDRAM_BASE)
 
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
 #endif
diff --git a/arch/arm/mach-at91/sam9_smc.c b/arch/arm/mach-at91/sam9_smc.c
new file mode 100644 (file)
index 0000000..5eab6aa
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-at91/sam9_smc.c
+ *
+ * Copyright (C) 2008 Andrew Victor
+ *
+ * This program is free software; you can 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/io.h>
+
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+
+void __init sam9_smc_configure(int cs, struct sam9_smc_config* config)
+{
+       /* Setup register */
+       at91_sys_write(AT91_SMC_SETUP(cs),
+                 AT91_SMC_NWESETUP_(config->nwe_setup)
+               | AT91_SMC_NCS_WRSETUP_(config->ncs_write_setup)
+               | AT91_SMC_NRDSETUP_(config->nrd_setup)
+               | AT91_SMC_NCS_RDSETUP_(config->ncs_read_setup)
+       );
+
+       /* Pulse register */
+       at91_sys_write(AT91_SMC_PULSE(cs),
+                 AT91_SMC_NWEPULSE_(config->nwe_pulse)
+               | AT91_SMC_NCS_WRPULSE_(config->ncs_write_pulse)
+                | AT91_SMC_NRDPULSE_(config->nrd_pulse)
+               | AT91_SMC_NCS_RDPULSE_(config->ncs_read_pulse)
+       );
+
+       /* Cycle register */
+       at91_sys_write(AT91_SMC_CYCLE(cs),
+                 AT91_SMC_NWECYCLE_(config->write_cycle)
+               | AT91_SMC_NRDCYCLE_(config->read_cycle)
+       );
+
+       /* Mode register */
+       at91_sys_write(AT91_SMC_MODE(cs),
+                 config->mode
+               | AT91_SMC_TDF_(config->tdf_cycles)
+       );
+}
diff --git a/arch/arm/mach-at91/sam9_smc.h b/arch/arm/mach-at91/sam9_smc.h
new file mode 100644 (file)
index 0000000..bf72cfb
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * linux/arch/arm/mach-at91/sam9_smc.
+ *
+ * Copyright (C) 2008 Andrew Victor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+struct sam9_smc_config {
+       /* Setup register */
+       u8 ncs_read_setup;
+       u8 nrd_setup;
+       u8 ncs_write_setup;
+       u8 nwe_setup;
+
+       /* Pulse register */
+       u8 ncs_read_pulse;
+       u8 nrd_pulse;
+       u8 ncs_write_pulse;
+       u8 nwe_pulse;
+
+       /* Cycle register */
+       u16 read_cycle;
+       u16 write_cycle;
+
+       /* Mode register */
+       u32 mode;
+       u8 tdf_cycles:4;
+};
+
+extern void __init sam9_smc_configure(int cs, struct sam9_smc_config* config);
diff --git a/arch/arm/mach-clps711x/include/mach/dma.h b/arch/arm/mach-clps711x/include/mach/dma.h
deleted file mode 100644 (file)
index 0d620e8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- *  arch/arm/mach-clps711x/include/mach/dma.h
- *
- *  Copyright (C) 1997,1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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
- */
index 4c8440087679cb0548b2b3481b92be97552f7132..2e0b3ced8f07034f7e7c342b34f1b64d5a491afd 100644 (file)
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 /*
  * We don't support ins[lb]/outs[lb].  Make them fault.
index 98ec30c97bbe9d115994ca20cfca0cc82a614473..e522b20bcbc25efcd17f4976c0544ea43252b57d 100644 (file)
  */
 #define PHYS_OFFSET    UL(0xc0000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-
-#if defined(CONFIG_ARCH_CDB89712)
-
-#define __virt_to_bus(x)       (x)
-#define __bus_to_virt(x)       (x)
-
-#elif defined (CONFIG_ARCH_AUTCPU12)
-
-#define __virt_to_bus(x)       (x)
-#define __bus_to_virt(x)       (x)
-
-#else
+#if !defined(CONFIG_ARCH_CDB89712) && !defined (CONFIG_ARCH_AUTCPU12)
 
 #define __virt_to_bus(x)       ((x) - PAGE_OFFSET)
 #define __bus_to_virt(x)       ((x) + PAGE_OFFSET)
diff --git a/arch/arm/mach-clps7500/Makefile b/arch/arm/mach-clps7500/Makefile
deleted file mode 100644 (file)
index 4bd8ebd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y                  := core.o
-obj-m                  :=
-obj-n                  :=
-obj-                   :=
-
diff --git a/arch/arm/mach-clps7500/Makefile.boot b/arch/arm/mach-clps7500/Makefile.boot
deleted file mode 100644 (file)
index fe16506..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-   zreladdr-y  := 0x10008000
-
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
deleted file mode 100644 (file)
index 7e247c0..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- *  linux/arch/arm/mach-clps7500/core.c
- *
- *  Copyright (C) 1998 Russell King
- *  Copyright (C) 1999 Nexus Electronics Ltd
- *
- * Extra MM routines for CL7500 architecture
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/serial_8250.h>
-#include <linux/io.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-
-#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-unsigned int vram_size;
-
-static void cl7500_ack_irq_a(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << irq;
-       val = iomd_readb(IOMD_IRQMASKA);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKA);
-       iomd_writeb(mask, IOMD_IRQCLRA);
-}
-
-static void cl7500_mask_irq_a(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << irq;
-       val = iomd_readb(IOMD_IRQMASKA);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKA);
-}
-
-static void cl7500_unmask_irq_a(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << irq;
-       val = iomd_readb(IOMD_IRQMASKA);
-       iomd_writeb(val | mask, IOMD_IRQMASKA);
-}
-
-static struct irq_chip clps7500_a_chip = {
-       .ack    = cl7500_ack_irq_a,
-       .mask   = cl7500_mask_irq_a,
-       .unmask = cl7500_unmask_irq_a,
-};
-
-static void cl7500_mask_irq_b(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_IRQMASKB);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKB);
-}
-
-static void cl7500_unmask_irq_b(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_IRQMASKB);
-       iomd_writeb(val | mask, IOMD_IRQMASKB);
-}
-
-static struct irq_chip clps7500_b_chip = {
-       .ack    = cl7500_mask_irq_b,
-       .mask   = cl7500_mask_irq_b,
-       .unmask = cl7500_unmask_irq_b,
-};
-
-static void cl7500_mask_irq_c(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_IRQMASKC);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKC);
-}
-
-static void cl7500_unmask_irq_c(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_IRQMASKC);
-       iomd_writeb(val | mask, IOMD_IRQMASKC);
-}
-
-static struct irq_chip clps7500_c_chip = {
-       .ack    = cl7500_mask_irq_c,
-       .mask   = cl7500_mask_irq_c,
-       .unmask = cl7500_unmask_irq_c,
-};
-
-static void cl7500_mask_irq_d(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_IRQMASKD);
-       iomd_writeb(val & ~mask, IOMD_IRQMASKD);
-}
-
-static void cl7500_unmask_irq_d(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_IRQMASKD);
-       iomd_writeb(val | mask, IOMD_IRQMASKD);
-}
-
-static struct irq_chip clps7500_d_chip = {
-       .ack    = cl7500_mask_irq_d,
-       .mask   = cl7500_mask_irq_d,
-       .unmask = cl7500_unmask_irq_d,
-};
-
-static void cl7500_mask_irq_dma(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_DMAMASK);
-       iomd_writeb(val & ~mask, IOMD_DMAMASK);
-}
-
-static void cl7500_unmask_irq_dma(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_DMAMASK);
-       iomd_writeb(val | mask, IOMD_DMAMASK);
-}
-
-static struct irq_chip clps7500_dma_chip = {
-       .ack    = cl7500_mask_irq_dma,
-       .mask   = cl7500_mask_irq_dma,
-       .unmask = cl7500_unmask_irq_dma,
-};
-
-static void cl7500_mask_irq_fiq(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_FIQMASK);
-       iomd_writeb(val & ~mask, IOMD_FIQMASK);
-}
-
-static void cl7500_unmask_irq_fiq(unsigned int irq)
-{
-       unsigned int val, mask;
-
-       mask = 1 << (irq & 7);
-       val = iomd_readb(IOMD_FIQMASK);
-       iomd_writeb(val | mask, IOMD_FIQMASK);
-}
-
-static struct irq_chip clps7500_fiq_chip = {
-       .ack    = cl7500_mask_irq_fiq,
-       .mask   = cl7500_mask_irq_fiq,
-       .unmask = cl7500_unmask_irq_fiq,
-};
-
-static void cl7500_no_action(unsigned int irq)
-{
-}
-
-static struct irq_chip clps7500_no_chip = {
-       .ack    = cl7500_no_action,
-       .mask   = cl7500_no_action,
-       .unmask = cl7500_no_action,
-};
-
-static struct irqaction irq_isa = {
-       .handler = no_action,
-       .mask = CPU_MASK_NONE,
-       .name = "isa",
-};
-
-static void __init clps7500_init_irq(void)
-{
-       unsigned int irq, flags;
-
-       iomd_writeb(0, IOMD_IRQMASKA);
-       iomd_writeb(0, IOMD_IRQMASKB);
-       iomd_writeb(0, IOMD_FIQMASK);
-       iomd_writeb(0, IOMD_DMAMASK);
-
-       for (irq = 0; irq < NR_IRQS; irq++) {
-               flags = IRQF_VALID;
-
-               if (irq <= 6 || (irq >= 9 && irq <= 15) ||
-                   (irq >= 48 && irq <= 55))
-                       flags |= IRQF_PROBE;
-
-               switch (irq) {
-               case 0 ... 7:
-                       set_irq_chip(irq, &clps7500_a_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-
-               case 8 ... 15:
-                       set_irq_chip(irq, &clps7500_b_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-
-               case 16 ... 22:
-                       set_irq_chip(irq, &clps7500_dma_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-
-               case 24 ... 31:
-                       set_irq_chip(irq, &clps7500_c_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-
-               case 40 ... 47:
-                       set_irq_chip(irq, &clps7500_d_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-
-               case 48 ... 55:
-                       set_irq_chip(irq, &clps7500_no_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-
-               case 64 ... 72:
-                       set_irq_chip(irq, &clps7500_fiq_chip);
-                       set_irq_handler(irq, handle_level_irq);
-                       set_irq_flags(irq, flags);
-                       break;
-               }
-       }
-
-       setup_irq(IRQ_ISA, &irq_isa);
-}
-
-static struct map_desc cl7500_io_desc[] __initdata = {
-       {       /* IO space     */
-               .virtual        = (unsigned long)IO_BASE,
-               .pfn            = __phys_to_pfn(IO_START),
-               .length         = IO_SIZE,
-               .type           = MT_DEVICE
-       }, {    /* ISA space    */
-               .virtual        = ISA_BASE,
-               .pfn            = __phys_to_pfn(ISA_START),
-               .length         = ISA_SIZE,
-               .type           = MT_DEVICE
-       }, {    /* Flash        */
-               .virtual        = CLPS7500_FLASH_BASE,
-               .pfn            = __phys_to_pfn(CLPS7500_FLASH_START),
-               .length         = CLPS7500_FLASH_SIZE,
-               .type           = MT_DEVICE
-       }, {    /* LED          */
-               .virtual        = LED_BASE,
-               .pfn            = __phys_to_pfn(LED_START),
-               .length         = LED_SIZE,
-               .type           = MT_DEVICE
-       }
-};
-
-static void __init clps7500_map_io(void)
-{
-       iotable_init(cl7500_io_desc, ARRAY_SIZE(cl7500_io_desc));
-}
-
-extern void ioctime_init(void);
-extern unsigned long ioc_timer_gettimeoffset(void);
-
-static irqreturn_t
-clps7500_timer_interrupt(int irq, void *dev_id)
-{
-       timer_tick();
-
-       /* Why not using do_leds interface?? */
-       {
-               /* Twinkle the lights. */
-               static int count, state = 0xff00;
-               if (count-- == 0) {
-                       state ^= 0x100;
-                       count = 25;
-                       *((volatile unsigned int *)LED_ADDRESS) = state;
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
-static struct irqaction clps7500_timer_irq = {
-       .name           = "CLPS7500 Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = clps7500_timer_interrupt,
-};
-
-/*
- * Set up timer interrupt.
- */
-static void __init clps7500_timer_init(void)
-{
-       ioctime_init();
-       setup_irq(IRQ_TIMER, &clps7500_timer_irq);
-}
-
-static struct sys_timer clps7500_timer = {
-       .init           = clps7500_timer_init,
-       .offset         = ioc_timer_gettimeoffset,
-};
-
-static struct plat_serial8250_port serial_platform_data[] = {
-       {
-               .mapbase        = 0x03010fe0,
-               .irq            = 10,
-               .uartclk        = 1843200,
-               .regshift       = 2,
-               .iotype         = UPIO_MEM,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
-       },
-       {
-               .mapbase        = 0x03010be0,
-               .irq            = 0,
-               .uartclk        = 1843200,
-               .regshift       = 2,
-               .iotype         = UPIO_MEM,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
-       },
-       {
-               .iobase         = ISASLOT_IO + 0x2e8,
-               .irq            = 41,
-               .uartclk        = 1843200,
-               .regshift       = 0,
-               .iotype         = UPIO_PORT,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-       },
-       {
-               .iobase         = ISASLOT_IO + 0x3e8,
-               .irq            = 40,
-               .uartclk        = 1843200,
-               .regshift       = 0,
-               .iotype         = UPIO_PORT,
-               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
-       },
-       { },
-};
-
-static struct platform_device serial_device = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev                    = {
-               .platform_data  = serial_platform_data,
-       },
-};
-
-static void __init clps7500_init(void)
-{
-       platform_device_register(&serial_device);
-}
-
-MACHINE_START(CLPS7500, "CL-PS7500")
-       /* Maintainer: Philip Blundell */
-       .phys_io        = 0x03000000,
-       .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
-       .map_io         = clps7500_map_io,
-       .init_irq       = clps7500_init_irq,
-       .init_machine   = clps7500_init,
-       .timer          = &clps7500_timer,
-MACHINE_END
-
diff --git a/arch/arm/mach-clps7500/include/mach/acornfb.h b/arch/arm/mach-clps7500/include/mach/acornfb.h
deleted file mode 100644 (file)
index aea6330..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#define acornfb_valid_pixrate(var) (var->pixclock >= 39325 && var->pixclock <= 40119)
-
-static inline void
-acornfb_vidc20_find_rates(struct vidc_timing *vidc,
-                         struct fb_var_screeninfo *var)
-{
-       u_int bandwidth;
-  
-       vidc->control |= VIDC20_CTRL_PIX_CK;
-
-       /* Calculate bandwidth */
-       bandwidth = var->pixclock * 8 / var->bits_per_pixel;
-
-       /* Encode bandwidth as VIDC20 setting */
-       if (bandwidth > 16667*2)
-               vidc->control |= VIDC20_CTRL_FIFO_16;
-       else if (bandwidth > 13333*2)
-               vidc->control |= VIDC20_CTRL_FIFO_20;
-       else if (bandwidth > 11111*2)
-               vidc->control |= VIDC20_CTRL_FIFO_24;
-       else
-               vidc->control |= VIDC20_CTRL_FIFO_28;
-
-       vidc->pll_ctl  = 0x2020;
-}
-
-#ifdef CONFIG_CHRONTEL_7003
-#define acornfb_default_control()      VIDC20_CTRL_PIX_HCLK
-#else
-#define acornfb_default_control()      VIDC20_CTRL_PIX_VCLK
-#endif
-
-#define acornfb_default_econtrol()     VIDC20_ECTL_DAC | VIDC20_ECTL_REG(3) | VIDC20_ECTL_ECK
diff --git a/arch/arm/mach-clps7500/include/mach/debug-macro.S b/arch/arm/mach-clps7500/include/mach/debug-macro.S
deleted file mode 100644 (file)
index af4104e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* arch/arm/mach-clps7500/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- *  Copyright (C) 1994-1999 Russell King
- *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
-*/
-
-               .macro  addruart,rx
-               mov     \rx, #0xe0000000
-               orr     \rx, \rx, #0x00010000
-               orr     \rx, \rx, #0x00000be0
-               .endm
-
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-clps7500/include/mach/dma.h b/arch/arm/mach-clps7500/include/mach/dma.h
deleted file mode 100644 (file)
index 63fcde5..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/dma.h
- *
- * Copyright (C) 1999 Nexus Electronics Ltd.
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-/* DMA is not yet implemented! It should be the same as acorn, copy over.. */
-
-/*
- * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
- */
-#define MAX_DMA_ADDRESS                0xd0000000
-
-#define DMA_S0                 0
-
-#endif /* _ASM_ARCH_DMA_H */
diff --git a/arch/arm/mach-clps7500/include/mach/entry-macro.S b/arch/arm/mach-clps7500/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 4e7e541..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <mach/hardware.h>
-#include <asm/hardware/entry-macro-iomd.S>
-
-       .equ    ioc_base_high, IOC_BASE & 0xff000000
-       .equ    ioc_base_low, IOC_BASE & 0x00ff0000
-
-       .macro  get_irqnr_preamble, base, tmp
-       mov     \base, #ioc_base_high           @ point at IOC
-       .if     ioc_base_low
-       orr     \base, \base, #ioc_base_low
-       .endif
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
diff --git a/arch/arm/mach-clps7500/include/mach/hardware.h b/arch/arm/mach-clps7500/include/mach/hardware.h
deleted file mode 100644 (file)
index a6ad1d4..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/hardware.h
- *
- * Copyright (C) 1996-1999 Russell King.
- * Copyright (C) 1999 Nexus Electronics Ltd.
- *
- * This file contains the hardware definitions of the 
- * CL7500 evaluation board.
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <mach/memory.h>
-#include <asm/hardware/iomd.h>
-
-#ifdef __ASSEMBLY__
-#define IOMEM(x) x
-#else
-#define IOMEM(x) ((void __iomem *)(x))
-#endif
-
-/*
- * What hardware must be present
- */
-#define HAS_IOMD
-#define HAS_VIDC20
-
-/* Hardware addresses of major areas.
- *  *_START is the physical address
- *  *_SIZE  is the size of the region
- *  *_BASE  is the virtual address
- */
-
-#define IO_START               0x03000000      /* I/O */
-#define IO_SIZE                        0x01000000
-#define IO_BASE                        IOMEM(0xe0000000)
-
-#define ISA_START              0x0c000000      /* ISA */
-#define ISA_SIZE               0x00010000
-#define ISA_BASE               0xe1000000
-
-#define CLPS7500_FLASH_START   0x01000000      /* XXX */
-#define CLPS7500_FLASH_SIZE    0x01000000
-#define CLPS7500_FLASH_BASE    0xe2000000
-
-#define LED_START              0x0302B000
-#define LED_SIZE               0x00001000
-#define LED_BASE               0xe3000000
-#define LED_ADDRESS            (LED_BASE + 0xa00)
-
-/* Let's define SCREEN_START for CL7500, even though it's a lie. */
-#define SCREEN_START           0x02000000      /* VRAM */
-#define SCREEN_END             0xdfc00000
-#define SCREEN_BASE            0xdf800000
-
-#define VIDC_BASE              (void __iomem *)0xe0400000
-#define IOMD_BASE              IOMEM(0xe0200000)
-#define IOC_BASE               IOMEM(0xe0200000)
-#define FLOPPYDMA_BASE         IOMEM(0xe002a000)
-#define PCIO_BASE              IOMEM(0xe0010000)
-
-#define vidc_writel(val)       __raw_writel(val, VIDC_BASE)
-
-/* in/out bias for the ISA slot region */
-#define ISASLOT_IO             0x80400000
-
-#endif
diff --git a/arch/arm/mach-clps7500/include/mach/io.h b/arch/arm/mach-clps7500/include/mach/io.h
deleted file mode 100644 (file)
index 2ff2860..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/io.h
- *  from arch/arm/mach-rpc/include/mach/io.h
- *
- * Copyright (C) 1997 Russell King
- *
- * Modifications:
- *  06-Dec-1997        RMK     Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * GCC is totally crap at loading/storing data.  We try to persuade it
- * to do the right thing by using these whereever possible instead of
- * the above.
- */
-#define __arch_base_getb(b,o)                  \
- ({                                            \
-       unsigned int v, r = (b);                \
-       __asm__ __volatile__(                   \
-               "ldrb   %0, [%1, %2]"           \
-               : "=r" (v)                      \
-               : "r" (r), "Ir" (o));           \
-       v;                                      \
- })
-
-#define __arch_base_getl(b,o)                  \
- ({                                            \
-       unsigned int v, r = (b);                \
-       __asm__ __volatile__(                   \
-               "ldr    %0, [%1, %2]"           \
-               : "=r" (v)                      \
-               : "r" (r), "Ir" (o));           \
-       v;                                      \
- })
-
-#define __arch_base_putb(v,b,o)                        \
- ({                                            \
-       unsigned int r = (b);                   \
-       __asm__ __volatile__(                   \
-               "strb   %0, [%1, %2]"           \
-               :                               \
-               : "r" (v), "r" (r), "Ir" (o));  \
- })
-
-#define __arch_base_putl(v,b,o)                        \
- ({                                            \
-       unsigned int r = (b);                   \
-       __asm__ __volatile__(                   \
-               "str    %0, [%1, %2]"           \
-               :                               \
-               : "r" (v), "r" (r), "Ir" (o));  \
- })
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
- * and are translated to the start of IO.  Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-static inline void __outb (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "strb   %1, [%0, %2, lsl #2]    @ outb"
-       : "=&r" (temp)
-       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-static inline void __outw (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "str    %1, [%0, %2, lsl #2]    @ outw"
-       : "=&r" (temp)
-       : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-static inline void __outl (unsigned int value, unsigned int port)
-{
-       unsigned long temp;
-       __asm__ __volatile__(
-       "tst    %2, #0x80000000\n\t"
-       "mov    %0, %4\n\t"
-       "addeq  %0, %0, %3\n\t"
-       "str    %1, [%0, %2, lsl #2]    @ outl"
-       : "=&r" (temp)
-       : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
-       : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr)                                      \
-static inline unsigned sz __in##fnsuffix (unsigned int port)           \
-{                                                                              \
-       unsigned long temp, value;                                              \
-       __asm__ __volatile__(                                                   \
-       "tst    %2, #0x80000000\n\t"                                            \
-       "mov    %0, %4\n\t"                                                     \
-       "addeq  %0, %0, %3\n\t"                                                 \
-       "ldr" instr "   %1, [%0, %2, lsl #2]    @ in" #fnsuffix                 \
-       : "=&r" (temp), "=r" (value)                                            \
-       : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)                \
-       : "cc");                                                                \
-       return (unsigned sz)value;                                              \
-}
-
-static inline unsigned int __ioaddr (unsigned int port)                        \
-{                                                                              \
-       if (__PORT_PCIO(port))                                                  \
-               return (unsigned int)(PCIO_BASE + (port << 2));                 \
-       else                                                                    \
-               return (unsigned int)(IO_BASE + (port << 2));                   \
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr)  \
-       DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(int,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)                                                    \
-({                                                                             \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "strb   %0, [%1, %2]    @ outbc"                                \
-               : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2));          \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "strb   %0, [%1, %2]    @ outbc"                                \
-               : : "r" (value), "r" (IO_BASE), "r" ((port) << 2));             \
-})
-
-#define __inbc(port)                                                           \
-({                                                                             \
-       unsigned char result;                                                   \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldrb   %0, [%1, %2]    @ inbc"                                 \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldrb   %0, [%1, %2]    @ inbc"                                 \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result;                                                                 \
-})
-
-#define __outwc(value,port)                                                    \
-({                                                                             \
-       unsigned long v = value;                                                \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]    @ outwc"                                \
-               : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2));        \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]    @ outwc"                                \
-               : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2));           \
-})
-
-#define __inwc(port)                                                           \
-({                                                                             \
-       unsigned short result;                                                  \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]    @ inwc"                                 \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]    @ inwc"                                 \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result & 0xffff;                                                        \
-})
-
-#define __outlc(value,port)                                                    \
-({                                                                             \
-       unsigned long v = value;                                                \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]    @ outlc"                                \
-               : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2));              \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "str    %0, [%1, %2]    @ outlc"                                \
-               : : "r" (v), "r" (IO_BASE), "r" ((port) << 2));                 \
-})
-
-#define __inlc(port)                                                           \
-({                                                                             \
-       unsigned long result;                                                   \
-       if (__PORT_PCIO((port)))                                                \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]    @ inlc"                                 \
-               : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2));         \
-       else                                                                    \
-               __asm__ __volatile__(                                           \
-               "ldr    %0, [%1, %2]    @ inlc"                                 \
-               : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2));            \
-       result;                                                                 \
-})
-
-#define __ioaddrc(port)                                                                \
-       (__PORT_PCIO((port)) ? PCIO_BASE + ((port) << 2) : IO_BASE + ((port) << 2))
-
-#define inb(p)         (__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
-#define inw(p)         (__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
-#define inl(p)         (__builtin_constant_p((p)) ? __inlc(p)    : __inl(p))
-#define outb(v,p)      (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
-#define outw(v,p)      (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
-#define outl(v,p)      (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-#define __ioaddr(p)    (__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
-/* the following macro is deprecated */
-#define ioaddr(port)                   __ioaddr((port))
-
-#define insb(p,d,l)    __raw_readsb(__ioaddr(p),d,l)
-#define insw(p,d,l)    __raw_readsw(__ioaddr(p),d,l)
-
-#define outsb(p,d,l)   __raw_writesb(__ioaddr(p),d,l)
-#define outsw(p,d,l)   __raw_writesw(__ioaddr(p),d,l)
-
-/*
- * 1:1 mapping for ioremapped regions.
- */
-#define __mem_pci(x)   (x)
-
-#endif
diff --git a/arch/arm/mach-clps7500/include/mach/irq.h b/arch/arm/mach-clps7500/include/mach/irq.h
deleted file mode 100644 (file)
index d02fcf2..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/irq.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1999, 2001 Nexus Electronics Ltd.
- *
- * Changelog:
- *   10-10-1996        RMK     Brought up to date with arch-sa110eval
- *   22-08-1998        RMK     Restructured IRQ routines
- *   11-08-1999        PJB     Created ARM7500 version, derived from RiscPC code
- */
-
-#include <linux/io.h>
-#include <asm/hardware/iomd.h>
-
-static inline int fixup_irq(unsigned int irq)
-{
-       if (irq == IRQ_ISA) {
-               int isabits = *((volatile unsigned int *)0xe002b700);
-               if (isabits == 0) {
-                       printk("Spurious ISA IRQ!\n");
-                       return irq;
-               }
-               irq = IRQ_ISA_BASE;
-               while (!(isabits & 1)) {
-                       irq++;
-                       isabits >>= 1;
-               }
-       }
-
-       return irq;
-}
diff --git a/arch/arm/mach-clps7500/include/mach/irqs.h b/arch/arm/mach-clps7500/include/mach/irqs.h
deleted file mode 100644 (file)
index bee66b4..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/irqs.h
- *
- * Copyright (C) 1999 Nexus Electronics Ltd
- */
-
-#define IRQ_INT2               0
-#define IRQ_INT1               2
-#define IRQ_VSYNCPULSE         3
-#define IRQ_POWERON            4
-#define IRQ_TIMER0             5
-#define IRQ_TIMER1             6
-#define IRQ_FORCE              7
-#define IRQ_INT8               8
-#define IRQ_ISA                        9
-#define IRQ_INT6               10
-#define IRQ_INT5               11
-#define IRQ_INT4               12
-#define IRQ_INT3               13
-#define IRQ_KEYBOARDTX         14
-#define IRQ_KEYBOARDRX         15
-
-#define IRQ_DMA0               16
-#define IRQ_DMA1               17
-#define IRQ_DMA2               18
-#define IRQ_DMA3               19
-#define IRQ_DMAS0              20
-#define IRQ_DMAS1              21
-
-#define IRQ_IOP0               24
-#define IRQ_IOP1               25
-#define IRQ_IOP2               26
-#define IRQ_IOP3               27
-#define IRQ_IOP4               28
-#define IRQ_IOP5               29
-#define IRQ_IOP6               30
-#define IRQ_IOP7               31
-
-#define IRQ_MOUSERX            40
-#define IRQ_MOUSETX            41
-#define IRQ_ADC                        42
-#define IRQ_EVENT1             43
-#define IRQ_EVENT2             44
-
-#define IRQ_ISA_BASE           48
-#define IRQ_ISA_3              48
-#define IRQ_ISA_4              49
-#define IRQ_ISA_5              50
-#define IRQ_ISA_7              51
-#define IRQ_ISA_9              52
-#define IRQ_ISA_10             53
-#define IRQ_ISA_11             54
-#define IRQ_ISA_14             55      
-
-#define FIQ_INT9               0
-#define FIQ_INT5               1
-#define FIQ_INT6               4
-#define FIQ_INT8               6
-#define FIQ_FORCE              7
-
-/*
- * This is the offset of the FIQ "IRQ" numbers
- */
-#define FIQ_START              64
-
-#define IRQ_TIMER              IRQ_TIMER0
diff --git a/arch/arm/mach-clps7500/include/mach/memory.h b/arch/arm/mach-clps7500/include/mach/memory.h
deleted file mode 100644 (file)
index 87b32db..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/memory.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-Oct-1996        RMK     Created
- *  31-Dec-1997        RMK     Fixed definitions to reduce warnings
- *  11-Jan-1998        RMK     Uninlined to reduce hits on cache
- *  08-Feb-1998        RMK     Added __virt_to_bus and __bus_to_virt
- *  21-Mar-1999        RMK     Renamed to memory.h
- *             RMK     Added TASK_SIZE and PAGE_OFFSET
- */
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-/*
- * Physical DRAM offset.
- */
-#define PHYS_OFFSET    UL(0x10000000)
-
-/*
- * These are exactly the same on the RiscPC as the
- * physical memory view.
- */
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
-/*
- * Cache flushing area - ROM
- */
-#define FLUSH_BASE_PHYS                0x00000000
-#define FLUSH_BASE             0xdf000000
-
-/*
- * Sparsemem support.  Each section is a maximum of 64MB.  The sections
- * are offset by 128MB and can cover 128MB, so that gives us a maximum
- * of 29 physmem bits.
- */
-#define MAX_PHYSMEM_BITS       29
-#define SECTION_SIZE_BITS      26
-
-#endif
diff --git a/arch/arm/mach-clps7500/include/mach/system.h b/arch/arm/mach-clps7500/include/mach/system.h
deleted file mode 100644 (file)
index 6d325fb..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/system.h
- *
- * Copyright (c) 1999 Nexus Electronics Ltd.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <linux/io.h>
-#include <asm/hardware/iomd.h>
-
-static inline void arch_idle(void)
-{
-       iomd_writeb(0, IOMD_SUSMODE);
-}
-
-#define arch_reset(mode)                       \
-       do {                                    \
-               iomd_writeb(0, IOMD_ROMCR0);    \
-               cpu_reset(0);                   \
-       } while (0)
-
-#endif
diff --git a/arch/arm/mach-clps7500/include/mach/timex.h b/arch/arm/mach-clps7500/include/mach/timex.h
deleted file mode 100644 (file)
index dfaa9b4..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/timex.h
- *
- * CL7500 architecture timex specifications
- *
- * Copyright (C) 1999 Nexus Electronics Ltd
- */
-
-/*
- * On the ARM7500, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE                2000000
-
diff --git a/arch/arm/mach-clps7500/include/mach/uncompress.h b/arch/arm/mach-clps7500/include/mach/uncompress.h
deleted file mode 100644 (file)
index d7d0af4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/uncompress.h
- *
- * Copyright (C) 1999, 2000 Nexus Electronics Ltd.
- */
-#define BASE 0x03010000
-#define SERBASE (BASE + (0x2f8 << 2))
-
-static inline void putc(char c)
-{
-       while (!(*((volatile unsigned int *)(SERBASE + 0x14)) & 0x20))
-               barrier();
-
-       *((volatile unsigned int *)(SERBASE)) = c;
-}
-
-static inline void flush(void)
-{
-}
-
-static __inline__ void arch_decomp_setup(void)
-{
-       int baud = 3686400 / (9600 * 32);
-
-       *((volatile unsigned int *)(SERBASE + 0xC)) = 0x80;
-       *((volatile unsigned int *)(SERBASE + 0x0)) = baud & 0xff;
-       *((volatile unsigned int *)(SERBASE + 0x4)) = (baud & 0xff00) >> 8;
-       *((volatile unsigned int *)(SERBASE + 0xC)) = 3; /* 8 bits */
-       *((volatile unsigned int *)(SERBASE + 0x10)) = 3; /* DTR, RTS */
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-clps7500/include/mach/vmalloc.h b/arch/arm/mach-clps7500/include/mach/vmalloc.h
deleted file mode 100644 (file)
index 8fc5406..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/*
- * arch/arm/mach-clps7500/include/mach/vmalloc.h
- */
-#define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
diff --git a/arch/arm/mach-davinci/include/mach/dma.h b/arch/arm/mach-davinci/include/mach/dma.h
deleted file mode 100644 (file)
index 8e2f2d0..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * DaVinci DMA definitions
- *
- * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
- *
- * 2007 (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.
- */
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS                        0xffffffff
-
-#endif /* __ASM_ARCH_DMA_H */
index b78ee9140496df8ef2f00fc3bf55986e3b211c2b..a48795fd24173f743ff859ef6ded883d7abf2ca9 100644 (file)
@@ -29,8 +29,7 @@
  * We don't actually have real ISA nor PCI buses, but there is so many
  * drivers out there that might just work if we fake them...
  */
-#define PCIO_BASE               0
-#define __io(a)                        ((void __iomem *)(PCIO_BASE + (a)))
+#define __io(a)                        __typesafe_io(a)
 #define __mem_pci(a)           (a)
 #define __mem_isa(a)           (a)
 
index dd1625c23cf43964c89a7eeca5f428ceabbba43a..86c25c7f3ce30f2014a98d50511ab3dc048c9e6f 100644 (file)
@@ -52,13 +52,8 @@ __arch_adjust_zones(int node, unsigned long *size, unsigned long *holes)
         if ((meminfo.bank[0].size >> 20) > 128) __arch_adjust_zones(node, zone_size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + (128<<20) - 1)
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + (128<<20))
 
 #endif
 
-/*
- * Bus address is physical address
- */
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
 #endif /* __ASM_ARCH_MEMORY_H */
index b98bd9e92fd687b48a660a92edb0814cd1123d3c..ad51625b66096f271037f1756632e65ba3408098 100644 (file)
@@ -8,7 +8,6 @@
  * is licensed "as is" without any warranty of any kind, whether express
  * or implied.
  */
-#include <asm/memory.h>
 #include <mach/io.h>
 
 /* Allow vmalloc range until the IO virtual range minus a 2M "hole" */
diff --git a/arch/arm/mach-ebsa110/include/mach/dma.h b/arch/arm/mach-ebsa110/include/mach/dma.h
deleted file mode 100644 (file)
index 780a04c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- *  arch/arm/mach-ebsa110/include/mach/dma.h
- *
- *  Copyright (C) 1997,1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  EBSA110 DMA definitions
- */
index eea4b75b657bb730cf978e633a0d1ef395c33d48..0ca66d080c6959245c3c0f38e574f849bbf41b73 100644 (file)
  */
 #define PHYS_OFFSET    UL(0x00000000)
 
-/*
- * We keep this 1:1 so that we don't interfere
- * with the PCMCIA memory regions
- */
-#define __virt_to_bus(x)       (x)
-#define __bus_to_virt(x)       (x)
-
 /*
  * Cache flushing area - SRAM
  */
index 5a1b8c05c9584af2850076060d387ee18682b4db..56bddcef6905fac93749b3520ef3eb9440283034 100644 (file)
@@ -33,6 +33,12 @@ config MACH_EDB9307
          Say 'Y' here if you want your kernel to support the Cirrus
          Logic EDB9307 Evaluation Board.
 
+config MACH_EDB9307A
+       bool "Support Cirrus Logic EDB9307A"
+       help
+         Say 'Y' here if you want your kernel to support the Cirrus
+         Logic EDB9307A Evaluation Board.
+
 config MACH_EDB9312
        bool "Support Cirrus Logic EDB9312"
        help
index c1252ca9648e9d9dcb2b91d6338cba448e94c8da..944e42d51646d224a2576f1c2739c315941f5f88 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_MACH_ADSSPHERE)  += adssphere.o
 obj-$(CONFIG_MACH_EDB9302)     += edb9302.o
 obj-$(CONFIG_MACH_EDB9302A)    += edb9302a.o
 obj-$(CONFIG_MACH_EDB9307)     += edb9307.o
+obj-$(CONFIG_MACH_EDB9307A)    += edb9307a.o
 obj-$(CONFIG_MACH_EDB9312)     += edb9312.o
 obj-$(CONFIG_MACH_EDB9315)     += edb9315.o
 obj-$(CONFIG_MACH_EDB9315A)    += edb9315a.o
index 561db73ec1ae1c559fc0c2c2528c308f495b5c5f..3fbd9b0fbe24e634795d4ca069051d4917b0e689 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data adssphere_flash_data = {
 };
 
 static struct resource adssphere_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x61ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -59,7 +60,7 @@ MACHINE_START(ADSSPHERE, "ADS Sphere board")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 8c9f2491dccc545f5abb614663c1c34aa1d5098e..96049283a10a56980fb6979da2e9e6aada13ed92 100644 (file)
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/io.h>
+
+#include <asm/clkdev.h>
 #include <asm/div64.h>
 #include <mach/hardware.h>
 
 struct clk {
-       char            *name;
        unsigned long   rate;
        int             users;
        u32             enable_reg;
@@ -28,53 +29,33 @@ struct clk {
 };
 
 static struct clk clk_uart = {
-       .name           = "UARTCLK",
        .rate           = 14745600,
 };
-static struct clk clk_pll1 = {
-       .name           = "pll1",
-};
-static struct clk clk_f = {
-       .name           = "fclk",
-};
-static struct clk clk_h = {
-       .name           = "hclk",
-};
-static struct clk clk_p = {
-       .name           = "pclk",
-};
-static struct clk clk_pll2 = {
-       .name           = "pll2",
-};
+static struct clk clk_pll1;
+static struct clk clk_f;
+static struct clk clk_h;
+static struct clk clk_p;
+static struct clk clk_pll2;
 static struct clk clk_usb_host = {
-       .name           = "usb_host",
        .enable_reg     = EP93XX_SYSCON_CLOCK_CONTROL,
        .enable_mask    = EP93XX_SYSCON_CLOCK_USH_EN,
 };
 
-
-static struct clk *clocks[] = {
-       &clk_uart,
-       &clk_pll1,
-       &clk_f,
-       &clk_h,
-       &clk_p,
-       &clk_pll2,
-       &clk_usb_host,
+#define INIT_CK(dev,con,ck)                                    \
+       { .dev_id = dev, .con_id = con, .clk = ck }
+
+static struct clk_lookup clocks[] = {
+       INIT_CK("apb:uart1", NULL, &clk_uart),
+       INIT_CK("apb:uart2", NULL, &clk_uart),
+       INIT_CK("apb:uart3", NULL, &clk_uart),
+       INIT_CK(NULL, "pll1", &clk_pll1),
+       INIT_CK(NULL, "fclk", &clk_f),
+       INIT_CK(NULL, "hclk", &clk_h),
+       INIT_CK(NULL, "pclk", &clk_p),
+       INIT_CK(NULL, "pll2", &clk_pll2),
+       INIT_CK(NULL, "usb_host", &clk_usb_host),
 };
 
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(clocks); i++) {
-               if (!strcmp(clocks[i]->name, id))
-                       return clocks[i];
-       }
-
-       return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
 
 int clk_enable(struct clk *clk)
 {
@@ -106,12 +87,6 @@ unsigned long clk_get_rate(struct clk *clk)
 }
 EXPORT_SYMBOL(clk_get_rate);
 
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
-
 
 static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
 static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
@@ -138,6 +113,7 @@ static unsigned long calc_pll_rate(u32 config_word)
 static int __init ep93xx_clock_init(void)
 {
        u32 value;
+       int i;
 
        value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
        if (!(value & 0x00800000)) {                    /* PLL1 bypassed?  */
@@ -165,6 +141,8 @@ static int __init ep93xx_clock_init(void)
                clk_f.rate / 1000000, clk_h.rate / 1000000,
                clk_p.rate / 1000000);
 
+       for (i = 0; i < ARRAY_SIZE(clocks); i++)
+               clkdev_add(&clocks[i]);
        return 0;
 }
 arch_initcall(ep93xx_clock_init);
index 48345fb34613434d2fa6c0e3b7bbd7dcb0a529c4..4781f323703bdcf782914999ad576acc9a2227e9 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -153,12 +155,14 @@ static unsigned char gpio_int_unmasked[3];
 static unsigned char gpio_int_enabled[3];
 static unsigned char gpio_int_type1[3];
 static unsigned char gpio_int_type2[3];
+static unsigned char gpio_int_debouce[3];
 
 /* Port ordering is: A B F */
 static const u8 int_type1_register_offset[3]   = { 0x90, 0xac, 0x4c };
 static const u8 int_type2_register_offset[3]   = { 0x94, 0xb0, 0x50 };
 static const u8 eoi_register_offset[3]         = { 0x98, 0xb4, 0x54 };
 static const u8 int_en_register_offset[3]      = { 0x9c, 0xb8, 0x58 };
+static const u8 int_debounce_register_offset[3]        = { 0xa8, 0xc4, 0x64 };
 
 void ep93xx_gpio_update_int_params(unsigned port)
 {
@@ -181,6 +185,22 @@ void ep93xx_gpio_int_mask(unsigned line)
        gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
 }
 
+void ep93xx_gpio_int_debounce(unsigned int irq, int enable)
+{
+       int line = irq_to_gpio(irq);
+       int port = line >> 3;
+       int port_mask = 1 << (line & 7);
+
+       if (enable)
+               gpio_int_debouce[port] |= port_mask;
+       else
+               gpio_int_debouce[port] &= ~port_mask;
+
+       __raw_writeb(gpio_int_debouce[port],
+               EP93XX_GPIO_REG(int_debounce_register_offset[port]));
+}
+EXPORT_SYMBOL(ep93xx_gpio_int_debounce);
+
 /*************************************************************************
  * EP93xx IRQ handling
  *************************************************************************/
@@ -497,6 +517,26 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
        platform_device_register(&ep93xx_eth_device);
 }
 
+static struct i2c_gpio_platform_data ep93xx_i2c_data = {
+       .sda_pin                = EP93XX_GPIO_LINE_EEDAT,
+       .sda_is_open_drain      = 0,
+       .scl_pin                = EP93XX_GPIO_LINE_EECLK,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 2,
+};
+
+static struct platform_device ep93xx_i2c_device = {
+       .name                   = "i2c-gpio",
+       .id                     = 0,
+       .dev.platform_data      = &ep93xx_i2c_data,
+};
+
+void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num)
+{
+       i2c_register_board_info(0, devices, num);
+       platform_device_register(&ep93xx_i2c_device);
+}
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
index e4add5bdccfd71532c1c5b26b2a02fd09aca3d06..8bf8d7c78f1a9e484eb9ee36cc2ecf28e44ebed4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data edb9302_flash_data = {
 };
 
 static struct resource edb9302_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x60ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -59,7 +60,7 @@ MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
        /* Maintainer: George Kashperko <george@chas.com.ua> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 02c4405afed7969fbf372f2be5d83f3788f7e61e..a352c57c7b46489a28ebb09f6d4c4bb2ad99f85e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data edb9302a_flash_data = {
 };
 
 static struct resource edb9302a_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x60ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -44,7 +45,7 @@ static struct platform_device edb9302a_flash = {
 };
 
 static struct ep93xx_eth_data edb9302a_eth_data = {
-       .phy_id                 = 1,
+       .phy_id         = 1,
 };
 
 static void __init edb9302a_init_machine(void)
@@ -59,7 +60,7 @@ MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0xc0000100,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 040edbd2ea053d92437e42129bcea91b9b684123..5ab22f63a4ebb947e84887bbe62c49d98ce551ec 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data edb9307_flash_data = {
 };
 
 static struct resource edb9307_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x61ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -44,7 +45,7 @@ static struct platform_device edb9307_flash = {
 };
 
 static struct ep93xx_eth_data edb9307_eth_data = {
-       .phy_id                 = 1,
+       .phy_id         = 1,
 };
 
 static void __init edb9307_init_machine(void)
@@ -59,7 +60,7 @@ MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
        /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
diff --git a/arch/arm/mach-ep93xx/edb9307a.c b/arch/arm/mach-ep93xx/edb9307a.c
new file mode 100644 (file)
index 0000000..5b5c22b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * arch/arm/mach-ep93xx/edb9307a.c
+ * Cirrus Logic EDB9307A support.
+ *
+ * Copyright (C) 2008 H Hartley Sweeten <hsweeten@visionengravers.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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data edb9307a_flash_data = {
+       .width          = 2,
+};
+
+static struct resource edb9307a_flash_resource = {
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device edb9307a_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &edb9307a_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &edb9307a_flash_resource,
+};
+
+static struct ep93xx_eth_data edb9307a_eth_data = {
+       .phy_id         = 1,
+};
+
+static void __init edb9307a_init_machine(void)
+{
+       ep93xx_init_devices();
+       platform_device_register(&edb9307a_flash);
+
+       ep93xx_register_eth(&edb9307a_eth_data, 1);
+}
+
+MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
+       /* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = edb9307a_init_machine,
+MACHINE_END
index 6853e302bc3a8f8bad7362a94b8ac0ebd07a1e86..d7179f66d804999957f325241d2b67cbbe453028 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -29,8 +30,8 @@ static struct physmap_flash_data edb9312_flash_data = {
 };
 
 static struct resource edb9312_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x61ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -45,7 +46,7 @@ static struct platform_device edb9312_flash = {
 };
 
 static struct ep93xx_eth_data edb9312_eth_data = {
-       .phy_id                 = 1,
+       .phy_id         = 1,
 };
 
 static void __init edb9312_init_machine(void)
@@ -60,7 +61,7 @@ MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
        /* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 9469b350d253ba6c291b3b7cc15c1c847e8e8e76..025af6eaca1033ae9ebd49088b3d81e27521864c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data edb9315_flash_data = {
 };
 
 static struct resource edb9315_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x61ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_32M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -44,7 +45,7 @@ static struct platform_device edb9315_flash = {
 };
 
 static struct ep93xx_eth_data edb9315_eth_data = {
-       .phy_id                 = 1,
+       .phy_id         = 1,
 };
 
 static void __init edb9315_init_machine(void)
@@ -59,7 +60,7 @@ MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 584457ce7c80f410e71b8323de5a94d668722569..4c9cc8a39f5c5eb5e46f5eef4cd1d74912c24584 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data edb9315a_flash_data = {
 };
 
 static struct resource edb9315a_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x60ffffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_16M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -44,7 +45,7 @@ static struct platform_device edb9315a_flash = {
 };
 
 static struct ep93xx_eth_data edb9315a_eth_data = {
-       .phy_id                 = 1,
+       .phy_id         = 1,
 };
 
 static void __init edb9315a_init_machine(void)
@@ -59,7 +60,7 @@ MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0xc0000100,
+       .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 035b24e31b64a99f0264a7c3ab460299a89f8976..3bad500b71b692adad98db5fd33b286b55da3023 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -28,8 +29,8 @@ static struct physmap_flash_data gesbc9312_flash_data = {
 };
 
 static struct resource gesbc9312_flash_resource = {
-       .start          = 0x60000000,
-       .end            = 0x607fffff,
+       .start          = EP93XX_CS6_PHYS_BASE,
+       .end            = EP93XX_CS6_PHYS_BASE + SZ_8M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -59,7 +60,7 @@ MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
diff --git a/arch/arm/mach-ep93xx/include/mach/clkdev.h b/arch/arm/mach-ep93xx/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/dma.h b/arch/arm/mach-ep93xx/include/mach/dma.h
deleted file mode 100644 (file)
index d0fa965..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/dma.h
- */
index f7020414c5df20a1414d3b773962e123cbf562d5..0a1498ae899aea4e114e855989010bd3b2d6da51 100644 (file)
@@ -99,6 +99,8 @@
 /* maximum value for irq capable line identifiers */
 #define EP93XX_GPIO_LINE_MAX_IRQ       EP93XX_GPIO_LINE_F(7)
 
+extern void ep93xx_gpio_int_debounce(unsigned int irq, int enable);
+
 /* new generic GPIO API - see Documentation/gpio.txt */
 
 #include <asm-generic/gpio.h>
index 1ab9a90ad33949b4dee55331eff8762fd21e59fe..fd5f081cc8b7263e01cf40c3e8473f19a3763998 100644 (file)
@@ -4,5 +4,5 @@
 
 #define IO_SPACE_LIMIT         0xffffffff
 
-#define __io(p)                        ((void __iomem *)(p))
-#define __mem_pci(p)           (p)
+#define __io(p)                __typesafe_io(p)
+#define __mem_pci(p)   (p)
index f1b6335907528401dee36181bae3c01b79869211..5c80c3c8158dc01145f14cd2964b2e25463ee3e4 100644 (file)
@@ -7,8 +7,4 @@
 
 #define PHYS_OFFSET            UL(0x00000000)
 
-#define __bus_to_virt(x)       __phys_to_virt(x)
-#define __virt_to_bus(x)       __virt_to_phys(x)
-
-
 #endif
index db2489d3bda74abe02b6af72223e8b9042ffc7b1..88f7e88f152f07d28c81faa0374b68be974f6533 100644 (file)
@@ -14,6 +14,7 @@ void ep93xx_map_io(void);
 void ep93xx_init_irq(void);
 void ep93xx_init_time(unsigned long);
 void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
+void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
 
index c2197236b63285190d99bcd0fa80225b84e67eac..15d6815d78c412b030f7d50a9b9de27de87de7cc 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <linux/mtd/physmap.h>
 
 #include <mach/hardware.h>
@@ -25,7 +26,7 @@
 #include <asm/mach-types.h>
 
 static struct ep93xx_eth_data micro9_eth_data = {
-       .phy_id                 = 0x1f,
+       .phy_id         = 0x1f,
 };
 
 static void __init micro9_init(void)
@@ -38,46 +39,46 @@ static void __init micro9_init(void)
  */
 #ifdef CONFIG_MACH_MICRO9H
 static struct physmap_flash_data micro9h_flash_data = {
-       .width          = 4,
+       .width          = 4,
 };
 
 static struct resource micro9h_flash_resource = {
-       .start          = 0x10000000,
-       .end            = 0x13ffffff,
-       .flags          = IORESOURCE_MEM,
+       .start          = EP93XX_CS1_PHYS_BASE,
+       .end            = EP93XX_CS1_PHYS_BASE + SZ_64M - 1,
+       .flags          = IORESOURCE_MEM,
 };
 
 static struct platform_device micro9h_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-               .platform_data  = &micro9h_flash_data,
-       },
-       .num_resources  = 1,
-       .resource       = &micro9h_flash_resource,
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &micro9h_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &micro9h_flash_resource,
 };
 
 static void __init micro9h_init(void)
 {
-       platform_device_register(&micro9h_flash);
+       platform_device_register(&micro9h_flash);
 }
 
 static void __init micro9h_init_machine(void)
 {
-       ep93xx_init_devices();
-       micro9_init();
-       micro9h_init();
+       ep93xx_init_devices();
+       micro9_init();
+       micro9h_init();
 }
 
 MACHINE_START(MICRO9, "Contec Hypercontrol Micro9-H")
-       /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = micro9h_init_machine,
+       /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = micro9h_init_machine,
 MACHINE_END
 #endif
 
@@ -87,19 +88,19 @@ MACHINE_END
 #ifdef CONFIG_MACH_MICRO9M
 static void __init micro9m_init_machine(void)
 {
-       ep93xx_init_devices();
-       micro9_init();
+       ep93xx_init_devices();
+       micro9_init();
 }
 
 MACHINE_START(MICRO9M, "Contec Hypercontrol Micro9-M")
-       /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = micro9m_init_machine,
+       /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = micro9m_init_machine,
 MACHINE_END
 #endif
 
@@ -109,19 +110,19 @@ MACHINE_END
 #ifdef CONFIG_MACH_MICRO9L
 static void __init micro9l_init_machine(void)
 {
-       ep93xx_init_devices();
-       micro9_init();
+       ep93xx_init_devices();
+       micro9_init();
 }
 
 MACHINE_START(MICRO9L, "Contec Hypercontrol Micro9-L")
-       /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
-       .map_io         = ep93xx_map_io,
-       .init_irq       = ep93xx_init_irq,
-       .timer          = &ep93xx_timer,
-       .init_machine   = micro9l_init_machine,
+       /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
+       .phys_io        = EP93XX_APB_PHYS_BASE,
+       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+       .map_io         = ep93xx_map_io,
+       .init_irq       = ep93xx_init_irq,
+       .timer          = &ep93xx_timer,
+       .init_machine   = micro9l_init_machine,
 MACHINE_END
 #endif
 
index b4aa4c0542769ebe4fd4409a938c98c315f7cc58..7ee024d3482984a339f854bc60df755a5ea4c781 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/m48t86.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -117,7 +118,7 @@ static struct physmap_flash_data ts72xx_flash_data = {
 
 static struct resource ts72xx_flash_resource = {
        .start          = TS72XX_NOR_PHYS_BASE,
-       .end            = TS72XX_NOR_PHYS_BASE + 0x00ffffff,
+       .end            = TS72XX_NOR_PHYS_BASE + SZ_16M - 1,
        .flags          = IORESOURCE_MEM,
 };
 
@@ -144,21 +145,21 @@ static void ts72xx_rtc_writebyte(unsigned char value, unsigned long addr)
 }
 
 static struct m48t86_ops ts72xx_rtc_ops = {
-       .readbyte               = ts72xx_rtc_readbyte,
-       .writebyte              = ts72xx_rtc_writebyte,
+       .readbyte       = ts72xx_rtc_readbyte,
+       .writebyte      = ts72xx_rtc_writebyte,
 };
 
 static struct platform_device ts72xx_rtc_device = {
-       .name                   = "rtc-m48t86",
-       .id                     = -1,
-       .dev                    = {
-               .platform_data          = &ts72xx_rtc_ops,
+       .name           = "rtc-m48t86",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &ts72xx_rtc_ops,
        },
-       .num_resources          = 0,
+       .num_resources  = 0,
 };
 
 static struct ep93xx_eth_data ts72xx_eth_data = {
-       .phy_id                 = 1,
+       .phy_id         = 1,
 };
 
 static void __init ts72xx_init_machine(void)
@@ -175,7 +176,7 @@ MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
        .phys_io        = EP93XX_APB_PHYS_BASE,
        .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
        .map_io         = ts72xx_map_io,
        .init_irq       = ep93xx_init_irq,
        .timer          = &ep93xx_timer,
index 6a5b437ab86ffdfd03c66527ea2331bfa4f4c7d9..1b996b26d2e0d06ee020a2fe2e763874536a9920 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 #include <linux/screen_info.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach-types.h>
index 818014e09f4a6e8cb0b679a9ea5aef4fd4928ea9..36ff06d4df15e30ba0272ee5645a811aa0f6b9cf 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/list.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
  
 #include <asm/pgtable.h>
 #include <asm/page.h>
index b2a21189dd81b620fe4e758d9a9cecc23d29a9eb..da35bc5c5ccc527a139852843fd3702efb8e116f 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/spinlock.h>
 
 #include <asm/irq.h>
 
index d4c1e526f59c4cd8071f78e17e06258f42e4cd79..133086019e3ea776b98c236a9bebc3a86146a9c0 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/ioport.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <asm/irq.h>
 #include <asm/system.h>
index b653e9cfa3f7761ee9d988a213223c71470eb706..4f3506346969d6214dd12004e48c057f31bd6b07 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <asm/dma.h>
 #include <asm/scatterlist.h>
index b1d3bf20a41e4b1d3251d716bd66280dccee5a72..30040fd588cc01661de7b4c01519c9d330e9f014 100644 (file)
@@ -4,6 +4,7 @@
  * EBSA285 machine fixup
  */
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach-types.h>
index ffaea90486f91dc98b9b5c60bd43d47e4ebd9794..51dd902043adb4895a968630c73450f69b005d76 100644 (file)
@@ -12,8 +12,6 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <mach/memory.h>
-
 /*   Virtual      Physical     Size
  * 0xff800000  0x40000000      1MB     X-Bus
  * 0xff000000  0x7c000000      1MB     PCI I/O space
@@ -28,9 +26,6 @@
 #define XBUS_SIZE              0x00100000
 #define XBUS_BASE              0xff800000
 
-#define PCIO_SIZE              0x00100000
-#define PCIO_BASE              0xff000000
-
 #define ARMCSR_SIZE            0x00100000
 #define ARMCSR_BASE            0xfe000000
 
 #define CPLD_FLASH_WR_ENABLE   1
 
 #ifndef __ASSEMBLY__
-extern void gpio_modify_op(int mask, int set);
-extern void gpio_modify_io(int mask, int in);
-extern int  gpio_read(void);
-extern void cpld_modify(int mask, int set);
+extern spinlock_t nw_gpio_lock;
+extern void nw_gpio_modify_op(unsigned int mask, unsigned int set);
+extern void nw_gpio_modify_io(unsigned int mask, unsigned int in);
+extern unsigned int nw_gpio_read(void);
+extern void nw_cpld_modify(unsigned int mask, unsigned int set);
 #endif
 
 #define pcibios_assign_all_busses()    1
index a7b066239996880bbeaec451dfb1386ce7fe452a..101a4fe90bdec17cc4cf7fa563979fa93c22a5f0 100644 (file)
@@ -14,7 +14,8 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
+#define PCIO_SIZE              0x00100000
+#define PCIO_BASE              0xff000000
 
 #define IO_SPACE_LIMIT 0xffff
 
similarity index 91%
rename from arch/arm/mach-footbridge/include/mach/dma.h
rename to arch/arm/mach-footbridge/include/mach/isa-dma.h
index 62afd213effb2818ea30a1245e8e616cc36672dc..5bd4a0d338a8ff351e7125c206a11a53c66fc76d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  arch/arm/mach-footbridge/include/mach/dma.h
+ *  arch/arm/mach-footbridge/include/mach/isa-dma.h
  *
  *  Architecture DMA routines
  *
index 6ae2f1a07ab90b585e122ee8596cbd4f3f7b4b6a..cb16e59d87b63c81f807b67c65b013fa7c11e763 100644 (file)
 extern unsigned long __virt_to_bus(unsigned long);
 extern unsigned long __bus_to_virt(unsigned long);
 #endif
+#define __virt_to_bus  __virt_to_bus
+#define __bus_to_virt  __bus_to_virt
 
 #elif defined(CONFIG_FOOTBRIDGE_HOST)
 
+/*
+ * The footbridge is programmed to expose the system RAM at the corresponding
+ * address.  So, if PAGE_OFFSET is 0xc0000000, RAM appears at 0xe0000000.
+ * If 0x80000000, then its exposed at 0xa0000000 on the bus. etc.
+ * The only requirement is that the RAM isn't placed at bus address 0 which
+ * would clash with VGA cards.
+ */
 #define __virt_to_bus(x)       ((x) - 0xe0000000)
 #define __bus_to_virt(x)       ((x) + 0xe0000000)
 
index 54fec9ae28b949b36a17c79de56f9b558f118ee6..9ee80a211d3cb670e71c8fcb58127193485dc392 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/list.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <asm/mach/irq.h>
 
index 00b0ddcac28347107cb932f18b0e7d4bb03236af..ac7ffa6fc413e78a93a4e308cf1b137a39adc4fd 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/leds.h>
@@ -67,13 +68,14 @@ static inline void wb977_ww(int reg, int val)
 /*
  * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE
  */
-DEFINE_SPINLOCK(gpio_lock);
+DEFINE_SPINLOCK(nw_gpio_lock);
+EXPORT_SYMBOL(nw_gpio_lock);
 
 static unsigned int current_gpio_op;
 static unsigned int current_gpio_io;
 static unsigned int current_cpld;
 
-void gpio_modify_op(int mask, int set)
+void nw_gpio_modify_op(unsigned int mask, unsigned int set)
 {
        unsigned int new_gpio, changed;
 
@@ -86,6 +88,7 @@ void gpio_modify_op(int mask, int set)
        if (changed & 0xff00)
                outb(new_gpio >> 8, GP2_IO_BASE);
 }
+EXPORT_SYMBOL(nw_gpio_modify_op);
 
 static inline void __gpio_modify_io(int mask, int in)
 {
@@ -118,7 +121,7 @@ static inline void __gpio_modify_io(int mask, int in)
        }
 }
 
-void gpio_modify_io(int mask, int in)
+void nw_gpio_modify_io(unsigned int mask, unsigned int in)
 {
        /* Open up the SuperIO chip */
        wb977_open();
@@ -128,11 +131,13 @@ void gpio_modify_io(int mask, int in)
        /* Close up the EFER gate */
        wb977_close();
 }
+EXPORT_SYMBOL(nw_gpio_modify_io);
 
-int gpio_read(void)
+unsigned int nw_gpio_read(void)
 {
        return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8;
 }
+EXPORT_SYMBOL(nw_gpio_read);
 
 /*
  * Initialise the Winbond W83977F global registers
@@ -322,9 +327,9 @@ static inline void wb977_init_gpio(void)
        /*
         * Set Group1/Group2 outputs
         */
-       spin_lock_irqsave(&gpio_lock, flags);
-       gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       nw_gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
 }
 
 /*
@@ -359,34 +364,35 @@ static void __init wb977_init(void)
        wb977_close();
 }
 
-void cpld_modify(int mask, int set)
+void nw_cpld_modify(unsigned int mask, unsigned int set)
 {
        int msk;
 
        current_cpld = (current_cpld & ~mask) | set;
 
-       gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0);
-       gpio_modify_op(GPIO_IOLOAD, 0);
+       nw_gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0);
+       nw_gpio_modify_op(GPIO_IOLOAD, 0);
 
        for (msk = 8; msk; msk >>= 1) {
                int bit = current_cpld & msk;
 
-               gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0);
-               gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK);
+               nw_gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0);
+               nw_gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK);
        }
 
-       gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0);
-       gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK);
-       gpio_modify_op(GPIO_IOLOAD, 0);
+       nw_gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0);
+       nw_gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK);
+       nw_gpio_modify_op(GPIO_IOLOAD, 0);
 }
+EXPORT_SYMBOL(nw_cpld_modify);
 
 static void __init cpld_init(void)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&gpio_lock, flags);
-       cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       nw_cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
 }
 
 static unsigned char rwa_unlock[] __initdata =
@@ -596,12 +602,6 @@ static void __init rwa010_init(void)
        rwa010_soundblaster_reset();
 }
 
-EXPORT_SYMBOL(gpio_lock);
-EXPORT_SYMBOL(gpio_modify_op);
-EXPORT_SYMBOL(gpio_modify_io);
-EXPORT_SYMBOL(cpld_modify);
-EXPORT_SYMBOL(gpio_read);
-
 /*
  * Initialise any other hardware after we've got the PCI bus
  * initialised.  We may need the PCI bus to talk to this other
@@ -616,9 +616,9 @@ static int __init nw_hw_init(void)
                cpld_init();
                rwa010_init();
 
-               spin_lock_irqsave(&gpio_lock, flags);
-               gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
-               spin_unlock_irqrestore(&gpio_lock, flags);
+               spin_lock_irqsave(&nw_gpio_lock, flags);
+               nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
+               spin_unlock_irqrestore(&nw_gpio_lock, flags);
        }
        return 0;
 }
index d91a4f4a32dc227161464b47abaa3eaee981e114..00269fe0be8a674c1f6464cdda5a4859737016af 100644 (file)
@@ -32,7 +32,6 @@ static char led_state;
 static char hw_led_state;
 
 static DEFINE_SPINLOCK(leds_lock);
-extern spinlock_t gpio_lock;
 
 static void netwinder_leds_event(led_event_t evt)
 {
@@ -121,9 +120,9 @@ static void netwinder_leds_event(led_event_t evt)
        spin_unlock_irqrestore(&leds_lock, flags);
 
        if  (led_state & LED_STATE_ENABLED) {
-               spin_lock_irqsave(&gpio_lock, flags);
-               gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
-               spin_unlock_irqrestore(&gpio_lock, flags);
+               spin_lock_irqsave(&nw_gpio_lock, flags);
+               nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
+               spin_unlock_irqrestore(&nw_gpio_lock, flags);
        }
 }
 
index c4f843fc099d98c4dd405217e06be5ad6676201b..e2c9f0690b1622b69b5b3e828209ec86160809b6 100644 (file)
@@ -4,6 +4,7 @@
  * Personal server (Skiff) machine fixup
  */
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach-types.h>
index 1dab74ce88c6b831b8586728e9707616e0c770fe..2c8659c21a936889f6048938fa07d0768f38e982 100644 (file)
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)                ((void __iomem *)(a))
+#define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)   (a)
 
 #endif
similarity index 60%
rename from arch/arm/mach-h720x/include/mach/dma.h
rename to arch/arm/mach-h720x/include/mach/isa-dma.h
index 0a9d86ee84fe6cebcf5c189cee09b1179ac98a2f..3eafb3f163c01be0a86af2e932262bbed47d5c98 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-h720x/include/mach/dma.h
+ * arch/arm/mach-h720x/include/mach/isa-dma.h
  *
  * Architecture DMA routes
  *
@@ -8,13 +8,6 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-/*
- * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
- */
-#define MAX_DMA_ADDRESS                0xd0000000
-
 #if defined (CONFIG_CPU_H7201)
 #define MAX_DMA_CHANNELS       3
 #elif defined (CONFIG_CPU_H7202)
index cb26f49cc4e183930c08b7f8941d5ab857c79c56..ef4c1e26f18efbdafe15395f4c0573ec3c4e15b6 100644 (file)
@@ -7,23 +7,13 @@
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
-/*
- * Page offset:
- *    ( 0xc0000000UL )
- */
 #define PHYS_OFFSET    UL(0x40000000)
-
 /*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- *
- * There is something to do here later !, Mar 2000, Jungjun Kim
+ * This is the maximum DMA address that can be DMAd to.
+ * There should not be more than (0xd0000000 - 0xc0000000)
+ * bytes of RAM.
  */
-
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
+#define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_256M - 1)
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_256M)
 
 #endif
index c10810c936b373525c24f836c67c7dc3b07cdaec..1536583eece0d0ed260604e8657b11cc81a323f6 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 
+#include <asm/scatterlist.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/imx-dma.h>
 
 struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
@@ -138,7 +139,7 @@ imx_dma_setup_sg_base(imx_dmach_t dma_ch,
 int
 imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
                     unsigned int dma_length, unsigned int dev_addr,
-                    dmamode_t dmamode)
+                    unsigned int dmamode)
 {
        struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
 
@@ -223,7 +224,7 @@ imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
 int
 imx_dma_setup_sg(imx_dmach_t dma_ch,
                 struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
-                unsigned int dev_addr, dmamode_t dmamode)
+                unsigned int dev_addr, unsigned int dmamode)
 {
        int res;
        struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
index 44d89c35539a50b2bf460ff742fda121cfcd22af..bbe54df7f0deb69af68171b37949ba56107f160e 100644 (file)
@@ -18,7 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 #ifndef __ASM_ARCH_IMX_DMA_H
 #define __ASM_ARCH_IMX_DMA_H
@@ -48,7 +48,7 @@ struct imx_dma_channel {
        void (*irq_handler) (int, void *);
        void (*err_handler) (int, void *, int errcode);
        void *data;
-       dmamode_t  dma_mode;
+       unsigned int  dma_mode;
        struct scatterlist *sg;
        unsigned int sgbc;
        unsigned int sgcount;
@@ -66,14 +66,18 @@ extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS];
 /* The type to distinguish channel numbers parameter from ordinal int type */
 typedef int imx_dmach_t;
 
+#define DMA_MODE_READ          0
+#define DMA_MODE_WRITE         1
+#define DMA_MODE_MASK          1
+
 int
 imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address,
-               unsigned int dma_length, unsigned int dev_addr, dmamode_t dmamode);
+               unsigned int dma_length, unsigned int dev_addr, unsigned int dmamode);
 
 int
 imx_dma_setup_sg(imx_dmach_t dma_ch,
                 struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length,
-                unsigned int dev_addr, dmamode_t dmamode);
+                unsigned int dev_addr, unsigned int dmamode);
 
 int
 imx_dma_setup_handlers(imx_dmach_t dma_ch,
index 3ed9ec8b9f008cb4c7fcdcc354e77bd40391ab99..870d0d939616111408abf6b2fd32fc280978c328 100644 (file)
@@ -1,7 +1,52 @@
 /*
  * This structure describes the machine which we are running on.
  */
-struct imxfb_mach_info {
+
+#define PCR_TFT                (1 << 31)
+#define PCR_COLOR      (1 << 30)
+#define PCR_PBSIZ_1    (0 << 28)
+#define PCR_PBSIZ_2    (1 << 28)
+#define PCR_PBSIZ_4    (2 << 28)
+#define PCR_PBSIZ_8    (3 << 28)
+#define PCR_BPIX_1     (0 << 25)
+#define PCR_BPIX_2     (1 << 25)
+#define PCR_BPIX_4     (2 << 25)
+#define PCR_BPIX_8     (3 << 25)
+#define PCR_BPIX_12    (4 << 25)
+#define PCR_BPIX_16    (4 << 25)
+#define PCR_PIXPOL     (1 << 24)
+#define PCR_FLMPOL     (1 << 23)
+#define PCR_LPPOL      (1 << 22)
+#define PCR_CLKPOL     (1 << 21)
+#define PCR_OEPOL      (1 << 20)
+#define PCR_SCLKIDLE   (1 << 19)
+#define PCR_END_SEL    (1 << 18)
+#define PCR_END_BYTE_SWAP (1 << 17)
+#define PCR_REV_VS     (1 << 16)
+#define PCR_ACD_SEL    (1 << 15)
+#define PCR_ACD(x)     (((x) & 0x7f) << 8)
+#define PCR_SCLK_SEL   (1 << 7)
+#define PCR_SHARP      (1 << 6)
+#define PCR_PCD(x)     ((x) & 0x3f)
+
+#define PWMR_CLS(x)    (((x) & 0x1ff) << 16)
+#define PWMR_LDMSK     (1 << 15)
+#define PWMR_SCR1      (1 << 10)
+#define PWMR_SCR0      (1 << 9)
+#define PWMR_CC_EN     (1 << 8)
+#define PWMR_PW(x)     ((x) & 0xff)
+
+#define LSCR1_PS_RISE_DELAY(x)    (((x) & 0x7f) << 26)
+#define LSCR1_CLS_RISE_DELAY(x)   (((x) & 0x3f) << 16)
+#define LSCR1_REV_TOGGLE_DELAY(x) (((x) & 0xf) << 8)
+#define LSCR1_GRAY2(x)            (((x) & 0xf) << 4)
+#define LSCR1_GRAY1(x)            (((x) & 0xf))
+
+#define DMACR_BURST    (1 << 31)
+#define DMACR_HM(x)    (((x) & 0xf) << 16)
+#define DMACR_TM(x)    ((x) & 0xf)
+
+struct imx_fb_platform_data {
        u_long          pixclock;
 
        u_short         xres;
@@ -34,4 +79,5 @@ struct imxfb_mach_info {
        void (*lcd_power)(int);
        void (*backlight_power)(int);
 };
-void set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info);
+
+void set_imx_fb_info(struct imx_fb_platform_data *);
index c50c5fa6fb814e0419995726565ed474a9399a95..9e197ae4590f8358b31f618641261151c9801262 100644 (file)
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)                ((void __iomem *)(a))
+#define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)   (a)
 
 #endif
index 5c453063c0eddfb58b4a9fb1dcff579a85ecb3b6..a93df7cba694b4e27e5b924149591e87434e9449 100644 (file)
 
 #define PHYS_OFFSET    UL(0x08000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus(x)       (x - PAGE_OFFSET + PHYS_OFFSET)
-#define __bus_to_virt(x)       (x - PHYS_OFFSET + PAGE_OFFSET)
-
 #endif
index 8d761fdd2ecdaf3b44ea2e0f926f581963780766..989ecf5f5c4685a9b8afedf0677e8e0a88d63f82 100644 (file)
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/list.h>
 #include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/string.h>
 #include <linux/clk.h>
 #include <linux/mutex.h>
 
-#include <asm/hardware/icst525.h>
-
-#include "clock.h"
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-       mutex_unlock(&clocks_mutex);
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-       module_put(clk->owner);
-}
-EXPORT_SYMBOL(clk_put);
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
 
 int clk_enable(struct clk *clk)
 {
@@ -67,7 +37,6 @@ EXPORT_SYMBOL(clk_get_rate);
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
        struct icst525_vco vco;
-
        vco = icst525_khz_to_vco(clk->params, rate / 1000);
        return icst525_khz(clk->params, vco) * 1000;
 }
@@ -76,56 +45,15 @@ EXPORT_SYMBOL(clk_round_rate);
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
        int ret = -EIO;
+
        if (clk->setvco) {
                struct icst525_vco vco;
 
                vco = icst525_khz_to_vco(clk->params, rate / 1000);
                clk->rate = icst525_khz(clk->params, vco) * 1000;
-
-               printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
-                       clk->name, vco.s, vco.r, vco.v);
-
                clk->setvco(clk, vco);
                ret = 0;
        }
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
-
-/*
- * These are fixed clocks.
- */
-static struct clk kmi_clk = {
-       .name   = "KMIREFCLK",
-       .rate   = 24000000,
-};
-
-static struct clk uart_clk = {
-       .name   = "UARTCLK",
-       .rate   = 14745600,
-};
-
-int clk_register(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_del(&clk->node);
-       mutex_unlock(&clocks_mutex);
-}
-EXPORT_SYMBOL(clk_unregister);
-
-static int __init clk_init(void)
-{
-       clk_register(&kmi_clk);
-       clk_register(&uart_clk);
-       return 0;
-}
-arch_initcall(clk_init);
index 09e6328ceba98627717d8ed1f5ce37859270b2a9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,25 +0,0 @@
-/*
- *  linux/arch/arm/mach-integrator/clock.h
- *
- *  Copyright (C) 2004 ARM Limited.
- *  Written by Deep Blue Solutions Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-struct module;
-struct icst525_params;
-
-struct clk {
-       struct list_head        node;
-       unsigned long           rate;
-       struct module           *owner;
-       const char              *name;
-       const struct icst525_params *params;
-       void                    *data;
-       void                    (*setvco)(struct clk *, struct icst525_vco vco);
-};
-
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
index 595b7392ee4eb9bfdad41ba8b9cc69243d49cf6c..c89c949b4d459930fc7ed6d0098cbe8e7126f3fa 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/amba/serial.h>
 #include <linux/io.h>
 
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/hardware/arm_timer.h>
@@ -108,10 +110,43 @@ static struct amba_device *amba_devs[] __initdata = {
        &kmi1_device,
 };
 
+/*
+ * These are fixed clocks.
+ */
+static struct clk clk24mhz = {
+       .rate   = 24000000,
+};
+
+static struct clk uartclk = {
+       .rate   = 14745600,
+};
+
+static struct clk_lookup lookups[] __initdata = {
+       {       /* UART0 */
+               .dev_id         = "mb:16",
+               .clk            = &uartclk,
+       }, {    /* UART1 */
+               .dev_id         = "mb:17",
+               .clk            = &uartclk,
+       }, {    /* KMI0 */
+               .dev_id         = "mb:18",
+               .clk            = &clk24mhz,
+       }, {    /* KMI1 */
+               .dev_id         = "mb:19",
+               .clk            = &clk24mhz,
+       }, {    /* MMCI - IntegratorCP */
+               .dev_id         = "mb:1c",
+               .clk            = &uartclk,
+       }
+};
+
 static int __init integrator_init(void)
 {
        int i;
 
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
+
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
index 172299a783021395f778c9a46eb771f7a152dafb..0058c937719ed7f7400fe8a1388e9c9e8f73e777 100644 (file)
 #include <linux/amba/clcd.h>
 #include <linux/io.h>
 
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
 #include <asm/hardware/icst525.h>
 #include <mach/lm.h>
 #include <mach/impd1.h>
 #include <asm/sizes.h>
 
-#include "clock.h"
-
 static int module_id;
 
 module_param_named(lmid, module_id, int, 0444);
@@ -37,6 +37,7 @@ MODULE_PARM_DESC(lmid, "logic module stack position");
 struct impd1_module {
        void __iomem    *base;
        struct clk      vcos[2];
+       struct clk_lookup *clks[3];
 };
 
 static const struct icst525_params impd1_vco_params = {
@@ -339,9 +340,8 @@ static struct impd1_device impd1_devs[] = {
        }
 };
 
-static const char *impd1_vconames[2] = {
-       "CLCDCLK",
-       "AUXVCO2",
+static struct clk fixed_14745600 = {
+       .rate = 14745600,
 };
 
 static int impd1_probe(struct lm_device *dev)
@@ -374,14 +374,20 @@ static int impd1_probe(struct lm_device *dev)
 
        for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) {
                impd1->vcos[i].owner = THIS_MODULE,
-               impd1->vcos[i].name = impd1_vconames[i],
                impd1->vcos[i].params = &impd1_vco_params,
                impd1->vcos[i].data = impd1,
                impd1->vcos[i].setvco = impd1_setvco;
-
-               clk_register(&impd1->vcos[i]);
        }
 
+       impd1->clks[0] = clkdev_alloc(&impd1->vcos[0], NULL, "lm%x:01000",
+                                       dev->id);
+       impd1->clks[1] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00100",
+                                       dev->id);
+       impd1->clks[2] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00200",
+                                       dev->id);
+       for (i = 0; i < ARRAY_SIZE(impd1->clks); i++)
+               clkdev_add(impd1->clks[i]);
+
        for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
                struct impd1_device *idev = impd1_devs + i;
                struct amba_device *d;
@@ -434,8 +440,8 @@ static void impd1_remove(struct lm_device *dev)
 
        device_for_each_child(&dev->dev, NULL, impd1_remove_one);
 
-       for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++)
-               clk_unregister(&impd1->vcos[i]);
+       for (i = 0; i < ARRAY_SIZE(impd1->clks); i++)
+               clkdev_drop(impd1->clks[i]);
 
        lm_set_drvdata(dev, NULL);
 
diff --git a/arch/arm/mach-integrator/include/mach/clkdev.h b/arch/arm/mach-integrator/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..9293e41
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#include <linux/module.h>
+#include <asm/hardware/icst525.h>
+
+struct clk {
+       unsigned long           rate;
+       struct module           *owner;
+       const struct icst525_params *params;
+       void                    *data;
+       void                    (*setvco)(struct clk *, struct icst525_vco vco);
+};
+
+static inline int __clk_get(struct clk *clk)
+{
+       return try_module_get(clk->owner);
+}
+
+static inline void __clk_put(struct clk *clk)
+{
+       module_put(clk->owner);
+}
+
+#endif
index be7e63c21d257d018b7227349ee837c490cf192e..2b2e7a110724b12aa0f8c07a576e4474a2ca8603 100644 (file)
  * Physical DRAM offset.
  */
 #define PHYS_OFFSET    UL(0x00000000)
-#define BUS_OFFSET     UL(0x80000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus(x)       (x - PAGE_OFFSET + BUS_OFFSET)
-#define __bus_to_virt(x)       (x - BUS_OFFSET + PAGE_OFFSET)
+#define BUS_OFFSET     UL(0x80000000)
+#define __virt_to_bus(x)       ((x) - PAGE_OFFSET + BUS_OFFSET)
+#define __bus_to_virt(x)       ((x) - BUS_OFFSET + PAGE_OFFSET)
 
 #endif
index 88026ccd5ac9b9b81074b12b17f48e6629c8e5b9..427c2d8dc1239bc835121f4b3e19956c5b0721c8 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/amba/clcd.h>
 #include <linux/io.h>
 
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/setup.h>
@@ -38,7 +40,6 @@
 #include <asm/mach/time.h>
 
 #include "common.h"
-#include "clock.h"
 
 #define INTCP_PA_MMC_BASE              0x1c000000
 #define INTCP_PA_AACI_BASE             0x1d000000
@@ -289,15 +290,16 @@ static void cp_auxvco_set(struct clk *clk, struct icst525_vco vco)
        writel(0, CM_LOCK);
 }
 
-static struct clk cp_clcd_clk = {
-       .name   = "CLCDCLK",
+static struct clk cp_auxclk = {
        .params = &cp_auxvco_params,
        .setvco = cp_auxvco_set,
 };
 
-static struct clk cp_mmci_clk = {
-       .name   = "MCLK",
-       .rate   = 14745600,
+static struct clk_lookup cp_lookups[] = {
+       {       /* CLCD */
+               .dev_id         = "mb:c0",
+               .clk            = &cp_auxclk,
+       },
 };
 
 /*
@@ -554,8 +556,8 @@ static void __init intcp_init(void)
 {
        int i;
 
-       clk_register(&cp_clcd_clk);
-       clk_register(&cp_mmci_clk);
+       for (i = 0; i < ARRAY_SIZE(cp_lookups); i++)
+               clkdev_add(&cp_lookups[i]);
 
        platform_add_devices(intcp_devs, ARRAY_SIZE(intcp_devs));
 
diff --git a/arch/arm/mach-iop13xx/include/mach/dma.h b/arch/arm/mach-iop13xx/include/mach/dma.h
deleted file mode 100644 (file)
index d79846f..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#ifndef _IOP13XX_DMA_H
-#define _IOP13XX_DMA_H
-#endif
index b82602d529bfb4e76ec26fee1800517f0efe36dc..e012bf13c95582d2a4a8b4fd5368dd2fa380097a 100644 (file)
 #define IOP13XX_PMMR_P_START (IOP13XX_PMMR_PHYS_MEM_BASE)
 #define IOP13XX_PMMR_P_END   (IOP13XX_PMMR_PHYS_MEM_BASE + IOP13XX_PMMR_SIZE)
 
-/*
- * Virtual view <-> PCI DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
-
-/* RAM has 1:1 mapping on the PCIe/x Busses */
-#define __virt_to_bus(x)       (__virt_to_phys(x))
-#define __bus_to_virt(x)       (__phys_to_virt(x))
-
 static inline dma_addr_t __virt_to_lbus(unsigned long x)
 {
        return x + IOP13XX_PMMR_PHYS_MEM_BASE - IOP13XX_PMMR_VIRT_MEM_BASE;
@@ -55,7 +43,7 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
                if (is_lbus_device(dev) && __is_lbus_dma(__dma))        \
                        __virt = __lbus_to_virt(__dma);                 \
                else                                                    \
-                       __virt = __bus_to_virt(__dma);                  \
+                       __virt = __phys_to_virt(__dma);                 \
                (void *)__virt;                                         \
        })
 
@@ -66,7 +54,7 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
                if (is_lbus_device(dev) && __is_lbus_virt(__virt))      \
                        __dma = __virt_to_lbus(__virt);                 \
                else                                                    \
-                       __dma = __virt_to_bus(__virt);                  \
+                       __dma = __virt_to_phys(__virt);                 \
                __dma;                                                  \
        })
 
index 5b1f1c8a82702a20002a4f8890c1ccff6daa57b9..45fb2745bb548e36cb9af3ebdf19741d18178b4c 100644 (file)
@@ -1,3 +1 @@
-#include <mach/hardware.h>
-
 #define CLOCK_TICK_RATE (100 * HZ)
diff --git a/arch/arm/mach-iop32x/include/mach/dma.h b/arch/arm/mach-iop32x/include/mach/dma.h
deleted file mode 100644 (file)
index f8bd817..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/dma.h
- *
- * Copyright (C) 2004 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
index ce54705ba3d41489675b4be47efcc2363623eb76..339e5854728b5f1f3d1434d8570567b3bc6b2fc8 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __IO_H
 #define __IO_H
 
-#include <mach/hardware.h>
+#include <asm/hardware/iop3xx.h>
 
 extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size,
        unsigned int mtype);
index 42cd4bf3148cba2a05b9da2dcd5cd1d97b9d9df2..c30f6450ad50de9681f64b1e41fb304152290e01 100644 (file)
@@ -5,22 +5,9 @@
 #ifndef __MEMORY_H
 #define __MEMORY_H
 
-#include <mach/hardware.h>
-
 /*
  * Physical DRAM offset.
  */
 #define PHYS_OFFSET    UL(0xa0000000)
 
-/*
- * Virtual view <-> PCI DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
-#define __virt_to_bus(x)       (__virt_to_phys(x))
-#define __bus_to_virt(x)       (__phys_to_virt(x))
-
-
 #endif
index 20f923e54f4601cc470dfeccd3275291db718ffa..32d9e5b0a28db1a36b6888c0fa019f453c42881e 100644 (file)
@@ -7,8 +7,9 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
 #include <asm/mach-types.h>
+#include <asm/hardware/iop3xx.h>
+#include <mach/n2100.h>
 
 static inline void arch_idle(void)
 {
index a541afced3cb39a36df45c97d66e0a49942d9b8f..7262ab81419da25eb9bf3041c0e91c30bd6aeb37 100644 (file)
@@ -3,7 +3,4 @@
  *
  * IOP32x architecture timex specifications
  */
-
-#include <mach/hardware.h>
-
 #define CLOCK_TICK_RATE                (100 * HZ)
diff --git a/arch/arm/mach-iop33x/include/mach/dma.h b/arch/arm/mach-iop33x/include/mach/dma.h
deleted file mode 100644 (file)
index d8b4223..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/dma.h
- *
- * Copyright (C) 2004 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
index 158874631217b0d7687c566de199ef9ddcce89ca..e99a7ed6d0502e0390ccb9f0e4de0c2f7890ba2c 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __IO_H
 #define __IO_H
 
-#include <mach/hardware.h>
+#include <asm/hardware/iop3xx.h>
 
 extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size,
        unsigned int mtype);
index 2cef0bbb354f84aa220b82382e49acdb50a251a5..a30a96aa6d2db541c7c2c44fa55d0cd164c26023 100644 (file)
@@ -5,22 +5,9 @@
 #ifndef __MEMORY_H
 #define __MEMORY_H
 
-#include <mach/hardware.h>
-
 /*
  * Physical DRAM offset.
  */
 #define PHYS_OFFSET    UL(0x00000000)
 
-/*
- * Virtual view <-> PCI DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
-#define __virt_to_bus(x)       (__virt_to_phys(x))
-#define __bus_to_virt(x)       (__phys_to_virt(x))
-
-
 #endif
index 7bf3bfb49446404afe2c684e92b1afbf60b8e002..0cb3ad862acd92ff1d023fbbe169ff46cdc59854 100644 (file)
@@ -7,6 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <asm/hardware/iop3xx.h>
 
 static inline void arch_idle(void)
 {
index c75760844d49eae5b509d6d9170918d79e3571fe..54c589091d6eb7b6dea1881059602de7258e43bd 100644 (file)
@@ -3,7 +3,4 @@
  *
  * IOP3xx architecture timex specifications
  */
-
-#include <mach/hardware.h>
-
 #define CLOCK_TICK_RATE                (100 * HZ)
diff --git a/arch/arm/mach-ixp2000/include/mach/dma.h b/arch/arm/mach-ixp2000/include/mach/dma.h
deleted file mode 100644 (file)
index 26063d6..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/dma.h
- *
- * Copyright (C) 2002 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
index 241529a7c52d0806cf89acdfd3613716bc52ced5..aee7eb8a71b24eb7d8580534551866c5c068efaf 100644 (file)
 
 #define PHYS_OFFSET    UL(0x00000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
 #include <mach/ixp2000-regs.h>
 
 #define __virt_to_bus(v) \
diff --git a/arch/arm/mach-ixp23xx/include/mach/dma.h b/arch/arm/mach-ixp23xx/include/mach/dma.h
deleted file mode 100644 (file)
index 8886544..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/dma.h
- */
index 305ea1808c714e740f8efae742e07b2da200dea8..fd9ef8e519f7dee6c3ea9cbfd7b4e2bca9d96f37 100644 (file)
@@ -20,8 +20,6 @@
 #define __io(p)                ((void __iomem*)((p) + IXP23XX_PCI_IO_VIRT))
 #define __mem_pci(a)   (a)
 
-#include <linux/kernel.h>      /* For BUG */
-
 static inline void __iomem *
 ixp23xx_ioremap(unsigned long addr, unsigned long size, unsigned int mtype)
 {
index 9d40115f7ebeb94eec1a517fcb64709491a16c66..fdd138706c704f7b0e72264f2a60248e94f0f0f6 100644 (file)
  */
 #define PHYS_OFFSET            (0x00000000)
 
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
-#ifndef __ASSEMBLY__
-
 #define __virt_to_bus(v)                                               \
        ({ unsigned int ret;                                            \
        ret = ((__virt_to_phys(v) - 0x00000000) +                       \
@@ -43,6 +33,3 @@
 #define arch_is_coherent()     1
 
 #endif
-
-
-#endif
diff --git a/arch/arm/mach-ixp4xx/include/mach/dma.h b/arch/arm/mach-ixp4xx/include/mach/dma.h
deleted file mode 100644 (file)
index 00c5070..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/include/mach/dma.h
- *
- * Copyright (C) 2001-2004 MontaVista Software, 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.
- *
- */
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#include <linux/device.h>
-#include <asm/page.h>
-#include <asm/sizes.h>
-#include <mach/hardware.h>
-
-#define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_64M)
-
-#endif /* _ASM_ARCH_DMA_H */
index 319948e31bec2d95d16ac669bdf86c005ed3b161..ce63048d45eb0ab7ad52556917ce5b28fe1c610c 100644 (file)
@@ -49,8 +49,6 @@ extern int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data);
 
 #else
 
-#include <linux/mm.h>
-
 /*
  * In the case of using indirect PCI, we simply return the actual PCI
  * address and our read/write implementation use that to drive the 
@@ -241,7 +239,7 @@ __ixp4xx_readsl(const volatile void __iomem *bus_addr, u32 *vaddr, u32 count)
 
 #ifndef CONFIG_PCI
 
-#define        __io(v)         v
+#define        __io(v)         __typesafe_io(v)
 
 #else
 
index c4d2830ac987463da197bd43aed72364009d5418..98f5e5e2098001398d45930d2fb5d33b3452f0ea 100644 (file)
@@ -22,19 +22,8 @@ void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes);
        ixp4xx_adjust_zones(node, size, holes)
 
 #define ISA_DMA_THRESHOLD (SZ_64M - 1)
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_64M)
 
 #endif
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- *
- * These are dummies for now.
- */
-#define __virt_to_bus(x)        __virt_to_phys(x)
-#define __bus_to_virt(x)        __phys_to_virt(x)
-
 #endif
index 0bb1fbd84ccb9f561cbb6cb6ebc14cdc485f6784..7b8ef97fb5016a99127a34b3ce0cdcd5ae3a7574 100644 (file)
@@ -57,6 +57,7 @@ void __init kirkwood_map_io(void)
  ****************************************************************************/
 static struct orion_ehci_data kirkwood_ehci_data = {
        .dram           = &kirkwood_mbus_dram_info,
+       .phy_version    = EHCI_PHY_NA,
 };
 
 static u64 ehci_dmamask = 0xffffffffUL;
@@ -152,6 +153,64 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 }
 
 
+/*****************************************************************************
+ * GE01
+ ****************************************************************************/
+struct mv643xx_eth_shared_platform_data kirkwood_ge01_shared_data = {
+       .dram           = &kirkwood_mbus_dram_info,
+       .shared_smi     = &kirkwood_ge00_shared,
+};
+
+static struct resource kirkwood_ge01_shared_resources[] = {
+       {
+               .name   = "ge01 base",
+               .start  = GE01_PHYS_BASE + 0x2000,
+               .end    = GE01_PHYS_BASE + 0x3fff,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "ge01 err irq",
+               .start  = IRQ_KIRKWOOD_GE01_ERR,
+               .end    = IRQ_KIRKWOOD_GE01_ERR,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device kirkwood_ge01_shared = {
+       .name           = MV643XX_ETH_SHARED_NAME,
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &kirkwood_ge01_shared_data,
+       },
+       .num_resources  = ARRAY_SIZE(kirkwood_ge01_shared_resources),
+       .resource       = kirkwood_ge01_shared_resources,
+};
+
+static struct resource kirkwood_ge01_resources[] = {
+       {
+               .name   = "ge01 irq",
+               .start  = IRQ_KIRKWOOD_GE01_SUM,
+               .end    = IRQ_KIRKWOOD_GE01_SUM,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device kirkwood_ge01 = {
+       .name           = MV643XX_ETH_NAME,
+       .id             = 1,
+       .num_resources  = 1,
+       .resource       = kirkwood_ge01_resources,
+};
+
+void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
+{
+       eth_data->shared = &kirkwood_ge01_shared;
+       kirkwood_ge01.dev.platform_data = eth_data;
+
+       platform_device_register(&kirkwood_ge01_shared);
+       platform_device_register(&kirkwood_ge01);
+}
+
+
 /*****************************************************************************
  * Ethernet switch
  ****************************************************************************/
index 5774632a67e34ac746307c8d749ab6355c71ef63..fe367c18e722f6d598a27f0f9772415c281e4589 100644 (file)
@@ -30,6 +30,7 @@ void kirkwood_pcie_id(u32 *dev, u32 *rev);
 
 void kirkwood_ehci_init(void);
 void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data);
+void kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data);
 void kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq);
 void kirkwood_pcie_init(void);
 void kirkwood_rtc_init(void);
diff --git a/arch/arm/mach-kirkwood/include/mach/dma.h b/arch/arm/mach-kirkwood/include/mach/dma.h
deleted file mode 100644 (file)
index 40a8c17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-kirkwood/include/mach/gpio.h b/arch/arm/mach-kirkwood/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..81b335e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * arch/asm-arm/mach-kirkwood/include/mach/gpio.h
+ *
+ * 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 __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <mach/irqs.h>
+#include <plat/gpio.h>
+#include <asm-generic/gpio.h>          /* cansleep wrappers */
+
+#define GPIO_MAX               50
+#define GPIO_OFF(pin)          (((pin) >> 5) ? 0x0140 : 0x0100)
+#define GPIO_OUT(pin)          (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x00)
+#define GPIO_IO_CONF(pin)      (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x04)
+#define GPIO_BLINK_EN(pin)     (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x08)
+#define GPIO_IN_POL(pin)       (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x0c)
+#define GPIO_DATA_IN(pin)      (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x10)
+#define GPIO_EDGE_CAUSE(pin)   (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x14)
+#define GPIO_EDGE_MASK(pin)    (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x18)
+#define GPIO_LEVEL_MASK(pin)   (DEV_BUS_VIRT_BASE + GPIO_OFF(pin) + 0x1c)
+
+static inline int gpio_to_irq(int pin)
+{
+       return pin + IRQ_KIRKWOOD_GPIO_START;
+}
+
+static inline int irq_to_gpio(int irq)
+{
+       return irq - IRQ_KIRKWOOD_GPIO_START;
+}
+
+
+#endif
index ffab89f21c11da5aa31d9bbf7abacc9243565072..f00a0a45a67e5356bf08d722a4c5bda29b4a57ce 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef __ASM_ARCH_IRQS_H
 #define __ASM_ARCH_IRQS_H
 
-#include "kirkwood.h"  /* need GPIO_MAX */
-
 /*
  * Low Interrupt Controller
  */
 #define IRQ_KIRKWOOD_GPIO_HIGH_8_15    40
 #define IRQ_KIRKWOOD_GPIO_HIGH_16_23   41
 #define IRQ_KIRKWOOD_GE00_ERR  46
+#define IRQ_KIRKWOOD_GE01_ERR  47
 
 /*
  * KIRKWOOD General Purpose Pins
  */
 #define IRQ_KIRKWOOD_GPIO_START        64
-#define NR_GPIO_IRQS           GPIO_MAX
+#define NR_GPIO_IRQS           50
 
 #define NR_IRQS                        (IRQ_KIRKWOOD_GPIO_START + NR_GPIO_IRQS)
 
index eae42406fd86302ed850c88f5094550213e0371c..ada480c0e1975d73c55ebc67d94a7df8356a7b68 100644 (file)
 #define SATA_PHYS_BASE         (KIRKWOOD_REGS_PHYS_BASE | 0x80000)
 
 
-#define GPIO_MAX               50
-
-
 #endif
index b5fb34bdccd5a16065fdcfb7fcd74b36ce9650a9..45431e1314652de8ee20b8f41046665c0fa3f2ae 100644 (file)
@@ -7,8 +7,4 @@
 
 #define PHYS_OFFSET            UL(0x00000000)
 
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
-
 #endif
index 5790643ffe079d5781e435fe5d36531aaa221949..efb86b700276bf965c611526e83d8973d20b7a90 100644 (file)
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <plat/irq.h>
+#include <asm/gpio.h>
 #include "common.h"
 
+static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       BUG_ON(irq < IRQ_KIRKWOOD_GPIO_LOW_0_7);
+       BUG_ON(irq > IRQ_KIRKWOOD_GPIO_HIGH_16_23);
+
+       orion_gpio_irq_handler((irq - IRQ_KIRKWOOD_GPIO_LOW_0_7) << 3);
+}
+
 void __init kirkwood_init_irq(void)
 {
+       int i;
+
        orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
        orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
+
+       /*
+        * Mask and clear GPIO IRQ interrupts.
+        */
+       writel(0, GPIO_LEVEL_MASK(0));
+       writel(0, GPIO_EDGE_MASK(0));
+       writel(0, GPIO_EDGE_CAUSE(0));
+       writel(0, GPIO_LEVEL_MASK(32));
+       writel(0, GPIO_EDGE_MASK(32));
+       writel(0, GPIO_EDGE_CAUSE(32));
+
+       for (i = IRQ_KIRKWOOD_GPIO_START; i < NR_IRQS; i++) {
+               set_irq_chip(i, &orion_gpio_irq_level_chip);
+               set_irq_handler(i, handle_level_irq);
+               irq_desc[i].status |= IRQ_LEVEL;
+               set_irq_flags(i, IRQF_VALID);
+       }
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_0_7, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_8_15, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_16_23, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_LOW_24_31, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_0_7, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_8_15, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_KIRKWOOD_GPIO_HIGH_16_23, gpio_irq_handler);
 }
index 175054abd630d59cbae7e4698adaba474adaf250..9a0e905d10cd04e6841f8dc7f5cc7bb6c57fa705 100644 (file)
@@ -80,24 +80,38 @@ static struct dsa_platform_data rd88f6281_switch_data = {
        .port_names[1]  = "lan2",
        .port_names[2]  = "lan3",
        .port_names[3]  = "lan4",
-       .port_names[4]  = "wan",
        .port_names[5]  = "cpu",
 };
 
+static struct mv643xx_eth_platform_data rd88f6281_ge01_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(11),
+};
+
 static struct mv_sata_platform_data rd88f6281_sata_data = {
        .n_ports        = 2,
 };
 
 static void __init rd88f6281_init(void)
 {
+       u32 dev, rev;
+
        /*
         * Basic setup. Needs to be called early.
         */
        kirkwood_init();
 
        kirkwood_ehci_init();
+
        kirkwood_ge00_init(&rd88f6281_ge00_data);
+       kirkwood_pcie_id(&dev, &rev);
+       if (rev == MV88F6281_REV_A0) {
+               rd88f6281_switch_data.sw_addr = 10;
+               kirkwood_ge01_init(&rd88f6281_ge01_data);
+       } else {
+               rd88f6281_switch_data.port_names[4] = "wan";
+       }
        kirkwood_ge00_switch_init(&rd88f6281_switch_data, NO_IRQ);
+
        kirkwood_rtc_init();
        kirkwood_sata_init(&rd88f6281_sata_data);
        kirkwood_uart0_init();
index ce1cf8de2b4d7653618a44062b907a623f47c032..2754daabda55eb54bbb3744e46ee7ef1d1041cd4 100644 (file)
@@ -8,6 +8,12 @@ config MACH_KS8695
          Say 'Y' here if you want your kernel to run on the original
          Kendin-Micrel KS8695 development board.
 
+config MACH_DSM320
+       bool "DSM-320 Wireless Media Player"
+       help
+         Say 'Y' here if you want your kernel to run on the D-Link
+         DSM-320 Wireless Media Player.
+
 endmenu
 
 endif
index ade42b73afbb2cea2c6c5722be88a2904af65e78..f735d2cc0294474bde6de12ff9f5ffc3331a0367 100644 (file)
@@ -16,3 +16,4 @@ obj-$(CONFIG_LEDS)            += leds.o
 
 # Board-specific support
 obj-$(CONFIG_MACH_KS8695)      += board-micrel.o
+obj-$(CONFIG_MACH_DSM320)      += board-dsm320.o
diff --git a/arch/arm/mach-ks8695/board-dsm320.c b/arch/arm/mach-ks8695/board-dsm320.c
new file mode 100644 (file)
index 0000000..521ff07
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * arch/arm/mach-ks8695/board-dsm320.c
+ *
+ * DSM-320 D-Link Wireless Media Player, board support.
+ *
+ * Copyright 2008 Simtec Electronics
+ *               Daniel Silverstone <dsilvers@simtec.co.uk>
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/devices.h>
+#include <mach/gpio.h>
+
+#include "generic.h"
+
+#ifdef CONFIG_PCI
+static int dsm320_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       switch (slot) {
+       case 0:
+               /* PCI-AHB bridge? */
+               return KS8695_IRQ_EXTERN0;
+       case 18:
+               /* Mini PCI slot */
+               return KS8695_IRQ_EXTERN2;
+       case 20:
+               /* RealMAGIC chip */
+               return KS8695_IRQ_EXTERN0;
+       }
+       BUG();
+}
+
+static struct ks8695_pci_cfg __initdata dsm320_pci = {
+       .mode           = KS8695_MODE_MINIPCI,
+       .map_irq        = dsm320_pci_map_irq,
+};
+
+static void __init dsm320_register_pci(void)
+{
+       /* Initialise the GPIO lines for interrupt mode */
+       /* RealMAGIC */
+       ks8695_gpio_interrupt(KS8695_GPIO_0, IRQ_TYPE_LEVEL_LOW);
+       /* MiniPCI Slot */
+       ks8695_gpio_interrupt(KS8695_GPIO_2, IRQ_TYPE_LEVEL_LOW);
+
+       ks8695_init_pci(&dsm320_pci);
+}
+
+#else
+static inline void __init dsm320_register_pci(void) { }
+#endif
+
+static struct physmap_flash_data dsm320_nor_pdata = {
+       .width          = 4,
+       .nr_parts       = 0,
+};
+
+static struct resource dsm320_nor_resource[] = {
+       [0] = {
+               .start = SZ_32M, /* We expect the bootloader to map
+                                 * the flash here.
+                                 */
+               .end   = SZ_32M + SZ_4M - 1,
+               .flags = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device dsm320_device_nor = {
+       .name           = "physmap-flash",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(dsm320_nor_resource),
+       .resource       = dsm320_nor_resource,
+       .dev            = {
+               .platform_data = &dsm320_nor_pdata,
+       },
+};
+
+void __init dsm320_register_nor(void)
+{
+       int ret;
+
+       ret = platform_device_register(&dsm320_device_nor);
+       if (ret < 0)
+               printk(KERN_ERR "failed to register physmap-flash device\n");
+}
+
+static void __init dsm320_init(void)
+{
+       /* GPIO registration */
+       ks8695_register_gpios();
+
+       /* PCI registration */
+       dsm320_register_pci();
+
+       /* Network device */
+       ks8695_add_device_lan();        /* eth0 = LAN */
+
+       /* NOR devices */
+       dsm320_register_nor();
+}
+
+MACHINE_START(DSM320, "D-Link DSM-320 Wireless Media Player")
+       /* Maintainer: Simtec Electronics. */
+       .phys_io        = KS8695_IO_PA,
+       .io_pg_offst    = (KS8695_IO_VA >> 18) & 0xfffc,
+       .boot_params    = KS8695_SDRAM_PA + 0x100,
+       .map_io         = ks8695_map_io,
+       .init_irq       = ks8695_init_irq,
+       .init_machine   = dsm320_init,
+       .timer          = &ks8695_timer,
+MACHINE_END
index 0468e93b7d3b3c2656f1537aa0a9698e3123cb87..8ceaf5ac6e2ca405bc4843b7f66fb8141807c8b3 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/gpio.h>
 #include <mach/devices.h>
 
 #include "generic.h"
@@ -39,6 +40,8 @@ static void __init micrel_init(void)
 {
        printk(KERN_INFO "Micrel KS8695 Development Board initializing\n");
 
+       ks8695_register_gpios();
+
 #ifdef CONFIG_PCI
        ks8695_init_pci(&micrel_pci);
 #endif
index 4bd251482c8ff8b9e7d636cdb57555fd7b0d778b..36ab0fd3d9b687ace1c166a3d4231262d6dedb12 100644 (file)
 #include <mach/regs-wan.h>
 #include <mach/regs-lan.h>
 #include <mach/regs-hpna.h>
+#include <mach/regs-switch.h>
+#include <mach/regs-misc.h>
 
 
 /* --------------------------------------------------------------------
  *  Ethernet
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_ARM_KS8695_ETHER) || defined(CONFIG_ARM_KS8695_ETHER_MODULE)
 static u64 eth_dmamask = 0xffffffffUL;
 
 static struct resource ks8695_wan_resources[] = {
        [0] = {
-               .start  = KS8695_WAN_VA,
-               .end    = KS8695_WAN_VA + 0x00ff,
+               .start  = KS8695_WAN_PA,
+               .end    = KS8695_WAN_PA + 0x00ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -58,6 +59,12 @@ static struct resource ks8695_wan_resources[] = {
                .end    = KS8695_IRQ_WAN_LINK,
                .flags  = IORESOURCE_IRQ,
        },
+       [4] = {
+               .name   = "WAN PHY",
+               .start  = KS8695_MISC_PA,
+               .end    = KS8695_MISC_PA + 0x1f,
+               .flags  = IORESOURCE_MEM,
+       },
 };
 
 static struct platform_device ks8695_wan_device = {
@@ -74,8 +81,8 @@ static struct platform_device ks8695_wan_device = {
 
 static struct resource ks8695_lan_resources[] = {
        [0] = {
-               .start  = KS8695_LAN_VA,
-               .end    = KS8695_LAN_VA + 0x00ff,
+               .start  = KS8695_LAN_PA,
+               .end    = KS8695_LAN_PA + 0x00ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -90,6 +97,12 @@ static struct resource ks8695_lan_resources[] = {
                .end    = KS8695_IRQ_LAN_TX_STATUS,
                .flags  = IORESOURCE_IRQ,
        },
+       [3] = {
+               .name   = "LAN SWITCH",
+               .start  = KS8695_SWITCH_PA,
+               .end    = KS8695_SWITCH_PA + 0x4f,
+               .flags  = IORESOURCE_MEM,
+       },
 };
 
 static struct platform_device ks8695_lan_device = {
@@ -106,8 +119,8 @@ static struct platform_device ks8695_lan_device = {
 
 static struct resource ks8695_hpna_resources[] = {
        [0] = {
-               .start  = KS8695_HPNA_VA,
-               .end    = KS8695_HPNA_VA + 0x00ff,
+               .start  = KS8695_HPNA_PA,
+               .end    = KS8695_HPNA_PA + 0x00ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
@@ -149,18 +162,12 @@ void __init ks8696_add_device_hpna(void)
 {
        platform_device_register(&ks8695_hpna_device);
 }
-#else
-void __init ks8695_add_device_wan(void) {}
-void __init ks8695_add_device_lan(void) {}
-void __init ks8696_add_device_hpna(void) {}
-#endif
 
 
 /* --------------------------------------------------------------------
  *  Watchdog
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_KS8695_WATCHDOG) || defined(CONFIG_KS8695_WATCHDOG_MODULE)
 static struct platform_device ks8695_wdt_device = {
        .name           = "ks8695_wdt",
        .id             = -1,
@@ -171,9 +178,6 @@ static void __init ks8695_add_device_watchdog(void)
 {
        platform_device_register(&ks8695_wdt_device);
 }
-#else
-static void __init ks8695_add_device_watchdog(void) {}
-#endif
 
 
 /* --------------------------------------------------------------------
@@ -190,7 +194,7 @@ void __init ks8695_init_leds(u8 cpu_led, u8 timer_led)
        gpio_direction_output(cpu_led, 1);
        gpio_direction_output(timer_led, 1);
 
-       ks8695_leds_cpu   = cpu_led;
+       ks8695_leds_cpu   = cpu_led;
        ks8695_leds_timer = timer_led;
 }
 #else
index 9aecf0c4b8b1e47b8c65e0655c3eaa0774e38554..55fbf7111a5bd3fb5e720fd68e2c023b965f9dcb 100644 (file)
@@ -2,6 +2,8 @@
  * arch/arm/mach-ks8695/gpio.c
  *
  * Copyright (C) 2006 Andrew Victor
+ * Updated to GPIOLIB, Copyright 2008 Simtec Electronics
+ *                     Daniel Silverstone <dsilvers@simtec.co.uk>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -35,7 +37,7 @@
  * Configure a GPIO line for either GPIO function, or its internal
  * function (Interrupt, Timer, etc).
  */
-static void __init_or_module ks8695_gpio_mode(unsigned int pin, short gpio)
+static void ks8695_gpio_mode(unsigned int pin, short gpio)
 {
        unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
        unsigned long x, flags;
@@ -61,7 +63,7 @@ static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8
 /*
  * Configure GPIO pin as external interrupt source.
  */
-int __init_or_module ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
+int ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
 {
        unsigned long x, flags;
 
@@ -94,7 +96,7 @@ EXPORT_SYMBOL(ks8695_gpio_interrupt);
 /*
  * Configure the GPIO line as an input.
  */
-int __init_or_module gpio_direction_input(unsigned int pin)
+static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin)
 {
        unsigned long x, flags;
 
@@ -115,13 +117,13 @@ int __init_or_module gpio_direction_input(unsigned int pin)
 
        return 0;
 }
-EXPORT_SYMBOL(gpio_direction_input);
 
 
 /*
  * Configure the GPIO line as an output, with default state.
  */
-int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state)
+static int ks8695_gpio_direction_output(struct gpio_chip *gc,
+                                       unsigned int pin, int state)
 {
        unsigned long x, flags;
 
@@ -150,13 +152,13 @@ int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state)
 
        return 0;
 }
-EXPORT_SYMBOL(gpio_direction_output);
 
 
 /*
  * Set the state of an output GPIO line.
  */
-void gpio_set_value(unsigned int pin, unsigned int state)
+static void ks8695_gpio_set_value(struct gpio_chip *gc,
+                                 unsigned int pin, int state)
 {
        unsigned long x, flags;
 
@@ -175,13 +177,12 @@ void gpio_set_value(unsigned int pin, unsigned int state)
 
        local_irq_restore(flags);
 }
-EXPORT_SYMBOL(gpio_set_value);
 
 
 /*
  * Read the state of a GPIO line.
  */
-int gpio_get_value(unsigned int pin)
+static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin)
 {
        unsigned long x;
 
@@ -191,21 +192,18 @@ int gpio_get_value(unsigned int pin)
        x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
        return (x & IOPD(pin)) != 0;
 }
-EXPORT_SYMBOL(gpio_get_value);
 
 
 /*
  * Map GPIO line to IRQ number.
  */
-int gpio_to_irq(unsigned int pin)
+static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
 {
        if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
                return -EINVAL;
 
        return gpio_irq[pin];
 }
-EXPORT_SYMBOL(gpio_to_irq);
-
 
 /*
  * Map IRQ number to GPIO line.
@@ -219,6 +217,26 @@ int irq_to_gpio(unsigned int irq)
 }
 EXPORT_SYMBOL(irq_to_gpio);
 
+/* GPIOLIB interface */
+
+static struct gpio_chip ks8695_gpio_chip = {
+       .label                  = "KS8695",
+       .direction_input        = ks8695_gpio_direction_input,
+       .direction_output       = ks8695_gpio_direction_output,
+       .get                    = ks8695_gpio_get_value,
+       .set                    = ks8695_gpio_set_value,
+       .to_irq                 = ks8695_gpio_to_irq,
+       .base                   = 0,
+       .ngpio                  = 16,
+       .can_sleep              = 0,
+};
+
+/* Register the GPIOs */
+void ks8695_register_gpios(void)
+{
+       if (gpiochip_add(&ks8695_gpio_chip))
+               printk(KERN_ERR "Unable to register core GPIOs\n");
+}
 
 /* .... Debug interface ..................................................... */
 
diff --git a/arch/arm/mach-ks8695/include/mach/dma.h b/arch/arm/mach-ks8695/include/mach/dma.h
deleted file mode 100644 (file)
index 5612062..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-ks8695/include/mach/dma.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 program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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
- */
index d4af5c335f1616aace85c43a4fa6b57f25c21006..86312d476bc69525317641b63fe46ff53021342d 100644 (file)
 #define KS8695_GPIO_14         14
 #define KS8695_GPIO_15         15
 
-
 /*
  * Configure GPIO pin as external interrupt source.
  */
-int __init_or_module ks8695_gpio_interrupt(unsigned int pin, unsigned int type);
-
-/*
- * Configure the GPIO line as an input.
- */
-int __init_or_module gpio_direction_input(unsigned int pin);
-
-/*
- * Configure the GPIO line as an output, with default state.
- */
-int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state);
-
-/*
- * Set the state of an output GPIO line.
- */
-void gpio_set_value(unsigned int pin, unsigned int state);
-
-/*
- * Read the state of a GPIO line.
- */
-int gpio_get_value(unsigned int pin);
-
-/*
- * Map GPIO line to IRQ number.
- */
-int gpio_to_irq(unsigned int pin);
+extern int ks8695_gpio_interrupt(unsigned int pin, unsigned int type);
 
 /*
  * Map IRQ number to GPIO line.
  */
-int irq_to_gpio(unsigned int irq);
-
+extern int irq_to_gpio(unsigned int irq);
 
 #include <asm-generic/gpio.h>
 
-static inline int gpio_request(unsigned int pin, const char *label)
-{
-       return 0;
-}
+/* If it turns out that we need to optimise GPIO access for the
+ * Micrel's GPIOs, then these can be changed to check their argument
+ * directly as static inlines. However for now it's probably not
+ * worthwhile.
+ */
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_to_irq __gpio_to_irq
 
-static inline void gpio_free(unsigned int pin)
-{
-       might_sleep();
-}
+/* Register the GPIOs */
+extern void ks8695_register_gpios(void);
 
 #endif
index f364f24ffe1ec44a1bc1a8e4c269e552b1dba95e..a7a63ac3ba4e5f607bec5607018533d7209d1843 100644 (file)
@@ -13,7 +13,7 @@
 
 #define IO_SPACE_LIMIT         0xffffffff
 
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 8fbc4c76c38b6485000476d8809154e01f009873..6d5887cf574286512c4321b668fdce3bc15d44cd 100644 (file)
@@ -37,11 +37,6 @@ extern struct bus_type platform_bus_type;
                                        (dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); })
 #define __arch_page_to_dma(dev, x)     __arch_virt_to_dma(dev, page_address(x))
 
-#else
-
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
 #endif
 
 #endif
diff --git a/arch/arm/mach-l7200/include/mach/dma.h b/arch/arm/mach-l7200/include/mach/dma.h
deleted file mode 100644 (file)
index c7e48bd..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/arm/mach-l7200/include/mach/dma.h
- *
- * Copyright (C) 2000 Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *  08-29-2000 SJH     Created
- */
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-/* DMA is not yet implemented! It should be the same as acorn, copy over.. */
-
-/*
- * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
- */
-#define MAX_DMA_ADDRESS         0xd0000000
-
-#define DMA_S0                  0
-
-#endif /* _ASM_ARCH_DMA_H */
index d432ba9e5dff8308974e9ebb8deebcaa45cc06e5..a770a89fb70829f55f889ea5b4dce49b1cd7b0fd 100644 (file)
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
 /*
  * There are not real ISA nor PCI buses, so we fake it.
  */
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-#define __io(a)        __io(a)
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index f338cf3ffd93d4498a169e0fff712753b3ac81ea..9fb40ed2f03b5854f764941cc246254853db768b 100644 (file)
@@ -17,9 +17,6 @@
  */
 #define PHYS_OFFSET     UL(0xf0000000)
 
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
 /*
  * Cache flushing area - ROM
  */
index 4fb23ac6b5ac6edef40c2fd84010b000ee32d790..6182f5410b4de466a88b6da43f72050463363411 100644 (file)
 #include <linux/err.h>
 
 struct module;
-struct icst525_params;
 
 struct clk {
        struct list_head node;
        unsigned long rate;
        struct module *owner;
        const char *name;
-//     void *data;
-//     const struct icst525_params *params;
-//     void (*setvco)(struct clk *, struct icst525_vco vco);
 };
 
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
-
 /* ----- */
 
 #define MAINDIV1(c)    (((c) >>  7) & 0x0f)
@@ -79,31 +72,15 @@ unsigned int pclkfreq_get (void)
 
 /* ----- */
 
-static LIST_HEAD(clocks);
-static DECLARE_MUTEX(clocks_sem);
-
 struct clk *clk_get (struct device *dev, const char *id)
 {
-       struct clk *p;
-       struct clk *clk = ERR_PTR(-ENOENT);
-
-       down (&clocks_sem);
-       list_for_each_entry (p, &clocks, node) {
-               if (strcmp (id, p->name) == 0
-                   && try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-       up (&clocks_sem);
-
-       return clk;
+       return dev && strcmp(dev_name(dev), "cldc-lh7a40x") == 0
+                ? NULL : ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get);
 
 void clk_put (struct clk *clk)
 {
-       module_put(clk->owner);
 }
 EXPORT_SYMBOL(clk_put);
 
@@ -118,20 +95,9 @@ void clk_disable (struct clk *clk)
 }
 EXPORT_SYMBOL(clk_disable);
 
-int clk_use (struct clk *clk)
-{
-       return 0;
-}
-EXPORT_SYMBOL(clk_use);
-
-void clk_unuse (struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_unuse);
-
 unsigned long clk_get_rate (struct clk *clk)
 {
-       return clk->rate;
+       return 0;
 }
 EXPORT_SYMBOL(clk_get_rate);
 
@@ -143,56 +109,6 @@ EXPORT_SYMBOL(clk_round_rate);
 
 int clk_set_rate (struct clk *clk, unsigned long rate)
 {
-       int ret = -EIO;
-       return ret;
+       return -EIO;
 }
 EXPORT_SYMBOL(clk_set_rate);
-
-#if 0
-/*
- * These are fixed clocks.
- */
-static struct clk kmi_clk = {
-       .name   = "KMIREFCLK",
-       .rate   = 24000000,
-};
-
-static struct clk uart_clk = {
-       .name   = "UARTCLK",
-       .rate   = 24000000,
-};
-
-static struct clk mmci_clk = {
-       .name   = "MCLK",
-       .rate   = 33000000,
-};
-#endif
-
-static struct clk clcd_clk = {
-       .name   = "CLCDCLK",
-       .rate   = 0,
-};
-
-int clk_register (struct clk *clk)
-{
-       down (&clocks_sem);
-       list_add (&clk->node, &clocks);
-       up (&clocks_sem);
-       return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister (struct clk *clk)
-{
-       down (&clocks_sem);
-       list_del (&clk->node);
-       up (&clocks_sem);
-}
-EXPORT_SYMBOL(clk_unregister);
-
-static int __init clk_init (void)
-{
-       clk_register(&clcd_clk);
-       return 0;
-}
-arch_initcall(clk_init);
index 031d26f9163cb5e6a7b4994d93e220b90cf8b86f..6ece45911cbc2a1e6efc274a7a4118befc86a2e5 100644 (file)
 #ifndef __ASM_ARCH_IO_H
 #define __ASM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
 /* No ISA or PCI bus on this machine. */
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif /* __ASM_ARCH_IO_H */
index 1da14ff66c93e035dc448997d2d280104af5ebfc..189d20e543e75f41b52a39f4f009e30ed87ed2d5 100644 (file)
  */
 #define PHYS_OFFSET    UL(0xc0000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
-#define __virt_to_bus(x)        __virt_to_phys(x)
-#define __bus_to_virt(x)        __phys_to_virt(x)
-
 #ifdef CONFIG_DISCONTIGMEM
 
 /*
diff --git a/arch/arm/mach-loki/include/mach/dma.h b/arch/arm/mach-loki/include/mach/dma.h
deleted file mode 100644 (file)
index 40a8c17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
index a39533ab489deb9affbc3d72cdb87f647aedf237..2ed7e6e732c2fc552120f4738bc1fa9218ae3aae 100644 (file)
@@ -7,8 +7,4 @@
 
 #define PHYS_OFFSET            UL(0x00000000)
 
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
-
 #endif
index c6a2feb268b0bc8def0f0890ad1aa803ae506173..aab964591db43a390e36c74c406b279bb768ce17 100644 (file)
 
 void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype);
 
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-#define __io(a)         __io(a)
+#define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)    (a)
 
 #endif
index 63fd47f2e62eb4415f8492df4e26a526355600ef..f4698baec976af9c2c2d8b8fd0f7f7abfa73c8ba 100644 (file)
@@ -19,9 +19,5 @@
 /* physical offset of RAM */
 #define PHYS_OFFSET            UL(0x10000000)
 
-/* bus address and physical addresses are identical */
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
 #endif
 
index 238a2f8c2d525b1f65b0579f86c9b0fc6e9761cb..b0e4e0d8f506af23f6abd53f2a6ab47d07e19daf 100644 (file)
@@ -167,6 +167,7 @@ void __init mv78xx0_map_io(void)
  ****************************************************************************/
 static struct orion_ehci_data mv78xx0_ehci_data = {
        .dram           = &mv78xx0_mbus_dram_info,
+       .phy_version    = EHCI_PHY_NA,
 };
 
 static u64 ehci_dmamask = 0xffffffffUL;
diff --git a/arch/arm/mach-mv78xx0/include/mach/dma.h b/arch/arm/mach-mv78xx0/include/mach/dma.h
deleted file mode 100644 (file)
index 40a8c17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-mv78xx0/include/mach/gpio.h b/arch/arm/mach-mv78xx0/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..d9d1535
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/asm-arm/mach-mv78xx0/include/mach/gpio.h
+ *
+ * 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 __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <mach/irqs.h>
+#include <plat/gpio.h>
+#include <asm-generic/gpio.h>          /* cansleep wrappers */
+
+extern int mv78xx0_core_index(void);
+
+#define GPIO_MAX               32
+#define GPIO_OUT(pin)          (DEV_BUS_VIRT_BASE + 0x0100)
+#define GPIO_IO_CONF(pin)      (DEV_BUS_VIRT_BASE + 0x0104)
+#define GPIO_BLINK_EN(pin)     (DEV_BUS_VIRT_BASE + 0x0108)
+#define GPIO_IN_POL(pin)       (DEV_BUS_VIRT_BASE + 0x010c)
+#define GPIO_DATA_IN(pin)      (DEV_BUS_VIRT_BASE + 0x0110)
+#define GPIO_EDGE_CAUSE(pin)   (DEV_BUS_VIRT_BASE + 0x0114)
+#define GPIO_MASK_OFF          (mv78xx0_core_index() ? 0x18 : 0)
+#define GPIO_EDGE_MASK(pin)    (DEV_BUS_VIRT_BASE + 0x0118 + GPIO_MASK_OFF)
+#define GPIO_LEVEL_MASK(pin)   (DEV_BUS_VIRT_BASE + 0x011c + GPIO_MASK_OFF)
+
+static inline int gpio_to_irq(int pin)
+{
+       return pin + IRQ_MV78XX0_GPIO_START;
+}
+
+static inline int irq_to_gpio(int irq)
+{
+       return irq - IRQ_MV78XX0_GPIO_START;
+}
+
+
+#endif
index bebc330281ec6173c056e0757dd2ce8f019bce27..fa1d422196c2ea769870e28a1b544d084b80d832 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef __ASM_ARCH_IRQS_H
 #define __ASM_ARCH_IRQS_H
 
-#include "mv78xx0.h"   /* need GPIO_MAX */
-
 /*
  * MV78xx0 Low Interrupt Controller
  */
@@ -88,7 +86,7 @@
  * MV78XX0 General Purpose Pins
  */
 #define IRQ_MV78XX0_GPIO_START 96
-#define NR_GPIO_IRQS           GPIO_MAX
+#define NR_GPIO_IRQS           32
 
 #define NR_IRQS                        (IRQ_MV78XX0_GPIO_START + NR_GPIO_IRQS)
 
index 9e47a140ff7a124aafde3274dfe8f991db68f489..e663042d307f580eda42fb3eb89fd9101fde7c6c 100644 (file)
@@ -7,8 +7,4 @@
 
 #define PHYS_OFFSET            UL(0x00000000)
 
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
-
 #endif
index ee9c5593ee92bcfe957b8e11131ebf1cc1054f17..e930ea5330a2c23bb9fc15d5f562b49a698982b2 100644 (file)
 #define SATA_PHYS_BASE         (MV78XX0_REGS_PHYS_BASE | 0xa0000)
 
 
-#define GPIO_MAX               32
-
-
 #endif
index 503e5d195ae548d9091486dda5b8b860d979dac1..e273418797b41cbaa309469fac12656aff97b986 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/gpio.h>
 #include <mach/mv78xx0.h>
 #include <plat/irq.h>
 #include "common.h"
 
+static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       BUG_ON(irq < IRQ_MV78XX0_GPIO_0_7 || irq > IRQ_MV78XX0_GPIO_24_31);
+
+       orion_gpio_irq_handler((irq - IRQ_MV78XX0_GPIO_0_7) << 3);
+}
+
 void __init mv78xx0_init_irq(void)
 {
+       int i;
+
        orion_irq_init(0, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF));
        orion_irq_init(32, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF));
        orion_irq_init(64, (void __iomem *)(IRQ_VIRT_BASE + IRQ_MASK_ERR_OFF));
+
+       /*
+        * Mask and clear GPIO IRQ interrupts.
+        */
+       writel(0, GPIO_LEVEL_MASK(0));
+       writel(0, GPIO_EDGE_MASK(0));
+       writel(0, GPIO_EDGE_CAUSE(0));
+
+       for (i = IRQ_MV78XX0_GPIO_START; i < NR_IRQS; i++) {
+               set_irq_chip(i, &orion_gpio_irq_level_chip);
+               set_irq_handler(i, handle_level_irq);
+               irq_desc[i].status |= IRQ_LEVEL;
+               set_irq_flags(i, IRQF_VALID);
+       }
+       set_irq_chained_handler(IRQ_MV78XX0_GPIO_0_7, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_MV78XX0_GPIO_8_15, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_MV78XX0_GPIO_16_23, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_MV78XX0_GPIO_24_31, gpio_irq_handler);
 }
diff --git a/arch/arm/mach-mx1/Kconfig b/arch/arm/mach-mx1/Kconfig
new file mode 100644 (file)
index 0000000..2b59fc7
--- /dev/null
@@ -0,0 +1,14 @@
+if ARCH_MX1
+
+comment "MX1 Platforms"
+
+config MACH_MXLADS
+       bool
+
+config ARCH_MX1ADS
+       bool "MX1ADS platform"
+       select MACH_MXLADS
+       help
+         Say Y here if you are using Motorola MX1ADS/MXLADS boards
+
+endif
diff --git a/arch/arm/mach-mx1/Makefile b/arch/arm/mach-mx1/Makefile
new file mode 100644 (file)
index 0000000..b969719
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y                  += generic.o clock.o devices.o
+
+# Specific board support
+obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
diff --git a/arch/arm/mach-mx1/Makefile.boot b/arch/arm/mach-mx1/Makefile.boot
new file mode 100644 (file)
index 0000000..8ed1492
--- /dev/null
@@ -0,0 +1,4 @@
+   zreladdr-y  := 0x08008000
+params_phys-y  := 0x08000100
+initrd_phys-y  := 0x08800000
+
diff --git a/arch/arm/mach-mx1/clock.c b/arch/arm/mach-mx1/clock.c
new file mode 100644 (file)
index 0000000..4bcd1ec
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ *  Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/clock.h>
+#include <mach/hardware.h>
+#include "crm_regs.h"
+
+static int _clk_enable(struct clk *clk)
+{
+       unsigned int reg;
+
+       reg = __raw_readl(clk->enable_reg);
+       reg |= 1 << clk->enable_shift;
+       __raw_writel(reg, clk->enable_reg);
+
+       return 0;
+}
+
+static void _clk_disable(struct clk *clk)
+{
+       unsigned int reg;
+
+       reg = __raw_readl(clk->enable_reg);
+       reg &= ~(1 << clk->enable_shift);
+       __raw_writel(reg, clk->enable_reg);
+}
+
+static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size,
+                              struct clk *parent)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               if (parent == clk_arr[i])
+                       return i;
+
+       return -EINVAL;
+}
+
+static unsigned long
+_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit)
+{
+       int div;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+       if (parent_rate % rate)
+               div++;
+
+       if (div > limit)
+               div = limit;
+
+       return parent_rate / div;
+}
+
+static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk->parent->round_rate(clk->parent, rate);
+}
+
+static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
+{
+       return clk->parent->set_rate(clk->parent, rate);
+}
+
+/*
+ *  get the system pll clock in Hz
+ *
+ *                  mfi + mfn / (mfd +1)
+ *  f = 2 * f_ref * --------------------
+ *                        pd + 1
+ */
+static unsigned long mx1_decode_pll(unsigned int pll, u32 f_ref)
+{
+       unsigned long long ll;
+       unsigned long quot;
+
+       u32 mfi = (pll >> 10) & 0xf;
+       u32 mfn = pll & 0x3ff;
+       u32 mfd = (pll >> 16) & 0x3ff;
+       u32 pd =  (pll >> 26) & 0xf;
+
+       mfi = mfi <= 5 ? 5 : mfi;
+
+       ll = 2 * (unsigned long long)f_ref *
+               ((mfi << 16) + (mfn << 16) / (mfd + 1));
+       quot = (pd + 1) * (1 << 16);
+       ll += quot / 2;
+       do_div(ll, quot);
+       return (unsigned long)ll;
+}
+
+static unsigned long clk16m_get_rate(struct clk *clk)
+{
+       return 16000000;
+}
+
+static struct clk clk16m = {
+       .name = "CLK16M",
+       .get_rate = clk16m_get_rate,
+       .enable = _clk_enable,
+       .enable_reg = CCM_CSCR,
+       .enable_shift = CCM_CSCR_OSC_EN_SHIFT,
+       .disable = _clk_disable,
+};
+
+/* in Hz */
+static unsigned long clk32_rate;
+
+static unsigned long clk32_get_rate(struct clk *clk)
+{
+       return clk32_rate;
+}
+
+static struct clk clk32 = {
+       .name = "CLK32",
+       .get_rate = clk32_get_rate,
+};
+
+static unsigned long clk32_premult_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) * 512;
+}
+
+static struct clk clk32_premult = {
+       .name = "CLK32_premultiplier",
+       .parent = &clk32,
+       .get_rate = clk32_premult_get_rate,
+};
+
+static const struct clk *prem_clk_clocks[] = {
+       &clk32_premult,
+       &clk16m,
+};
+
+static int prem_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int i;
+       unsigned int reg = __raw_readl(CCM_CSCR);
+
+       i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks),
+                               parent);
+
+       switch (i) {
+       case 0:
+               reg &= ~CCM_CSCR_SYSTEM_SEL;
+               break;
+       case 1:
+               reg |= CCM_CSCR_SYSTEM_SEL;
+               break;
+       default:
+               return i;
+       }
+
+       __raw_writel(reg, CCM_CSCR);
+
+       return 0;
+}
+
+static struct clk prem_clk = {
+       .name = "prem_clk",
+       .set_parent = prem_clk_set_parent,
+};
+
+static unsigned long system_clk_get_rate(struct clk *clk)
+{
+       return mx1_decode_pll(__raw_readl(CCM_SPCTL0),
+                             clk_get_rate(clk->parent));
+}
+
+static struct clk system_clk = {
+       .name = "system_clk",
+       .parent = &prem_clk,
+       .get_rate = system_clk_get_rate,
+};
+
+static unsigned long mcu_clk_get_rate(struct clk *clk)
+{
+       return mx1_decode_pll(__raw_readl(CCM_MPCTL0),
+                             clk_get_rate(clk->parent));
+}
+
+static struct clk mcu_clk = {
+       .name = "mcu_clk",
+       .parent = &clk32_premult,
+       .get_rate = mcu_clk_get_rate,
+};
+
+static unsigned long fclk_get_rate(struct clk *clk)
+{
+       unsigned long fclk = clk_get_rate(clk->parent);
+
+       if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC)
+               fclk /= 2;
+
+       return fclk;
+}
+
+static struct clk fclk = {
+       .name = "fclk",
+       .parent = &mcu_clk,
+       .get_rate = fclk_get_rate,
+};
+
+/*
+ *  get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
+ */
+static unsigned long hclk_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
+                       CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1);
+}
+
+static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate)
+{
+       return _clk_simple_round_rate(clk, rate, 16);
+}
+
+static int hclk_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int div;
+       unsigned int reg;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+
+       if (div > 16 || div < 1 || ((parent_rate / div) != rate))
+               return -EINVAL;
+
+       div--;
+
+       reg = __raw_readl(CCM_CSCR);
+       reg &= ~CCM_CSCR_BCLK_MASK;
+       reg |= div << CCM_CSCR_BCLK_OFFSET;
+       __raw_writel(reg, CCM_CSCR);
+
+       return 0;
+}
+
+static struct clk hclk = {
+       .name = "hclk",
+       .parent = &system_clk,
+       .get_rate = hclk_get_rate,
+       .round_rate = hclk_round_rate,
+       .set_rate = hclk_set_rate,
+};
+
+static unsigned long clk48m_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
+                       CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1);
+}
+
+static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate)
+{
+       return _clk_simple_round_rate(clk, rate, 8);
+}
+
+static int clk48m_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int div;
+       unsigned int reg;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+
+       if (div > 8 || div < 1 || ((parent_rate / div) != rate))
+               return -EINVAL;
+
+       div--;
+
+       reg = __raw_readl(CCM_CSCR);
+       reg &= ~CCM_CSCR_USB_MASK;
+       reg |= div << CCM_CSCR_USB_OFFSET;
+       __raw_writel(reg, CCM_CSCR);
+
+       return 0;
+}
+
+static struct clk clk48m = {
+       .name = "CLK48M",
+       .parent = &system_clk,
+       .get_rate = clk48m_get_rate,
+       .round_rate = clk48m_round_rate,
+       .set_rate = clk48m_set_rate,
+};
+
+/*
+ *  get peripheral clock 1 ( UART[12], Timer[12], PWM )
+ */
+static unsigned long perclk1_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
+                       CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1);
+}
+
+static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate)
+{
+       return _clk_simple_round_rate(clk, rate, 16);
+}
+
+static int perclk1_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int div;
+       unsigned int reg;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+
+       if (div > 16 || div < 1 || ((parent_rate / div) != rate))
+               return -EINVAL;
+
+       div--;
+
+       reg = __raw_readl(CCM_PCDR);
+       reg &= ~CCM_PCDR_PCLK1_MASK;
+       reg |= div << CCM_PCDR_PCLK1_OFFSET;
+       __raw_writel(reg, CCM_PCDR);
+
+       return 0;
+}
+
+/*
+ *  get peripheral clock 2 ( LCD, SD, SPI[12] )
+ */
+static unsigned long perclk2_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
+                       CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1);
+}
+
+static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate)
+{
+       return _clk_simple_round_rate(clk, rate, 16);
+}
+
+static int perclk2_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int div;
+       unsigned int reg;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+
+       if (div > 16 || div < 1 || ((parent_rate / div) != rate))
+               return -EINVAL;
+
+       div--;
+
+       reg = __raw_readl(CCM_PCDR);
+       reg &= ~CCM_PCDR_PCLK2_MASK;
+       reg |= div << CCM_PCDR_PCLK2_OFFSET;
+       __raw_writel(reg, CCM_PCDR);
+
+       return 0;
+}
+
+/*
+ *  get peripheral clock 3 ( SSI )
+ */
+static unsigned long perclk3_get_rate(struct clk *clk)
+{
+       return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
+                       CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1);
+}
+
+static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate)
+{
+       return _clk_simple_round_rate(clk, rate, 128);
+}
+
+static int perclk3_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int div;
+       unsigned int reg;
+       unsigned long parent_rate;
+
+       parent_rate = clk_get_rate(clk->parent);
+
+       div = parent_rate / rate;
+
+       if (div > 128 || div < 1 || ((parent_rate / div) != rate))
+               return -EINVAL;
+
+       div--;
+
+       reg = __raw_readl(CCM_PCDR);
+       reg &= ~CCM_PCDR_PCLK3_MASK;
+       reg |= div << CCM_PCDR_PCLK3_OFFSET;
+       __raw_writel(reg, CCM_PCDR);
+
+       return 0;
+}
+
+static struct clk perclk[] = {
+       {
+               .name = "perclk",
+               .id = 0,
+               .parent = &system_clk,
+               .get_rate = perclk1_get_rate,
+               .round_rate = perclk1_round_rate,
+               .set_rate = perclk1_set_rate,
+       }, {
+               .name = "perclk",
+               .id = 1,
+               .parent = &system_clk,
+               .get_rate = perclk2_get_rate,
+               .round_rate = perclk2_round_rate,
+               .set_rate = perclk2_set_rate,
+       }, {
+               .name = "perclk",
+               .id = 2,
+               .parent = &system_clk,
+               .get_rate = perclk3_get_rate,
+               .round_rate = perclk3_round_rate,
+               .set_rate = perclk3_set_rate,
+       }
+};
+
+static const struct clk *clko_clocks[] = {
+       &perclk[0],
+       &hclk,
+       &clk48m,
+       &clk16m,
+       &prem_clk,
+       &fclk,
+};
+
+static int clko_set_parent(struct clk *clk, struct clk *parent)
+{
+       int i;
+       unsigned int reg;
+
+       i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent);
+       if (i < 0)
+               return i;
+
+       reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK;
+       reg |= i << CCM_CSCR_CLKO_OFFSET;
+       __raw_writel(reg, CCM_CSCR);
+
+       if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) {
+               clk->set_rate = _clk_parent_set_rate;
+               clk->round_rate = _clk_parent_round_rate;
+       } else {
+               clk->set_rate = NULL;
+               clk->round_rate = NULL;
+       }
+
+       return 0;
+}
+
+static struct clk clko_clk = {
+       .name = "clko_clk",
+       .set_parent = clko_set_parent,
+};
+
+static struct clk dma_clk = {
+       .name = "dma_clk",
+       .parent = &hclk,
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+       .enable = _clk_enable,
+       .enable_reg = SCM_GCCR,
+       .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET,
+       .disable = _clk_disable,
+};
+
+static struct clk csi_clk = {
+       .name = "csi_clk",
+       .parent = &hclk,
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+       .enable = _clk_enable,
+       .enable_reg = SCM_GCCR,
+       .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET,
+       .disable = _clk_disable,
+};
+
+static struct clk mma_clk = {
+       .name = "mma_clk",
+       .parent = &hclk,
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+       .enable = _clk_enable,
+       .enable_reg = SCM_GCCR,
+       .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET,
+       .disable = _clk_disable,
+};
+
+static struct clk usbd_clk = {
+       .name = "usbd_clk",
+       .parent = &clk48m,
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+       .enable = _clk_enable,
+       .enable_reg = SCM_GCCR,
+       .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET,
+       .disable = _clk_disable,
+};
+
+static struct clk gpt_clk = {
+       .name = "gpt_clk",
+       .parent = &perclk[0],
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk uart_clk = {
+       .name = "uart_clk",
+       .parent = &perclk[0],
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk i2c_clk = {
+       .name = "i2c_clk",
+       .parent = &hclk,
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk spi_clk = {
+       .name = "spi_clk",
+       .parent = &perclk[1],
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk sdhc_clk = {
+       .name = "sdhc_clk",
+       .parent = &perclk[1],
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk lcdc_clk = {
+       .name = "lcdc_clk",
+       .parent = &perclk[1],
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk mshc_clk = {
+       .name = "mshc_clk",
+       .parent = &hclk,
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk ssi_clk = {
+       .name = "ssi_clk",
+       .parent = &perclk[2],
+       .round_rate = _clk_parent_round_rate,
+       .set_rate = _clk_parent_set_rate,
+};
+
+static struct clk rtc_clk = {
+       .name = "rtc_clk",
+       .parent = &clk32,
+};
+
+static struct clk *mxc_clks[] = {
+       &clk16m,
+       &clk32,
+       &clk32_premult,
+       &prem_clk,
+       &system_clk,
+       &mcu_clk,
+       &fclk,
+       &hclk,
+       &clk48m,
+       &perclk[0],
+       &perclk[1],
+       &perclk[2],
+       &clko_clk,
+       &dma_clk,
+       &csi_clk,
+       &mma_clk,
+       &usbd_clk,
+       &gpt_clk,
+       &uart_clk,
+       &i2c_clk,
+       &spi_clk,
+       &sdhc_clk,
+       &lcdc_clk,
+       &mshc_clk,
+       &ssi_clk,
+       &rtc_clk,
+};
+
+int __init mxc_clocks_init(unsigned long fref)
+{
+       struct clk **clkp;
+       unsigned int reg;
+
+       /* disable clocks we are able to */
+       __raw_writel(0, SCM_GCCR);
+
+       clk32_rate = fref;
+       reg = __raw_readl(CCM_CSCR);
+
+       /* detect clock reference for system PLL */
+       if (reg & CCM_CSCR_SYSTEM_SEL) {
+               prem_clk.parent = &clk16m;
+       } else {
+               /* ensure that oscillator is disabled */
+               reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT);
+               __raw_writel(reg, CCM_CSCR);
+               prem_clk.parent = &clk32_premult;
+       }
+
+       /* detect reference for CLKO */
+       reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET;
+       clko_clk.parent = (struct clk *)clko_clocks[reg];
+
+       for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
+               clk_register(*clkp);
+
+       clk_enable(&hclk);
+       clk_enable(&fclk);
+
+       return 0;
+}
diff --git a/arch/arm/mach-mx1/crm_regs.h b/arch/arm/mach-mx1/crm_regs.h
new file mode 100644 (file)
index 0000000..22e866f
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#ifndef __ARCH_ARM_MACH_MX1_CRM_REGS_H__
+#define __ARCH_ARM_MACH_MX1_CRM_REGS_H__
+
+#define CCM_BASE       IO_ADDRESS(CCM_BASE_ADDR)
+#define SCM_BASE       IO_ADDRESS(SCM_BASE_ADDR)
+
+/* CCM register addresses */
+#define CCM_CSCR       (CCM_BASE + 0x0)
+#define CCM_MPCTL0     (CCM_BASE + 0x4)
+#define CCM_MPCTL1     (CCM_BASE + 0x8)
+#define CCM_SPCTL0     (CCM_BASE + 0xC)
+#define CCM_SPCTL1     (CCM_BASE + 0x10)
+#define CCM_PCDR       (CCM_BASE + 0x20)
+
+#define CCM_CSCR_CLKO_OFFSET   29
+#define CCM_CSCR_CLKO_MASK     (0x7 << 29)
+#define CCM_CSCR_USB_OFFSET    26
+#define CCM_CSCR_USB_MASK      (0x7 << 26)
+#define CCM_CSCR_SPLL_RESTART  (1 << 22)
+#define CCM_CSCR_MPLL_RESTART  (1 << 21)
+#define CCM_CSCR_OSC_EN_SHIFT  17
+#define CCM_CSCR_SYSTEM_SEL    (1 << 16)
+#define CCM_CSCR_BCLK_OFFSET   10
+#define CCM_CSCR_BCLK_MASK     (0xF << 10)
+#define CCM_CSCR_PRESC         (1 << 15)
+#define CCM_CSCR_SPEN          (1 << 1)
+#define CCM_CSCR_MPEN          (1 << 0)
+
+#define CCM_PCDR_PCLK3_OFFSET  16
+#define CCM_PCDR_PCLK3_MASK    (0x7F << 16)
+#define CCM_PCDR_PCLK2_OFFSET  4
+#define CCM_PCDR_PCLK2_MASK    (0xF << 4)
+#define CCM_PCDR_PCLK1_OFFSET  0
+#define CCM_PCDR_PCLK1_MASK    0xF
+
+/* SCM register addresses */
+#define SCM_SIDR       (SCM_BASE + 0x0)
+#define SCM_FMCR       (SCM_BASE + 0x4)
+#define SCM_GPCR       (SCM_BASE + 0x8)
+#define SCM_GCCR       (SCM_BASE + 0xC)
+
+#define SCM_GCCR_DMA_CLK_EN_OFFSET     3
+#define SCM_GCCR_CSI_CLK_EN_OFFSET     2
+#define SCM_GCCR_MMA_CLK_EN_OFFSET     1
+#define SCM_GCCR_USBD_CLK_EN_OFFSET    0
+
+#endif /* __ARCH_ARM_MACH_MX2_CRM_REGS_H__ */
diff --git a/arch/arm/mach-mx1/devices.c b/arch/arm/mach-mx1/devices.c
new file mode 100644 (file)
index 0000000..686d8d2
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
+ * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (c) 2008 Darius Augulis <darius.augulis@teltonika.lt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <mach/hardware.h>
+
+static struct resource imx_csi_resources[] = {
+       [0] = {
+               .start  = 0x00224000,
+               .end    = 0x00224010,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = CSI_INT,
+               .end    = CSI_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static u64 imx_csi_dmamask = 0xffffffffUL;
+
+struct platform_device imx_csi_device = {
+       .name           = "imx-csi",
+       .id             = 0, /* This is used to put cameras on this interface */
+       .dev            = {
+               .dma_mask = &imx_csi_dmamask,
+               .coherent_dma_mask = 0xffffffff,
+       },
+       .resource       = imx_csi_resources,
+       .num_resources  = ARRAY_SIZE(imx_csi_resources),
+};
+
+static struct resource imx_i2c_resources[] = {
+       [0] = {
+               .start  = 0x00217000,
+               .end    = 0x00217010,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = I2C_INT,
+               .end    = I2C_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_i2c_device = {
+       .name           = "imx-i2c",
+       .id             = 0,
+       .resource       = imx_i2c_resources,
+       .num_resources  = ARRAY_SIZE(imx_i2c_resources),
+};
+
+static struct resource imx_uart1_resources[] = {
+       [0] = {
+               .start  = UART1_BASE_ADDR,
+               .end    = UART1_BASE_ADDR + 0xD0,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = UART1_MINT_RX,
+               .end    = UART1_MINT_RX,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = UART1_MINT_TX,
+               .end    = UART1_MINT_TX,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = UART1_MINT_RTS,
+               .end    = UART1_MINT_RTS,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_uart1_device = {
+       .name           = "imx-uart",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(imx_uart1_resources),
+       .resource       = imx_uart1_resources,
+};
+
+static struct resource imx_uart2_resources[] = {
+       [0] = {
+               .start  = UART2_BASE_ADDR,
+               .end    = UART2_BASE_ADDR + 0xD0,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = UART2_MINT_RX,
+               .end    = UART2_MINT_RX,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = UART2_MINT_TX,
+               .end    = UART2_MINT_TX,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = UART2_MINT_RTS,
+               .end    = UART2_MINT_RTS,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_uart2_device = {
+       .name           = "imx-uart",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(imx_uart2_resources),
+       .resource       = imx_uart2_resources,
+};
+
+static struct resource imx_rtc_resources[] = {
+       [0] = {
+               .start  = 0x00204000,
+               .end    = 0x00204024,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = RTC_INT,
+               .end    = RTC_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = RTC_SAMINT,
+               .end    = RTC_SAMINT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_rtc_device = {
+       .name           = "rtc-imx",
+       .id             = 0,
+       .resource       = imx_rtc_resources,
+       .num_resources  = ARRAY_SIZE(imx_rtc_resources),
+};
+
+static struct resource imx_wdt_resources[] = {
+       [0] = {
+               .start  = 0x00201000,
+               .end    = 0x00201008,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = WDT_INT,
+               .end    = WDT_INT,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_wdt_device = {
+       .name           = "imx-wdt",
+       .id             = 0,
+       .resource       = imx_wdt_resources,
+       .num_resources  = ARRAY_SIZE(imx_wdt_resources),
+};
+
+static struct resource imx_usb_resources[] = {
+       [0] = {
+               .start  = 0x00212000,
+               .end    = 0x00212148,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = USBD_INT0,
+               .end    = USBD_INT0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = USBD_INT1,
+               .end    = USBD_INT1,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = USBD_INT2,
+               .end    = USBD_INT2,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [4] = {
+               .start  = USBD_INT3,
+               .end    = USBD_INT3,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [5] = {
+               .start  = USBD_INT4,
+               .end    = USBD_INT4,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [6] = {
+               .start  = USBD_INT5,
+               .end    = USBD_INT5,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [7] = {
+               .start  = USBD_INT6,
+               .end    = USBD_INT6,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device imx_usb_device = {
+       .name           = "imx_udc",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(imx_usb_resources),
+       .resource       = imx_usb_resources,
+};
+
+/* GPIO port description */
+static struct mxc_gpio_port imx_gpio_ports[] = {
+       [0] = {
+               .chip.label = "gpio-0",
+               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR),
+               .irq = GPIO_INT_PORTA,
+               .virtual_irq_start = MXC_GPIO_IRQ_START
+       },
+       [1] = {
+               .chip.label = "gpio-1",
+               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x100),
+               .irq = GPIO_INT_PORTB,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32
+       },
+       [2] = {
+               .chip.label = "gpio-2",
+               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x200),
+               .irq = GPIO_INT_PORTC,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 64
+       },
+       [3] = {
+               .chip.label = "gpio-3",
+               .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x300),
+               .irq = GPIO_INT_PORTD,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 96
+       }
+};
+
+int __init mxc_register_gpios(void)
+{
+       return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
+}
diff --git a/arch/arm/mach-mx1/devices.h b/arch/arm/mach-mx1/devices.h
new file mode 100644 (file)
index 0000000..0da5d7c
--- /dev/null
@@ -0,0 +1,7 @@
+extern struct platform_device imx_csi_device;
+extern struct platform_device imx_i2c_device;
+extern struct platform_device imx_uart1_device;
+extern struct platform_device imx_uart2_device;
+extern struct platform_device imx_rtc_device;
+extern struct platform_device imx_wdt_device;
+extern struct platform_device imx_usb_device;
similarity index 58%
rename from arch/arm/mach-integrator/include/mach/dma.h
rename to arch/arm/mach-mx1/generic.c
index fbebe85a2db7ca20cbfac8e2ea821dde6929edf6..0dec6f300ffc140da11ce1937e84323af90a6e40 100644 (file)
@@ -1,7 +1,9 @@
 /*
- *  arch/arm/mach-integrator/include/mach/dma.h
+ *  author: Sascha Hauer
+ *  Created: april 20th, 2004
+ *  Copyright: Synertronixx GmbH
  *
- *  Copyright (C) 1997,1998 Russell King
+ *  Common code for i.MX machines
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
  */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+
+static struct map_desc imx_io_desc[] __initdata = {
+       {
+               .virtual        = IMX_IO_BASE,
+               .pfn            = __phys_to_pfn(IMX_IO_PHYS),
+               .length         = IMX_IO_SIZE,
+               .type           = MT_DEVICE
+       }
+};
+
+void __init mxc_map_io(void)
+{
+       iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
+}
diff --git a/arch/arm/mach-mx1/mx1ads.c b/arch/arm/mach-mx1/mx1ads.c
new file mode 100644 (file)
index 0000000..2e4b185
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * arch/arm/mach-imx/mx1ads.c
+ *
+ * Initially based on:
+ *     linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
+ *     Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
+ *
+ * 2004 (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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx1-mx2.h>
+#include "devices.h"
+
+/*
+ * UARTs platform data
+ */
+static int mxc_uart1_pins[] = {
+       PC9_PF_UART1_CTS,
+       PC10_PF_UART1_RTS,
+       PC11_PF_UART1_TXD,
+       PC12_PF_UART1_RXD,
+};
+
+static int uart1_mxc_init(struct platform_device *pdev)
+{
+       return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
+                       ARRAY_SIZE(mxc_uart1_pins), "UART1");
+}
+
+static int uart1_mxc_exit(struct platform_device *pdev)
+{
+       mxc_gpio_release_multiple_pins(mxc_uart1_pins,
+                       ARRAY_SIZE(mxc_uart1_pins));
+       return 0;
+}
+
+static int mxc_uart2_pins[] = {
+       PB28_PF_UART2_CTS,
+       PB29_PF_UART2_RTS,
+       PB30_PF_UART2_TXD,
+       PB31_PF_UART2_RXD,
+};
+
+static int uart2_mxc_init(struct platform_device *pdev)
+{
+       return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
+                       ARRAY_SIZE(mxc_uart2_pins), "UART2");
+}
+
+static int uart2_mxc_exit(struct platform_device *pdev)
+{
+       mxc_gpio_release_multiple_pins(mxc_uart2_pins,
+                       ARRAY_SIZE(mxc_uart2_pins));
+       return 0;
+}
+
+static struct imxuart_platform_data uart_pdata[] = {
+       {
+               .init = uart1_mxc_init,
+               .exit = uart1_mxc_exit,
+               .flags = IMXUART_HAVE_RTSCTS,
+       }, {
+               .init = uart2_mxc_init,
+               .exit = uart2_mxc_exit,
+               .flags = IMXUART_HAVE_RTSCTS,
+       },
+};
+
+/*
+ * Physmap flash
+ */
+
+static struct physmap_flash_data mx1ads_flash_data = {
+       .width          = 4,            /* bankwidth in bytes */
+};
+
+static struct resource flash_resource = {
+       .start  = IMX_CS0_PHYS,
+       .end    = IMX_CS0_PHYS + SZ_32M - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+       .name   = "physmap-flash",
+       .id     = 0,
+       .resource = &flash_resource,
+       .num_resources = 1,
+};
+
+/*
+ * Board init
+ */
+static void __init mx1ads_init(void)
+{
+       /* UART */
+       mxc_register_device(&imx_uart1_device, &uart_pdata[0]);
+       mxc_register_device(&imx_uart2_device, &uart_pdata[1]);
+
+       /* Physmap flash */
+       mxc_register_device(&flash_device, &mx1ads_flash_data);
+}
+
+static void __init mx1ads_timer_init(void)
+{
+       mxc_clocks_init(32000);
+       mxc_timer_init("gpt_clk");
+}
+
+struct sys_timer mx1ads_timer = {
+       .init   = mx1ads_timer_init,
+};
+
+MACHINE_START(MX1ADS, "Freescale MX1ADS")
+       /* Maintainer: Sascha Hauer, Pengutronix */
+       .phys_io        = IMX_IO_PHYS,
+       .io_pg_offst    = (IMX_IO_BASE >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mxc_map_io,
+       .init_irq       = mxc_init_irq,
+       .timer          = &mx1ads_timer,
+       .init_machine   = mx1ads_init,
+MACHINE_END
+
+MACHINE_START(MXLADS, "Freescale MXLADS")
+       .phys_io        = IMX_IO_PHYS,
+       .io_pg_offst    = (IMX_IO_BASE >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mxc_map_io,
+       .init_irq       = mxc_init_irq,
+       .timer          = &mx1ads_timer,
+       .init_machine   = mx1ads_init,
+MACHINE_END
index bd0559d5933e1a03e4000050becf460252792e5f..af121f5ab710152dd359fb60ae390fdb1c41c93f 100644 (file)
@@ -190,38 +190,72 @@ struct platform_device mxc_wdt = {
        .resource = mxc_wdt_resources,
 };
 
+static struct resource mxc_w1_master_resources[] = {
+       {
+               .start = OWIRE_BASE_ADDR,
+               .end   = OWIRE_BASE_ADDR + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mxc_w1_master_device = {
+       .name = "mxc_w1",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_w1_master_resources),
+       .resource = mxc_w1_master_resources,
+};
+
+static struct resource mxc_nand_resources[] = {
+       {
+               .start  = NFC_BASE_ADDR,
+               .end    = NFC_BASE_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = MXC_INT_NANDFC,
+               .end    = MXC_INT_NANDFC,
+               .flags  = IORESOURCE_IRQ
+       },
+};
+
+struct platform_device mxc_nand_device = {
+       .name = "mxc_nand",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_nand_resources),
+       .resource = mxc_nand_resources,
+};
+
 /* GPIO port description */
 static struct mxc_gpio_port imx_gpio_ports[] = {
        [0] = {
                .chip.label = "gpio-0",
                .irq = MXC_INT_GPIO,
                .base = (void*)(AIPI_BASE_ADDR_VIRT + 0x15000 + 0x100 * 0),
-               .virtual_irq_start = MXC_MAX_INT_LINES,
+               .virtual_irq_start = MXC_GPIO_IRQ_START,
        },
        [1] = {
                .chip.label = "gpio-1",
                .base = (void*)(AIPI_BASE_ADDR_VIRT + 0x15000 + 0x100 * 1),
-               .virtual_irq_start = MXC_MAX_INT_LINES + 32,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32,
        },
        [2] = {
                .chip.label = "gpio-2",
                .base = (void*)(AIPI_BASE_ADDR_VIRT + 0x15000 + 0x100 * 2),
-               .virtual_irq_start = MXC_MAX_INT_LINES + 64,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 64,
        },
        [3] = {
                .chip.label = "gpio-3",
                .base = (void*)(AIPI_BASE_ADDR_VIRT + 0x15000 + 0x100 * 3),
-               .virtual_irq_start = MXC_MAX_INT_LINES + 96,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 96,
        },
        [4] = {
                .chip.label = "gpio-4",
                .base = (void*)(AIPI_BASE_ADDR_VIRT + 0x15000 + 0x100 * 4),
-               .virtual_irq_start = MXC_MAX_INT_LINES + 128,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 128,
        },
        [5] = {
                .chip.label = "gpio-5",
                .base = (void*)(AIPI_BASE_ADDR_VIRT + 0x15000 + 0x100 * 5),
-               .virtual_irq_start = MXC_MAX_INT_LINES + 160,
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 160,
        }
 };
 
index c77a4b8f73b4708593fdda6e7aa959918e1ccf88..1e8cb577a64262752afca2ea9f6c38b176119ea0 100644 (file)
@@ -12,4 +12,5 @@ extern struct platform_device mxc_uart_device2;
 extern struct platform_device mxc_uart_device3;
 extern struct platform_device mxc_uart_device4;
 extern struct platform_device mxc_uart_device5;
-
+extern struct platform_device mxc_w1_master_device;
+extern struct platform_device mxc_nand_device;
index 56e22d3ca075a7e6ae886b206a29bc6bcb507ebd..2b5c67f545718dab0f361225a057e23abec6e9eb 100644 (file)
@@ -68,15 +68,14 @@ static int mxc_uart0_pins[] = {
 static int uart_mxc_port0_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART0");
+                       ARRAY_SIZE(mxc_uart0_pins), "UART0");
 }
 
 static int uart_mxc_port0_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART0");
+       mxc_gpio_release_multiple_pins(mxc_uart0_pins,
+                       ARRAY_SIZE(mxc_uart0_pins));
+       return 0;
 }
 
 static int mxc_uart1_pins[] = {
@@ -89,15 +88,14 @@ static int mxc_uart1_pins[] = {
 static int uart_mxc_port1_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART1");
+                       ARRAY_SIZE(mxc_uart1_pins), "UART1");
 }
 
 static int uart_mxc_port1_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART1");
+       mxc_gpio_release_multiple_pins(mxc_uart1_pins,
+                       ARRAY_SIZE(mxc_uart1_pins));
+       return 0;
 }
 
 static int mxc_uart2_pins[] = {
@@ -110,15 +108,14 @@ static int mxc_uart2_pins[] = {
 static int uart_mxc_port2_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART2");
+                       ARRAY_SIZE(mxc_uart2_pins), "UART2");
 }
 
 static int uart_mxc_port2_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART2");
+       mxc_gpio_release_multiple_pins(mxc_uart2_pins,
+                       ARRAY_SIZE(mxc_uart2_pins));
+       return 0;
 }
 
 static int mxc_uart3_pins[] = {
@@ -131,15 +128,13 @@ static int mxc_uart3_pins[] = {
 static int uart_mxc_port3_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart3_pins,
-                       ARRAY_SIZE(mxc_uart3_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART3");
+                       ARRAY_SIZE(mxc_uart3_pins), "UART3");
 }
 
 static int uart_mxc_port3_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart3_pins,
-                       ARRAY_SIZE(mxc_uart3_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART3");
+       mxc_gpio_release_multiple_pins(mxc_uart3_pins,
+                       ARRAY_SIZE(mxc_uart3_pins));
 }
 
 static int mxc_uart4_pins[] = {
@@ -152,15 +147,14 @@ static int mxc_uart4_pins[] = {
 static int uart_mxc_port4_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart4_pins,
-                       ARRAY_SIZE(mxc_uart4_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART4");
+                       ARRAY_SIZE(mxc_uart4_pins), "UART4");
 }
 
 static int uart_mxc_port4_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart4_pins,
-                       ARRAY_SIZE(mxc_uart4_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART4");
+       mxc_gpio_release_multiple_pins(mxc_uart4_pins,
+                       ARRAY_SIZE(mxc_uart4_pins));
+       return 0;
 }
 
 static int mxc_uart5_pins[] = {
@@ -173,15 +167,14 @@ static int mxc_uart5_pins[] = {
 static int uart_mxc_port5_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart5_pins,
-                       ARRAY_SIZE(mxc_uart5_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART5");
+                       ARRAY_SIZE(mxc_uart5_pins), "UART5");
 }
 
 static int uart_mxc_port5_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart5_pins,
-                       ARRAY_SIZE(mxc_uart5_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART5");
+       mxc_gpio_release_multiple_pins(mxc_uart5_pins,
+                       ARRAY_SIZE(mxc_uart5_pins));
+       return 0;
 }
 
 static struct platform_device *platform_devices[] __initdata = {
@@ -212,15 +205,13 @@ static int mxc_fec_pins[] = {
 static void gpio_fec_active(void)
 {
        mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-                       ARRAY_SIZE(mxc_fec_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "FEC");
+                       ARRAY_SIZE(mxc_fec_pins), "FEC");
 }
 
 static void gpio_fec_inactive(void)
 {
-       mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-                       ARRAY_SIZE(mxc_fec_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "FEC");
+       mxc_gpio_release_multiple_pins(mxc_fec_pins,
+                       ARRAY_SIZE(mxc_fec_pins));
 }
 
 static struct imxuart_platform_data uart_pdata[] = {
index 7f55746e259156181442e4c682d7162541a85e9e..dfd4156da7d5b1fe1b597d4ea9a44e598cdeeac7 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mtd/plat-ram.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 #include <mach/common.h>
 #include <asm/mach/time.h>
 #include <mach/imx-uart.h>
 #include <mach/board-pcm038.h>
+#include <mach/mxc_nand.h>
 
 #include "devices.h"
 
+/*
+ * Phytec's PCM038 comes with 2MiB battery buffered SRAM,
+ * 16 bit width
+ */
+
+static struct platdata_mtd_ram pcm038_sram_data = {
+       .bankwidth = 2,
+};
+
+static struct resource pcm038_sram_resource = {
+       .start = CS1_BASE_ADDR,
+       .end   = CS1_BASE_ADDR + 512 * 1024 - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device pcm038_sram_mtd_device = {
+       .name = "mtd-ram",
+       .id = 0,
+       .dev = {
+               .platform_data = &pcm038_sram_data,
+       },
+       .num_resources = 1,
+       .resource = &pcm038_sram_resource,
+};
+
 /*
  * Phytec's phyCORE-i.MX27 comes with 32MiB flash,
  * 16 bit width
@@ -64,15 +91,14 @@ static int mxc_uart0_pins[] = {
 static int uart_mxc_port0_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART0");
+                       ARRAY_SIZE(mxc_uart0_pins), "UART0");
 }
 
 static int uart_mxc_port0_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart0_pins,
-                       ARRAY_SIZE(mxc_uart0_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART0");
+       mxc_gpio_release_multiple_pins(mxc_uart0_pins,
+                       ARRAY_SIZE(mxc_uart0_pins));
+       return 0;
 }
 
 static int mxc_uart1_pins[] = {
@@ -85,15 +111,14 @@ static int mxc_uart1_pins[] = {
 static int uart_mxc_port1_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART1");
+                       ARRAY_SIZE(mxc_uart1_pins), "UART1");
 }
 
 static int uart_mxc_port1_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart1_pins,
-                       ARRAY_SIZE(mxc_uart1_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART1");
+       mxc_gpio_release_multiple_pins(mxc_uart1_pins,
+                       ARRAY_SIZE(mxc_uart1_pins));
+       return 0;
 }
 
 static int mxc_uart2_pins[] = { PE10_PF_UART3_CTS,
@@ -104,15 +129,14 @@ static int mxc_uart2_pins[] = { PE10_PF_UART3_CTS,
 static int uart_mxc_port2_init(struct platform_device *pdev)
 {
        return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "UART2");
+                       ARRAY_SIZE(mxc_uart2_pins), "UART2");
 }
 
 static int uart_mxc_port2_exit(struct platform_device *pdev)
 {
-       return mxc_gpio_setup_multiple_pins(mxc_uart2_pins,
-                       ARRAY_SIZE(mxc_uart2_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "UART2");
+       mxc_gpio_release_multiple_pins(mxc_uart2_pins,
+                       ARRAY_SIZE(mxc_uart2_pins));
+       return 0;
 }
 
 static struct imxuart_platform_data uart_pdata[] = {
@@ -155,29 +179,47 @@ static int mxc_fec_pins[] = {
 static void gpio_fec_active(void)
 {
        mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-                       ARRAY_SIZE(mxc_fec_pins),
-                       MXC_GPIO_ALLOC_MODE_NORMAL, "FEC");
+                       ARRAY_SIZE(mxc_fec_pins), "FEC");
 }
 
 static void gpio_fec_inactive(void)
 {
-       mxc_gpio_setup_multiple_pins(mxc_fec_pins,
-                       ARRAY_SIZE(mxc_fec_pins),
-                       MXC_GPIO_ALLOC_MODE_RELEASE, "FEC");
+       mxc_gpio_release_multiple_pins(mxc_fec_pins,
+                       ARRAY_SIZE(mxc_fec_pins));
 }
 
+static struct mxc_nand_platform_data pcm038_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
 static struct platform_device *platform_devices[] __initdata = {
        &pcm038_nor_mtd_device,
+       &mxc_w1_master_device,
+       &pcm038_sram_mtd_device,
 };
 
+/* On pcm038 there's a sram attached to CS1, we enable the chipselect here and
+ * setup other stuffs to access the sram. */
+static void __init pcm038_init_sram(void)
+{
+       __raw_writel(0x0000d843, CSCR_U(1));
+       __raw_writel(0x22252521, CSCR_L(1));
+       __raw_writel(0x22220a00, CSCR_A(1));
+}
+
 static void __init pcm038_init(void)
 {
        gpio_fec_active();
+       pcm038_init_sram();
 
        mxc_register_device(&mxc_uart_device0, &uart_pdata[0]);
        mxc_register_device(&mxc_uart_device1, &uart_pdata[1]);
        mxc_register_device(&mxc_uart_device2, &uart_pdata[2]);
 
+       mxc_gpio_mode(PE16_AF_RTCK); /* OWIRE */
+       mxc_register_device(&mxc_nand_device, &pcm038_nand_board_info);
+
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 #ifdef CONFIG_MACH_PCM970_BASEBOARD
index db9431dee1b4c18b80c47f968bc1c5dc99962041..e79659e8176ee76c0525123b27cf5b8993d5ae9f 100644 (file)
@@ -21,5 +21,19 @@ config MACH_MX31LITE
          Include support for MX31 LITEKIT platform. This includes specific
          configurations for the board and its peripherals.
 
+config MACH_MX31_3DS
+       bool "Support MX31PDK (3DS)"
+       default n
+       help
+         Include support for MX31PDK (3DS) platform. This includes specific
+         configurations for the board and its peripherals.
+
+config MACH_MX31MOBOARD
+       bool "Support mx31moboard platforms (EPFL Mobots group)"
+       default n
+       help
+         Include support for mx31moboard platform. This includes specific
+         configurations for the board and its peripherals.
+
 endmenu
 
index 8b21abb71fb0c193564ae0c6ad936444673a032b..5a151540fe836ebeaa233ce873240dabc79aa243 100644 (file)
@@ -8,3 +8,5 @@ obj-y                   := mm.o clock.o devices.o iomux.o
 obj-$(CONFIG_MACH_MX31ADS)     += mx31ads.o
 obj-$(CONFIG_MACH_MX31LITE)    += mx31lite.o
 obj-$(CONFIG_MACH_PCM037)      += pcm037.o
+obj-$(CONFIG_MACH_MX31_3DS)    += mx31pdk.o
+obj-$(CONFIG_MACH_MX31MOBOARD) += mx31moboard.o
index 9f14a871ee7c5f40c53cfd050ba7e50d7350372a..b1746aae1f89eaeaf1eb2fb7a79037b02da4c1bd 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <mach/clock.h>
+#include <mach/hardware.h>
 #include <asm/div64.h>
 
 #include "crm_regs.h"
index a6bdcc07f3c964ea7ed3437fefbe39bb20994262..1d46cb4adf96a5b30f2d4710a73dd57a626e16f0 100644 (file)
@@ -125,19 +125,19 @@ static struct mxc_gpio_port imx_gpio_ports[] = {
                .chip.label = "gpio-0",
                .base = IO_ADDRESS(GPIO1_BASE_ADDR),
                .irq = MXC_INT_GPIO1,
-               .virtual_irq_start = MXC_GPIO_INT_BASE
+               .virtual_irq_start = MXC_GPIO_IRQ_START,
        },
        [1] = {
                .chip.label = "gpio-1",
                .base = IO_ADDRESS(GPIO2_BASE_ADDR),
                .irq = MXC_INT_GPIO2,
-               .virtual_irq_start = MXC_GPIO_INT_BASE + GPIO_NUM_PIN
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 32,
        },
        [2] = {
                .chip.label = "gpio-2",
                .base = IO_ADDRESS(GPIO3_BASE_ADDR),
                .irq = MXC_INT_GPIO3,
-               .virtual_irq_start = MXC_GPIO_INT_BASE + GPIO_NUM_PIN * 2
+               .virtual_irq_start = MXC_GPIO_IRQ_START + 64,
        }
 };
 
@@ -145,3 +145,37 @@ int __init mxc_register_gpios(void)
 {
        return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 }
+
+static struct resource mxc_w1_master_resources[] = {
+       {
+               .start = OWIRE_BASE_ADDR,
+               .end   = OWIRE_BASE_ADDR + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+struct platform_device mxc_w1_master_device = {
+       .name = "mxc_w1",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_w1_master_resources),
+       .resource = mxc_w1_master_resources,
+};
+
+static struct resource mxc_nand_resources[] = {
+       {
+               .start  = NFC_BASE_ADDR,
+               .end    = NFC_BASE_ADDR + 0xfff,
+               .flags  = IORESOURCE_MEM
+       }, {
+               .start  = MXC_INT_NANDFC,
+               .end    = MXC_INT_NANDFC,
+               .flags  = IORESOURCE_IRQ
+       },
+};
+
+struct platform_device mxc_nand_device = {
+       .name = "mxc_nand",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(mxc_nand_resources),
+       .resource = mxc_nand_resources,
+};
index 4dc03f9e6001144fe47c77c7b8a1e894d21751bb..9949ef4e0694dfec46d1361b20691b0a90fb04a8 100644 (file)
@@ -4,3 +4,5 @@ extern struct platform_device mxc_uart_device1;
 extern struct platform_device mxc_uart_device2;
 extern struct platform_device mxc_uart_device3;
 extern struct platform_device mxc_uart_device4;
+extern struct platform_device mxc_w1_master_device;
+extern struct platform_device mxc_nand_device;
index 6e664be8cc13ed187ba28159cec8283ccd1e3c1a..7a5088b519a8c6a1d077b4bd3cd997b7adde7c9f 100644 (file)
@@ -74,17 +74,18 @@ void mxc_iomux_set_pad(enum iomux_pins pin, u32 config)
        u32 field, l;
        void __iomem *reg;
 
-       reg = IOMUXSW_PAD_CTL + (pin + 2) / 3;
+       pin &= IOMUX_PADNUM_MASK;
+       reg = IOMUXSW_PAD_CTL + (pin + 2) / 3 * 4;
        field = (pin + 2) % 3;
 
-       pr_debug("%s: reg offset = 0x%x field = %d\n",
+       pr_debug("%s: reg offset = 0x%x, field = %d\n",
                        __func__, (pin + 2) / 3, field);
 
        spin_lock(&gpio_mux_lock);
 
        l = __raw_readl(reg);
-       l &= ~(0x1ff << (field * 9));
-       l |= config << (field * 9);
+       l &= ~(0x1ff << (field * 10));
+       l |= config << (field * 10);
        __raw_writel(l, reg);
 
        spin_unlock(&gpio_mux_lock);
diff --git a/arch/arm/mach-mx3/mx31moboard.c b/arch/arm/mach-mx3/mx31moboard.c
new file mode 100644 (file)
index 0000000..c29098a
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *  Copyright (C) 2008 Valentin Longchamp, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/types.h>
+#include <linux/init.h>
+
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mtd/partitions.h>
+#include <linux/memory.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+
+#include "devices.h"
+
+static struct physmap_flash_data mx31moboard_flash_data = {
+       .width          = 2,
+};
+
+static struct resource mx31moboard_flash_resource = {
+       .start  = 0xa0000000,
+       .end    = 0xa1ffffff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device mx31moboard_flash = {
+       .name   = "physmap-flash",
+       .id     = 0,
+       .dev    = {
+               .platform_data  = &mx31moboard_flash_data,
+       },
+       .resource = &mx31moboard_flash_resource,
+       .num_resources = 1,
+};
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *devices[] __initdata = {
+       &mx31moboard_flash,
+};
+
+/*
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+
+       mxc_iomux_mode(MX31_PIN_CTS1__CTS1);
+       mxc_iomux_mode(MX31_PIN_RTS1__RTS1);
+       mxc_iomux_mode(MX31_PIN_TXD1__TXD1);
+       mxc_iomux_mode(MX31_PIN_RXD1__RXD1);
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+
+       mxc_iomux_mode(MX31_PIN_CTS2__CTS2);
+       mxc_iomux_mode(MX31_PIN_RTS2__RTS2);
+       mxc_iomux_mode(MX31_PIN_TXD2__TXD2);
+       mxc_iomux_mode(MX31_PIN_RXD2__RXD2);
+
+       mxc_register_device(&mxc_uart_device1, &uart_pdata);
+
+       mxc_iomux_mode(MX31_PIN_PC_RST__CTS5);
+       mxc_iomux_mode(MX31_PIN_PC_VS2__RTS5);
+       mxc_iomux_mode(MX31_PIN_PC_BVD2__TXD5);
+       mxc_iomux_mode(MX31_PIN_PC_BVD1__RXD5);
+
+       mxc_register_device(&mxc_uart_device4, &uart_pdata);
+}
+
+/*
+ * This structure defines static mappings for the mx31moboard.
+ */
+static struct map_desc mx31moboard_io_desc[] __initdata = {
+       {
+               .virtual        = AIPS1_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AIPS1_BASE_ADDR),
+               .length         = AIPS1_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       }, {
+               .virtual        = AIPS2_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AIPS2_BASE_ADDR),
+               .length         = AIPS2_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+/*
+ * Set up static virtual mappings.
+ */
+void __init mx31moboard_map_io(void)
+{
+       mxc_map_io();
+       iotable_init(mx31moboard_io_desc, ARRAY_SIZE(mx31moboard_io_desc));
+}
+
+static void __init mx31moboard_timer_init(void)
+{
+       mxc_clocks_init(26000000);
+       mxc_timer_init("ipg_clk.0");
+}
+
+struct sys_timer mx31moboard_timer = {
+       .init   = mx31moboard_timer_init,
+};
+
+MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
+       /* Maintainer: Valentin Longchamp, EPFL Mobots group */
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx31moboard_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mxc_board_init,
+       .timer          = &mx31moboard_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-mx3/mx31pdk.c b/arch/arm/mach-mx3/mx31pdk.c
new file mode 100644 (file)
index 0000000..d464d06
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/types.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/memory.h>
+#include <asm/mach/map.h>
+#include <mach/common.h>
+#include <mach/board-mx31pdk.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx3.h>
+#include "devices.h"
+
+/*!
+ * @file mx31pdk.c
+ *
+ * @brief This file contains the board-specific initialization routines.
+ *
+ * @ingroup System
+ */
+
+static struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mxc_init_imx_uart(void)
+{
+       mxc_iomux_mode(MX31_PIN_CTS1__CTS1);
+       mxc_iomux_mode(MX31_PIN_RTS1__RTS1);
+       mxc_iomux_mode(MX31_PIN_TXD1__TXD1);
+       mxc_iomux_mode(MX31_PIN_RXD1__RXD1);
+
+       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+}
+
+/*!
+ * This structure defines static mappings for the i.MX31PDK board.
+ */
+static struct map_desc mx31pdk_io_desc[] __initdata = {
+       {
+               .virtual        = AIPS1_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AIPS1_BASE_ADDR),
+               .length         = AIPS1_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       }, {
+               .virtual        = AIPS2_BASE_ADDR_VIRT,
+               .pfn            = __phys_to_pfn(AIPS2_BASE_ADDR),
+               .length         = AIPS2_SIZE,
+               .type           = MT_DEVICE_NONSHARED
+       },
+};
+
+/*!
+ * Set up static virtual mappings.
+ */
+static void __init mx31pdk_map_io(void)
+{
+       mxc_map_io();
+       iotable_init(mx31pdk_io_desc, ARRAY_SIZE(mx31pdk_io_desc));
+}
+
+/*!
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+       mxc_init_imx_uart();
+}
+
+static void __init mx31pdk_timer_init(void)
+{
+       mxc_clocks_init(26000000);
+       mxc_timer_init("ipg_clk.0");
+}
+
+static struct sys_timer mx31pdk_timer = {
+       .init   = mx31pdk_timer_init,
+};
+
+/*
+ * The following uses standard kernel macros defined in arch.h in order to
+ * initialize __mach_desc_MX31PDK data structure.
+ */
+MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
+       /* Maintainer: Freescale Semiconductor, Inc. */
+       .phys_io        = AIPS1_BASE_ADDR,
+       .io_pg_offst    = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x100,
+       .map_io         = mx31pdk_map_io,
+       .init_irq       = mxc_init_irq,
+       .init_machine   = mxc_board_init,
+       .timer          = &mx31pdk_timer,
+MACHINE_END
index 843f68c8ead11d2d1c1ada2bd017d1b93b0cd817..8cea825872221a3efd0b8f15e56a729a5764430a 100644 (file)
 
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mtd/plat-ram.h>
 #include <linux/memory.h>
+#include <linux/gpio.h>
+#include <linux/smc911x.h>
+#include <linux/interrupt.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -32,6 +36,7 @@
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx3.h>
 #include <mach/board-pcm037.h>
+#include <mach/mxc_nand.h>
 
 #include "devices.h"
 
@@ -59,8 +64,63 @@ static struct imxuart_platform_data uart_pdata = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
+static struct resource smc911x_resources[] = {
+       [0] = {
+               .start          = CS1_BASE_ADDR + 0x300,
+               .end            = CS1_BASE_ADDR + 0x300 + SZ_64K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IOMUX_TO_IRQ(MX31_PIN_GPIO3_1),
+               .end            = IOMUX_TO_IRQ(MX31_PIN_GPIO3_1),
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct smc911x_platdata smc911x_info = {
+       .flags          = SMC911X_USE_32BIT,
+       .irq_flags      = IRQF_SHARED | IRQF_TRIGGER_LOW,
+};
+
+static struct platform_device pcm037_eth = {
+       .name           = "smc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc911x_resources),
+       .resource       = smc911x_resources,
+       .dev            = {
+               .platform_data = &smc911x_info,
+       },
+};
+
+static struct platdata_mtd_ram pcm038_sram_data = {
+       .bankwidth = 2,
+};
+
+static struct resource pcm038_sram_resource = {
+       .start = CS4_BASE_ADDR,
+       .end   = CS4_BASE_ADDR + 512 * 1024 - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device pcm037_sram_device = {
+       .name = "mtd-ram",
+       .id = 0,
+       .dev = {
+               .platform_data = &pcm038_sram_data,
+       },
+       .num_resources = 1,
+       .resource = &pcm038_sram_resource,
+};
+
+static struct mxc_nand_platform_data pcm037_nand_board_info = {
+       .width = 1,
+       .hw_ecc = 1,
+};
+
 static struct platform_device *devices[] __initdata = {
        &pcm037_flash,
+       &pcm037_eth,
+       &pcm037_sram_device,
 };
 
 /*
@@ -81,6 +141,16 @@ static void __init mxc_board_init(void)
        mxc_iomux_mode(MX31_PIN_CSPI3_MISO__TXD3);
 
        mxc_register_device(&mxc_uart_device2, &uart_pdata);
+
+       mxc_iomux_mode(MX31_PIN_BATT_LINE__OWIRE);
+       mxc_register_device(&mxc_w1_master_device, NULL);
+
+       /* SMSC9215 IRQ pin */
+       mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO));
+       if (!gpio_request(MX31_PIN_GPIO3_1, "pcm037-eth"))
+               gpio_direction_input(MX31_PIN_GPIO3_1);
+
+       mxc_register_device(&mxc_nand_device, &pcm037_nand_board_info);
 }
 
 /*
index 24c79650f9f359cb0d87c7842f0c3b21db253bd0..8f1f992f002ee6804e19edf7cfd552a993f2f58d 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
+#include <linux/err.h>
 
 #include <mach/netx-regs.h>
 #include <mach/hardware.h>
 
-struct clk {};
-
-static struct clk fb_clk;
-
 static struct clcd_panel *netx_panel;
 
 void netx_clcd_enable(struct clcd_fb *fb)
@@ -85,7 +82,7 @@ int clk_enable(struct clk *clk)
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
-       return &fb_clk;
+       return dev && strcmp(dev_name(dev), "fb") == 0 ? NULL : ERR_PTR(-ENOENT);
 }
 
 void clk_put(struct clk *clk)
diff --git a/arch/arm/mach-netx/include/mach/dma.h b/arch/arm/mach-netx/include/mach/dma.h
deleted file mode 100644 (file)
index 690b3eb..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- *  arch/arm/mach-netx/include/mach/dma.h
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#define MAX_DMA_CHANNELS 0
-#define MAX_DMA_ADDRESS ~0
index 468b92a825850592daad5da82a4fa2cfc48e76ed..c3921cb3b6a6c7bde77b7cfd6f7108c48ccc04a5 100644 (file)
@@ -22,7 +22,7 @@
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)         ((void __iomem *)(a))
+#define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)            (a)
 
 #endif
index 53745a1378de7cb98bdc19710e119f33eef4941e..9a363f297f90e42ab9ad6bdedd0494c1245b978c 100644 (file)
 
 #define PHYS_OFFSET UL(0x80000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus(x)         __virt_to_phys(x)
-#define __bus_to_virt(x)         __phys_to_virt(x)
-
 #endif
 
index 5104a00d40f4c21273f6f7713cf9fbc90793d7d3..08c60ff227befbfb8832e3afbf7a39e64ec31148 100644 (file)
 #define NETX_PFIFO_FILL_LEVEL(pfifo)  NETX_PFIFO_REG(0x180 + ((pfifo)<<2))
 #define NETX_PFIFO_XPEC_ISR(xpec)     NETX_PFIFO_REG(0x400 + ((xpec) << 2))
 
+
+/*******************************
+ * Memory Controller           *
+ *******************************/
+
+/* Registers */
+#define NETX_MEMCR_REG(ofs)               __io(NETX_VA_MEMCR + (ofs))
+#define NETX_MEMCR_SRAM_CTRL(cs)      NETX_MEMCR_REG(0x0 + 4 * (cs)) /* SRAM for CS 0..2 */
+#define NETX_MEMCR_SDRAM_CFG_CTRL     NETX_MEMCR_REG(0x40)
+#define NETX_MEMCR_SDRAM_TIMING_CTRL  NETX_MEMCR_REG(0x44)
+#define NETX_MEMCR_SDRAM_MODE         NETX_MEMCR_REG(0x48)
+#define NETX_MEMCR_SDRAM_EXT_MODE     NETX_MEMCR_REG(0x4c)
+#define NETX_MEMCR_PRIO_TIMESLOT_CTRL NETX_MEMCR_REG(0x80)
+#define NETX_MEMCR_PRIO_ACCESS_CTRL   NETX_MEMCR_REG(0x84)
+
+/* Bits */
+#define NETX_MEMCR_SRAM_CTRL_WIDTHEXTMEM(x)       (((x) & 0x3)  << 24)
+#define NETX_MEMCR_SRAM_CTRL_WSPOSTPAUSEEXTMEM(x) (((x) & 0x3)  << 16)
+#define NETX_MEMCR_SRAM_CTRL_WSPREPASEEXTMEM(x)   (((x) & 0x3)  << 8)
+#define NETX_MEMCR_SRAM_CTRL_WSEXTMEM(x)          (((x) & 0x1f) << 0)
+
+
 /*******************************
  * Dual Port Memory            *
  *******************************/
index 7c540c1f01fab84a1fb797522649ca14427c1b4c..d51d627ce7cfb081cef650b6ac54bd98f859532d 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/mach/time.h>
 #include <mach/netx-regs.h>
 
+#define TIMER_CLOCKEVENT 0
+#define TIMER_CLOCKSOURCE 1
+
+static void netx_set_mode(enum clock_event_mode mode,
+               struct clock_event_device *clk)
+{
+       u32 tmode;
+
+       /* disable timer */
+       writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT));
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               writel(LATCH, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT));
+               tmode = NETX_GPIO_COUNTER_CTRL_RST_EN |
+                       NETX_GPIO_COUNTER_CTRL_IRQ_EN |
+                       NETX_GPIO_COUNTER_CTRL_RUN;
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               writel(0, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKEVENT));
+               tmode = NETX_GPIO_COUNTER_CTRL_IRQ_EN |
+                       NETX_GPIO_COUNTER_CTRL_RUN;
+               break;
+
+       default:
+               WARN(1, "%s: unhandled mode %d\n", __func__, mode);
+               /* fall through */
+
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_RESUME:
+               tmode = 0;
+               break;
+       }
+
+       writel(tmode, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKEVENT));
+}
+
+static int netx_set_next_event(unsigned long evt,
+               struct clock_event_device *clk)
+{
+       writel(0 - evt, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKEVENT));
+       return 0;
+}
+
+static struct clock_event_device netx_clockevent = {
+       .name = "netx-timer" __stringify(TIMER_CLOCKEVENT),
+       .shift = 32,
+       .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_next_event = netx_set_next_event,
+       .set_mode = netx_set_mode,
+};
+
 /*
  * IRQ handler for the timer
  */
 static irqreturn_t
 netx_timer_interrupt(int irq, void *dev_id)
 {
-       timer_tick();
+       struct clock_event_device *evt = &netx_clockevent;
 
        /* acknowledge interrupt */
        writel(COUNTER_BIT(0), NETX_GPIO_IRQ);
 
+       evt->event_handler(evt);
+
        return IRQ_HANDLED;
 }
 
 static struct irqaction netx_timer_irq = {
-       .name           = "NetX Timer Tick",
-       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = netx_timer_interrupt,
+       .name           = "NetX Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = netx_timer_interrupt,
 };
 
 cycle_t netx_get_cycles(void)
 {
-       return readl(NETX_GPIO_COUNTER_CURRENT(1));
+       return readl(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE));
 }
 
 static struct clocksource clocksource_netx = {
-       .name           = "netx_timer",
+       .name           = "netx_timer",
        .rating         = 200,
        .read           = netx_get_cycles,
        .mask           = CLOCKSOURCE_MASK(32),
-       .shift          = 20,
+       .shift          = 20,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
@@ -77,24 +134,37 @@ static void __init netx_timer_init(void)
        /* acknowledge interrupt */
        writel(COUNTER_BIT(0), NETX_GPIO_IRQ);
 
-       /* Enable the interrupt in the specific timer register and start timer */
+       /* Enable the interrupt in the specific timer
+        * register and start timer
+        */
        writel(COUNTER_BIT(0), NETX_GPIO_IRQ_ENABLE);
        writel(NETX_GPIO_COUNTER_CTRL_IRQ_EN | NETX_GPIO_COUNTER_CTRL_RUN,
-               NETX_GPIO_COUNTER_CTRL(0));
+                       NETX_GPIO_COUNTER_CTRL(0));
 
        setup_irq(NETX_IRQ_TIMER0, &netx_timer_irq);
 
        /* Setup timer one for clocksource */
-        writel(0, NETX_GPIO_COUNTER_CTRL(1));
-        writel(0, NETX_GPIO_COUNTER_CURRENT(1));
-        writel(0xFFFFFFFF, NETX_GPIO_COUNTER_MAX(1));
+       writel(0, NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE));
+       writel(0, NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE));
+       writel(0xffffffff, NETX_GPIO_COUNTER_MAX(TIMER_CLOCKSOURCE));
 
-        writel(NETX_GPIO_COUNTER_CTRL_RUN,
-                NETX_GPIO_COUNTER_CTRL(1));
+       writel(NETX_GPIO_COUNTER_CTRL_RUN,
+                       NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE));
 
        clocksource_netx.mult =
                clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_netx.shift);
        clocksource_register(&clocksource_netx);
+
+       netx_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
+                       netx_clockevent.shift);
+       netx_clockevent.max_delta_ns =
+               clockevent_delta2ns(0xfffffffe, &netx_clockevent);
+       /* with max_delta_ns >= delta2ns(0x800) the system currently runs fine.
+        * Adding some safety ... */
+       netx_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xa00, &netx_clockevent);
+       netx_clockevent.cpumask = cpumask_of_cpu(0);
+       clockevents_register_device(&netx_clockevent);
 }
 
 struct sys_timer netx_timer = {
index 32eabf5dfa4fcd736ec332087963b6a1be6552eb..8fc6205dc3a5417fd3f0e12ea339db1d8932929a 100644 (file)
@@ -92,10 +92,10 @@ static int xc_check_ptr(struct xc *x, unsigned long adr, unsigned int size)
        return -1;
 }
 
-static int xc_patch(struct xc *x, void *patch, int count)
+static int xc_patch(struct xc *x, const void *patch, int count)
 {
        unsigned int val, adr;
-       unsigned int *data = patch;
+       const unsigned int *data = patch;
 
        int i;
        for (i = 0; i < count; i++) {
@@ -117,7 +117,7 @@ int xc_request_firmware(struct xc *x)
        struct fw_header *head;
        unsigned int size;
        int i;
-       void *src;
+       const void *src;
        unsigned long dst;
 
        sprintf(name, "xc%d.bin", x->no);
diff --git a/arch/arm/mach-ns9xxx/include/mach/dma.h b/arch/arm/mach-ns9xxx/include/mach/dma.h
deleted file mode 100644 (file)
index 3f50d8c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/dma.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can 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_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#endif /* ifndef __ASM_ARCH_DMA_H */
index 6dbb2030f5631b3c6e2dbf0abdd5d9a331383745..76631128e11cfb467649c02b5bbe4dba488eaf92 100644 (file)
@@ -11,8 +11,6 @@
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-#include <asm/memory.h>
-
 /*
  * NetSilicon NS9xxx internal mapping:
  *
index 027bf649645adfc738dda0224dc856e0725f6a53..f08451d2e1bc87d69a1b861e2f9175dd7a5cef45 100644 (file)
@@ -13,7 +13,7 @@
 
 #define IO_SPACE_LIMIT  0xffffffff /* XXX */
 
-#define __io(a)         ((void __iomem *)(a))
+#define __io(a)                __typesafe_io(a)
 #define __mem_pci(a)    (a)
 #define __mem_isa(a)    (IO_BASE + (a))
 
index 649ee6235b943404161d7325d8c9025f9a3acb6b..6107193adbfe67ec4a38d11c2f6b7a23ce900b81 100644 (file)
@@ -21,7 +21,4 @@
 
 #define PHYS_OFFSET    UL(0x00000000)
 
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
 #endif
index 79f0b1f8497be84a210e7330b4a87843c5eb14c1..10a301e32434639e737f18db0832e6657001d66c 100644 (file)
@@ -4,16 +4,19 @@ comment "OMAP Core Type"
 config ARCH_OMAP730
        depends on ARCH_OMAP1
        bool "OMAP730 Based System"
+       select CPU_ARM926T
        select ARCH_OMAP_OTG
 
 config ARCH_OMAP15XX
        depends on ARCH_OMAP1
        default y
        bool "OMAP15xx Based System"
+       select CPU_ARM925T
 
 config ARCH_OMAP16XX
        depends on ARCH_OMAP1
        bool "OMAP16xx Based System"
+       select CPU_ARM926T
        select ARCH_OMAP_OTG
 
 comment "OMAP Board Type"
index db789461fca49ed3b38530daa05d779320f1dd13..30308294e7c1d1ca87e881295789b9f881e0ddfe 100644 (file)
@@ -205,7 +205,7 @@ static struct platform_device *devices[] __initdata = {
 
 static int nand_dev_ready(struct omap_nand_platform_data *data)
 {
-       return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN);
+       return gpio_get_value(P2_NAND_RB_GPIO_PIN);
 }
 
 static struct omap_uart_config fsample_uart_config __initdata = {
@@ -223,8 +223,9 @@ static struct omap_board_config_kernel fsample_config[] = {
 
 static void __init omap_fsample_init(void)
 {
-       if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN)))
-               nand_data.dev_ready = nand_dev_ready;
+       if (gpio_request(P2_NAND_RB_GPIO_PIN, "NAND ready") < 0)
+               BUG();
+       nand_data.dev_ready = nand_dev_ready;
 
        omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
        omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
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..b240c5f861da440080c77715e284b87ce604d601 100644 (file)
@@ -250,11 +250,8 @@ static struct platform_device h2_kp_device = {
 #if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
 static int h2_transceiver_mode(struct device *dev, int state)
 {
-       if (state & IR_SIRMODE)
-               omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 0);
-       else    /* MIR/FIR */
-               omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 1);
-
+       /* SIR when low, else MIR/FIR when HIGH */
+       gpio_set_value(H2_IRDA_FIRSEL_GPIO_PIN, !(state & IR_SIRMODE));
        return 0;
 }
 #endif
@@ -342,16 +339,31 @@ static struct platform_device *h2_devices[] __initdata = {
 
 static void __init h2_init_smc91x(void)
 {
-       if ((omap_request_gpio(0)) < 0) {
+       if (gpio_request(0, "SMC91x irq") < 0) {
                printk("Error requesting gpio 0 for smc91x irq\n");
                return;
        }
 }
 
+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 +393,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 +403,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 },
 };
@@ -409,7 +411,7 @@ static struct omap_board_config_kernel h2_config[] __initdata = {
 
 static int h2_nand_dev_ready(struct omap_nand_platform_data *data)
 {
-       return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN);
+       return gpio_get_value(H2_NAND_RB_GPIO_PIN);
 }
 
 static void __init h2_init(void)
@@ -428,8 +430,9 @@ static void __init h2_init(void)
 
        h2_nand_resource.end = h2_nand_resource.start = OMAP_CS2B_PHYS;
        h2_nand_resource.end += SZ_4K - 1;
-       if (!(omap_request_gpio(H2_NAND_RB_GPIO_PIN)))
-               h2_nand_data.dev_ready = h2_nand_dev_ready;
+       if (gpio_request(H2_NAND_RB_GPIO_PIN, "NAND ready") < 0)
+               BUG();
+       gpio_direction_input(H2_NAND_RB_GPIO_PIN);
 
        omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
        omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
@@ -441,10 +444,10 @@ static void __init h2_init(void)
        /* Irda */
 #if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
        omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A);
-       if (!(omap_request_gpio(H2_IRDA_FIRSEL_GPIO_PIN))) {
-               omap_set_gpio_direction(H2_IRDA_FIRSEL_GPIO_PIN, 0);
-               h2_irda_data.transceiver_mode = h2_transceiver_mode;
-       }
+       if (gpio_request(H2_IRDA_FIRSEL_GPIO_PIN, "IRDA mode") < 0)
+               BUG();
+       gpio_direction_output(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+       h2_irda_data.transceiver_mode = h2_transceiver_mode;
 #endif
 
        platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
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 adfcd7b513930cdaa677aa835e7e3d24f9d1171d..5157eea9be3547fa1a5a14ee3cfe94769481a144 100644 (file)
@@ -447,15 +447,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,7 +457,6 @@ 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 },
 };
@@ -498,7 +488,7 @@ static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
 
 static int nand_dev_ready(struct omap_nand_platform_data *data)
 {
-       return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
+       return gpio_get_value(H3_NAND_RB_GPIO_PIN);
 }
 
 static void __init h3_init(void)
@@ -516,8 +506,9 @@ static void __init h3_init(void)
 
        nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS;
        nand_resource.end += SZ_4K - 1;
-       if (!(omap_request_gpio(H3_NAND_RB_GPIO_PIN)))
-               nand_data.dev_ready = nand_dev_ready;
+       if (gpio_request(H3_NAND_RB_GPIO_PIN, "NAND ready") < 0)
+               BUG();
+       nand_data.dev_ready = nand_dev_ready;
 
        /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */
        /* GPIO10 pullup/down register, Enable pullup on GPIO10 */
@@ -537,7 +528,7 @@ static void __init h3_init(void)
 static void __init h3_init_smc91x(void)
 {
        omap_cfg_reg(W15_1710_GPIO40);
-       if (omap_request_gpio(40) < 0) {
+       if (gpio_request(40, "SMC91x irq") < 0) {
                printk("Error requesting gpio 40 for smc91x irq\n");
                return;
        }
index cbc11be5cd2a9ebcbc1fc43f82308f17c969076c..af2fb9070083386d7eb9c2716298a548506437e2 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),
@@ -301,7 +302,7 @@ static void __init innovator_init_smc91x(void)
                           OMAP1510_FPGA_RST);
                udelay(750);
        } else {
-               if ((omap_request_gpio(0)) < 0) {
+               if (gpio_request(0, "SMC91x irq") < 0) {
                        printk("Error requesting gpio 0 for smc91x irq\n");
                        return;
                }
@@ -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,
+               .wires                  = 4,
+               .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..4970c402a59431d14c439e7ccfd650de3658539f 100644 (file)
@@ -35,6 +35,7 @@
 #include <mach/aic23.h>
 #include <mach/omapfb.h>
 #include <mach/lcd_mipid.h>
+#include <mach/mmc.h>
 
 #define ADS7846_PENDOWN_GPIO   15
 
@@ -102,7 +103,7 @@ static void mipid_shutdown(struct mipid_platform_data *pdata)
 {
        if (pdata->nreset_gpio != -1) {
                printk(KERN_INFO "shutdown LCD\n");
-               omap_set_gpio_dataout(pdata->nreset_gpio, 0);
+               gpio_set_value(pdata->nreset_gpio, 0);
                msleep(120);
        }
 }
@@ -124,13 +125,13 @@ static void mipid_dev_init(void)
 
 static void ads7846_dev_init(void)
 {
-       if (omap_request_gpio(ADS7846_PENDOWN_GPIO) < 0)
+       if (gpio_request(ADS7846_PENDOWN_GPIO, "ADS7846 pendown") < 0)
                printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
 }
 
 static int ads7846_get_pendown_state(void)
 {
-       return !omap_get_gpio_datain(ADS7846_PENDOWN_GPIO);
+       return !gpio_get_value(ADS7846_PENDOWN_GPIO);
 }
 
 static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = {
@@ -173,26 +174,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)
@@ -228,9 +271,9 @@ static void nokia770_audio_pwr_up(void)
        /* Turn on codec */
        aic23_power_up();
 
-       if (omap_get_gpio_datain(HEADPHONE_GPIO))
+       if (gpio_get_value(HEADPHONE_GPIO))
                /* HP not connected, turn on amplifier */
-               omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 1);
+               gpio_set_value(AMPLIFIER_CTRL_GPIO, 1);
        else
                /* HP connected, do not turn on amplifier */
                printk("HP connected\n");
@@ -250,7 +293,7 @@ static DECLARE_DELAYED_WORK(codec_power_down_work, codec_delayed_power_down);
 static void nokia770_audio_pwr_down(void)
 {
        /* Turn off amplifier */
-       omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 0);
+       gpio_set_value(AMPLIFIER_CTRL_GPIO, 0);
 
        /* Turn off codec: schedule delayed work */
        schedule_delayed_work(&codec_power_down_work, HZ / 20); /* 50ms */
@@ -335,6 +378,7 @@ static void __init omap_nokia770_init(void)
        omap_dsp_init();
        ads7846_dev_init();
        mipid_dev_init();
+       nokia770_mmc_init();
 }
 
 static void __init omap_nokia770_map_io(void)
index 3e766e49f7cc05faced8c31b01150a56e8fe1471..ff9e67baa5c9f2c818b64c643c23e1bb622abca8 100644 (file)
@@ -188,7 +188,8 @@ static struct gpio_led tps_leds[] = {
        /* NOTE:  D9 and D2 have hardware blink support.
         * Also, D9 requires non-battery power.
         */
-       { .gpio = OSK_TPS_GPIO_LED_D9, .name = "d9", },
+       { .gpio = OSK_TPS_GPIO_LED_D9, .name = "d9",
+                       .default_trigger = "ide-disk", },
        { .gpio = OSK_TPS_GPIO_LED_D2, .name = "d2", },
        { .gpio = OSK_TPS_GPIO_LED_D3, .name = "d3", .active_low = 1,
                        .default_trigger = "heartbeat", },
@@ -260,7 +261,6 @@ static struct i2c_board_info __initdata osk_i2c_board_info[] = {
        },
        /* TODO when driver support is ready:
         *  - aic23 audio chip at 0x1a
-        *  - on Mistral, 24c04 eeprom at 0x50
         *  - optionally on Mistral, ov9640 camera sensor at 0x30
         */
 };
@@ -288,7 +288,7 @@ static void __init osk_init_cf(void)
                return;
        }
        /* the CF I/O IRQ is really active-low */
-       set_irq_type(OMAP_GPIO_IRQ(62), IRQ_TYPE_EDGE_FALLING);
+       set_irq_type(gpio_to_irq(62), IRQ_TYPE_EDGE_FALLING);
 }
 
 static void __init osk_init_irq(void)
@@ -337,11 +337,28 @@ static struct omap_board_config_kernel osk_config[] __initdata = {
 #ifdef CONFIG_OMAP_OSK_MISTRAL
 
 #include <linux/input.h>
+#include <linux/i2c/at24.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
 
 #include <mach/keypad.h>
 
+static struct at24_platform_data at24c04 = {
+       .byte_len       = SZ_4K / 8,
+       .page_size      = 16,
+};
+
+static struct i2c_board_info __initdata mistral_i2c_board_info[] = {
+       {
+               /* NOTE:  powered from LCD supply */
+               I2C_BOARD_INFO("24c04", 0x50),
+               .platform_data  = &at24c04,
+       },
+       /* TODO when driver support is ready:
+        *  - optionally ov9640 camera sensor at 0x30
+        */
+};
+
 static const int osk_keymap[] = {
        /* KEY(col, row, code) */
        KEY(0, 0, KEY_F1),              /* SW4 */
@@ -483,23 +500,30 @@ static void __init osk_mistral_init(void)
        omap_cfg_reg(P20_1610_GPIO4);   /* PENIRQ */
        gpio_request(4, "ts_int");
        gpio_direction_input(4);
-       set_irq_type(OMAP_GPIO_IRQ(4), IRQ_TYPE_EDGE_FALLING);
+       set_irq_type(gpio_to_irq(4), IRQ_TYPE_EDGE_FALLING);
 
        spi_register_board_info(mistral_boardinfo,
                        ARRAY_SIZE(mistral_boardinfo));
 
-       /* the sideways button (SW1) is for use as a "wakeup" button */
+       /* the sideways button (SW1) is for use as a "wakeup" button
+        *
+        * NOTE:  The Mistral board has the wakeup button (SW1) wired
+        * to the LCD 3.3V rail, which is powered down during suspend.
+        * To allow this button to wake up the omap, work around this
+        * HW bug by rewiring SW1 to use the main 3.3V rail.
+        */
        omap_cfg_reg(N15_1610_MPUIO2);
        if (gpio_request(OMAP_MPUIO(2), "wakeup") == 0) {
                int ret = 0;
+               int irq = gpio_to_irq(OMAP_MPUIO(2));
 
                gpio_direction_input(OMAP_MPUIO(2));
-               set_irq_type(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), IRQ_TYPE_EDGE_RISING);
+               set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
 #ifdef CONFIG_PM
                /* share the IRQ in case someone wants to use the
                 * button for more than wakeup from system sleep.
                 */
-               ret = request_irq(OMAP_GPIO_IRQ(OMAP_MPUIO(2)),
+               ret = request_irq(irq,
                                &osk_mistral_wake_interrupt,
                                IRQF_SHARED, "mistral_wakeup",
                                &osk_mistral_wake_interrupt);
@@ -508,7 +532,7 @@ static void __init osk_mistral_init(void)
                        printk(KERN_ERR "OSK+Mistral: no wakeup irq, %d?\n",
                                ret);
                } else
-                       enable_irq_wake(OMAP_GPIO_IRQ(OMAP_MPUIO(2)));
+                       enable_irq_wake(irq);
 #endif
        } else
                printk(KERN_ERR "OSK+Mistral: wakeup button is awol\n");
@@ -520,6 +544,9 @@ static void __init osk_mistral_init(void)
        if (gpio_request(2, "lcd_pwr") == 0)
                gpio_direction_output(2, 1);
 
+       i2c_register_board_info(1, mistral_i2c_board_info,
+                       ARRAY_SIZE(mistral_i2c_board_info));
+
        platform_add_devices(mistral_devices, ARRAY_SIZE(mistral_devices));
 }
 #else
index b58043644a6f55681ba5c66cb1d3a47f03687116..75e32d35afd9301888e55f8dbb177ffc566268c0 100644 (file)
@@ -255,7 +255,7 @@ static void palmte_get_power_status(struct apm_power_info *info, int *battery)
 {
        int charging, batt, hi, lo, mid;
 
-       charging = !omap_get_gpio_datain(PALMTE_DC_GPIO);
+       charging = !gpio_get_value(PALMTE_DC_GPIO);
        batt = battery[0];
        if (charging)
                batt -= 60;
@@ -316,7 +316,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 },
 };
@@ -335,11 +334,11 @@ static void palmte_headphones_detect(void *data, int state)
 {
        if (state) {
                /* Headphones connected, disable speaker */
-               omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 0);
+               gpio_set_value(PALMTE_SPEAKER_GPIO, 0);
                printk(KERN_INFO "PM: speaker off\n");
        } else {
                /* Headphones unplugged, re-enable speaker */
-               omap_set_gpio_dataout(PALMTE_SPEAKER_GPIO, 1);
+               gpio_set_value(PALMTE_SPEAKER_GPIO, 1);
                printk(KERN_INFO "PM: speaker on\n");
        }
 }
@@ -347,18 +346,18 @@ static void palmte_headphones_detect(void *data, int state)
 static void __init palmte_misc_gpio_setup(void)
 {
        /* Set TSC2102 PINTDAV pin as input (used by TSC2102 driver) */
-       if (omap_request_gpio(PALMTE_PINTDAV_GPIO)) {
+       if (gpio_request(PALMTE_PINTDAV_GPIO, "TSC2102 PINTDAV") < 0) {
                printk(KERN_ERR "Could not reserve PINTDAV GPIO!\n");
                return;
        }
-       omap_set_gpio_direction(PALMTE_PINTDAV_GPIO, 1);
+       gpio_direction_input(PALMTE_PINTDAV_GPIO);
 
        /* Set USB-or-DC-IN pin as input (unused) */
-       if (omap_request_gpio(PALMTE_USB_OR_DC_GPIO)) {
+       if (gpio_request(PALMTE_USB_OR_DC_GPIO, "USB/DC-IN") < 0) {
                printk(KERN_ERR "Could not reserve cable signal GPIO!\n");
                return;
        }
-       omap_set_gpio_direction(PALMTE_USB_OR_DC_GPIO, 1);
+       gpio_direction_input(PALMTE_USB_OR_DC_GPIO);
 }
 
 static void __init omap_palmte_init(void)
index 40f9860a09df243147c87ce320fa41588ffe0dfc..5c001afe806235117685c5904bbef5af79e2e958 100644 (file)
@@ -268,7 +268,7 @@ static struct platform_device *palmtt_devices[] __initdata = {
 
 static int palmtt_get_pendown_state(void)
 {
-       return !omap_get_gpio_datain(6);
+       return !gpio_get_value(6);
 }
 
 static const struct ads7846_platform_data palmtt_ts_info = {
index e719294250b1f5dedf0bbec0a486ee855caf536d..cc05257eb1cddd7720b182dd7fd52444e8510636 100644 (file)
@@ -239,7 +239,7 @@ static struct platform_device *devices[] __initdata = {
 static int
 palmz71_get_pendown_state(void)
 {
-       return !omap_get_gpio_datain(PALMZ71_PENIRQ_GPIO);
+       return !gpio_get_value(PALMZ71_PENIRQ_GPIO);
 }
 
 static const struct ads7846_platform_data palmz71_ts_info = {
@@ -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},
 };
@@ -295,13 +284,13 @@ static struct omap_board_config_kernel palmz71_config[] __initdata = {
 static irqreturn_t
 palmz71_powercable(int irq, void *dev_id)
 {
-       if (omap_get_gpio_datain(PALMZ71_USBDETECT_GPIO)) {
+       if (gpio_get_value(PALMZ71_USBDETECT_GPIO)) {
                printk(KERN_INFO "PM: Power cable connected\n");
-               set_irq_type(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO),
+               set_irq_type(gpio_to_irq(PALMZ71_USBDETECT_GPIO),
                                IRQ_TYPE_EDGE_FALLING);
        } else {
                printk(KERN_INFO "PM: Power cable disconnected\n");
-               set_irq_type(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO),
+               set_irq_type(gpio_to_irq(PALMZ71_USBDETECT_GPIO),
                                IRQ_TYPE_EDGE_RISING);
        }
        return IRQ_HANDLED;
@@ -323,29 +312,28 @@ palmz71_gpio_setup(int early)
 {
        if (early) {
                /* Only set GPIO1 so we have a working serial */
-               omap_set_gpio_dataout(1, 1);
-               omap_set_gpio_direction(1, 0);
+               gpio_direction_output(1, 1);
        } else {
                /* Set MMC/SD host WP pin as input */
-               if (omap_request_gpio(PALMZ71_MMC_WP_GPIO)) {
+               if (gpio_request(PALMZ71_MMC_WP_GPIO, "MMC WP") < 0) {
                        printk(KERN_ERR "Could not reserve WP GPIO!\n");
                        return;
                }
-               omap_set_gpio_direction(PALMZ71_MMC_WP_GPIO, 1);
+               gpio_direction_input(PALMZ71_MMC_WP_GPIO);
 
                /* Monitor the Power-cable-connected signal */
-               if (omap_request_gpio(PALMZ71_USBDETECT_GPIO)) {
+               if (gpio_request(PALMZ71_USBDETECT_GPIO, "USB detect") < 0) {
                        printk(KERN_ERR
                                "Could not reserve cable signal GPIO!\n");
                        return;
                }
-               omap_set_gpio_direction(PALMZ71_USBDETECT_GPIO, 1);
-               if (request_irq(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO),
+               gpio_direction_input(PALMZ71_USBDETECT_GPIO);
+               if (request_irq(gpio_to_irq(PALMZ71_USBDETECT_GPIO),
                                palmz71_powercable, IRQF_SAMPLE_RANDOM,
                                "palmz71-cable", 0))
                        printk(KERN_ERR
                                        "IRQ request for power cable failed!\n");
-               palmz71_powercable(OMAP_GPIO_IRQ(PALMZ71_USBDETECT_GPIO), 0);
+               palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), 0);
        }
 }
 
index b715917bfdaf89852fac68e6715314205fadbc3b..3b9f907aa89908569da3e101a471083630787146 100644 (file)
@@ -205,7 +205,7 @@ static struct platform_device *devices[] __initdata = {
 
 static int nand_dev_ready(struct omap_nand_platform_data *data)
 {
-       return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN);
+       return gpio_get_value(P2_NAND_RB_GPIO_PIN);
 }
 
 static struct omap_uart_config perseus2_uart_config __initdata = {
@@ -223,8 +223,9 @@ static struct omap_board_config_kernel perseus2_config[] __initdata = {
 
 static void __init omap_perseus2_init(void)
 {
-       if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN)))
-               nand_data.dev_ready = nand_dev_ready;
+       if (gpio_request(P2_NAND_RB_GPIO_PIN, "NAND ready") < 0)
+               BUG();
+       nand_data.dev_ready = nand_dev_ready;
 
        omap_cfg_reg(L3_1610_FLASH_CS2B_OE);
        omap_cfg_reg(M8_1610_FLASH_CS2B_WE);
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..8171fe0ca082aeb8e0fb59999cd0e5eb6a1cadc7 100644 (file)
@@ -378,15 +378,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 +405,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 },
 };
@@ -436,14 +426,9 @@ static void __init omap_sx1_init(void)
        omap_request_gpio(1);   /* A_IRDA_OFF */
        omap_request_gpio(11);  /* A_SWITCH */
        omap_request_gpio(15);  /* A_USB_ON */
-       omap_set_gpio_direction(1, 0);/* gpio1 -> output */
-       omap_set_gpio_direction(11, 0);/* gpio11 -> output */
-       omap_set_gpio_direction(15, 0);/* gpio15 -> output */
-       /* set GPIO data */
-       omap_set_gpio_dataout(1, 1);/*A_IRDA_OFF = 1 */
-       omap_set_gpio_dataout(11, 0);/*A_SWITCH = 0 */
-       omap_set_gpio_dataout(15, 0);/*A_USB_ON = 0 */
-
+       gpio_direction_output(1, 1);    /*A_IRDA_OFF = 1 */
+       gpio_direction_output(11, 0);   /*A_SWITCH = 0 */
+       gpio_direction_output(15, 0);   /*A_USB_ON = 0 */
 }
 /*----------------------------------------*/
 static void __init omap_sx1_init_irq(void)
index 45a01311669aecf643a02273db3000268d6e8af7..c224f3c642353b2705c82c69d91e5537500acad2 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>
@@ -140,21 +141,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 },
 };
 
@@ -168,29 +160,27 @@ static void __init voiceblue_init_irq(void)
 static void __init voiceblue_init(void)
 {
        /* Watchdog */
-       omap_request_gpio(0);
+       gpio_request(0, "Watchdog");
        /* smc91x reset */
-       omap_request_gpio(7);
-       omap_set_gpio_direction(7, 0);
-       omap_set_gpio_dataout(7, 1);
+       gpio_request(7, "SMC91x reset");
+       gpio_direction_output(7, 1);
        udelay(2);      /* wait at least 100ns */
-       omap_set_gpio_dataout(7, 0);
+       gpio_set_value(7, 0);
        mdelay(50);     /* 50ms until PHY ready */
        /* smc91x interrupt pin */
-       omap_request_gpio(8);
+       gpio_request(8, "SMC91x irq");
        /* 16C554 reset*/
-       omap_request_gpio(6);
-       omap_set_gpio_direction(6, 0);
-       omap_set_gpio_dataout(6, 0);
+       gpio_request(6, "16C554 reset");
+       gpio_direction_output(6, 0);
        /* 16C554 interrupt pins */
-       omap_request_gpio(12);
-       omap_request_gpio(13);
-       omap_request_gpio(14);
-       omap_request_gpio(15);
-       set_irq_type(OMAP_GPIO_IRQ(12), IRQ_TYPE_EDGE_RISING);
-       set_irq_type(OMAP_GPIO_IRQ(13), IRQ_TYPE_EDGE_RISING);
-       set_irq_type(OMAP_GPIO_IRQ(14), IRQ_TYPE_EDGE_RISING);
-       set_irq_type(OMAP_GPIO_IRQ(15), IRQ_TYPE_EDGE_RISING);
+       gpio_request(12, "16C554 irq");
+       gpio_request(13, "16C554 irq");
+       gpio_request(14, "16C554 irq");
+       gpio_request(15, "16C554 irq");
+       set_irq_type(gpio_to_irq(12), IRQ_TYPE_EDGE_RISING);
+       set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
+       set_irq_type(gpio_to_irq(14), IRQ_TYPE_EDGE_RISING);
+       set_irq_type(gpio_to_irq(15), IRQ_TYPE_EDGE_RISING);
 
        platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
        omap_board_config = voiceblue_config;
@@ -244,19 +234,18 @@ static int wdt_gpio_state;
 
 void voiceblue_wdt_enable(void)
 {
-       omap_set_gpio_direction(0, 0);
-       omap_set_gpio_dataout(0, 0);
-       omap_set_gpio_dataout(0, 1);
-       omap_set_gpio_dataout(0, 0);
+       gpio_direction_output(0, 0);
+       gpio_set_value(0, 1);
+       gpio_set_value(0, 0);
        wdt_gpio_state = 0;
 }
 
 void voiceblue_wdt_disable(void)
 {
-       omap_set_gpio_dataout(0, 0);
-       omap_set_gpio_dataout(0, 1);
-       omap_set_gpio_dataout(0, 0);
-       omap_set_gpio_direction(0, 1);
+       gpio_set_value(0, 0);
+       gpio_set_value(0, 1);
+       gpio_set_value(0, 0);
+       gpio_direction_input(0);
 }
 
 void voiceblue_wdt_ping(void)
@@ -265,7 +254,7 @@ void voiceblue_wdt_ping(void)
                return;
 
        wdt_gpio_state = !wdt_gpio_state;
-       omap_set_gpio_dataout(0, wdt_gpio_state);
+       gpio_set_value(0, wdt_gpio_state);
 }
 
 void voiceblue_reset(void)
index 5635b511ab6f0b5d1546fef5dec6ed52d70e3c96..c1dcdf18d8ddecaeaf14706cb839a1a424aae22f 100644 (file)
@@ -705,7 +705,6 @@ 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,
@@ -720,7 +719,7 @@ 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,
index e382b438c64ed5d42d49f05e1586ab03c3218aa5..77382d8b6b2f61a4d0c4a93fb4357ba48220d061 100644 (file)
@@ -22,6 +22,7 @@
 #include <mach/board.h>
 #include <mach/mux.h>
 #include <mach/gpio.h>
+#include <mach/mmc.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -99,6 +100,95 @@ 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].wires == 4) {
+                       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].wires == 4) {
+                               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         0xfffea000
index 04995381aa5c9965890b74704b628b6ee7d00da5..4f2b8a7adb19a3ff8fb1673e21b3c3e9752de567 100644 (file)
@@ -177,9 +177,9 @@ void omap1510_fpga_init_irq(void)
         * NOTE: For general GPIO/MPUIO access and interrupts, please see
         * gpio.[ch]
         */
-       omap_request_gpio(13);
-       omap_set_gpio_direction(13, 1);
-       set_irq_type(OMAP_GPIO_IRQ(13), IRQ_TYPE_EDGE_RISING);
+       gpio_request(13, "FPGA irq");
+       gpio_direction_input(13);
+       set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
        set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
 }
 
index 13083d7e692d5b32bd3d36c5bedea570aace62df..89bb8756f4503309434ac4b723d42f8cd076bd9b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <mach/cpu.h>
 
 #define OMAP_DIE_ID_0          0xfffe1800
 #define OMAP_DIE_ID_1          0xfffe1804
@@ -30,6 +31,8 @@ struct omap_id {
        u32     type;           /* Cpu id bits [31:08], cpu class bits [07:00] */
 };
 
+static unsigned int omap_revision;
+
 /* Register values to detect the OMAP version */
 static struct omap_id omap_ids[] __initdata = {
        { .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000},
@@ -53,6 +56,12 @@ static struct omap_id omap_ids[] __initdata = {
        { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
 };
 
+unsigned int omap_rev(void)
+{
+       return omap_revision;
+}
+EXPORT_SYMBOL(omap_rev);
+
 /*
  * Get OMAP type from PROD_ID.
  * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
@@ -121,17 +130,18 @@ void __init omap_check_revision(void)
        omap_id = omap_readl(OMAP32_ID_0);
 
 #ifdef DEBUG
-       printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
-       printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
+       printk(KERN_DEBUG "OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
+       printk(KERN_DEBUG "OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
                omap_readl(OMAP_DIE_ID_1),
               (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
-       printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
-       printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
+       printk(KERN_DEBUG "OMAP_PRODUCTION_ID_0: 0x%08x\n",
+               omap_readl(OMAP_PRODUCTION_ID_0));
+       printk(KERN_DEBUG "OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
                omap_readl(OMAP_PRODUCTION_ID_1),
                omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
-       printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
-       printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
-       printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
+       printk(KERN_DEBUG "OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
+       printk(KERN_DEBUG "OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
+       printk(KERN_DEBUG "JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
 #endif
 
        system_serial_high = omap_readl(OMAP_DIE_ID_0);
@@ -140,7 +150,7 @@ void __init omap_check_revision(void)
        /* First check only the major version in a safe way */
        for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
                if (jtag_id == (omap_ids[i].jtag_id)) {
-                       system_rev = omap_ids[i].type;
+                       omap_revision = omap_ids[i].type;
                        break;
                }
        }
@@ -148,7 +158,7 @@ void __init omap_check_revision(void)
        /* Check if we can find the die revision */
        for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
                if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
-                       system_rev = omap_ids[i].type;
+                       omap_revision = omap_ids[i].type;
                        break;
                }
        }
@@ -158,38 +168,35 @@ void __init omap_check_revision(void)
                if (jtag_id == omap_ids[i].jtag_id
                    && die_rev == omap_ids[i].die_rev
                    && omap_id == omap_ids[i].omap_id) {
-                       system_rev = omap_ids[i].type;
+                       omap_revision = omap_ids[i].type;
                        break;
                }
        }
 
        /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
-       cpu_type = system_rev >> 24;
+       cpu_type = omap_revision >> 24;
 
        switch (cpu_type) {
        case 0x07:
-               system_rev |= 0x07;
+               omap_revision |= 0x07;
                break;
        case 0x03:
        case 0x15:
-               system_rev |= 0x15;
+               omap_revision |= 0x15;
                break;
        case 0x16:
        case 0x17:
-               system_rev |= 0x16;
-               break;
-       case 0x24:
-               system_rev |= 0x24;
+               omap_revision |= 0x16;
                break;
        default:
-               printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
+               printk(KERN_INFO "Unknown OMAP cpu type: 0x%02x\n", cpu_type);
        }
 
-       printk("OMAP%04x", system_rev >> 16);
-       if ((system_rev >> 8) & 0xff)
-               printk("%x", (system_rev >> 8) & 0xff);
-       printk(" revision %i handled as %02xxx id: %08x%08x\n",
-              die_rev, system_rev & 0xff, system_serial_low,
+       printk(KERN_INFO "OMAP%04x", omap_revision >> 16);
+       if ((omap_revision >> 8) & 0xff)
+               printk(KERN_INFO "%x", (omap_revision >> 8) & 0xff);
+       printk(KERN_INFO " revision %i handled as %02xxx id: %08x%08x\n",
+              die_rev, omap_revision & 0xff, system_serial_low,
               system_serial_high);
 }
 
index 71fe2cc7f7cf536e28725214c979339369086c9c..17c9d0e04216b6f1891dc2f0b063cbd0b99857d9 100644 (file)
@@ -65,8 +65,8 @@ void h2p2_dbg_leds_event(led_event_t evt)
                /* all leds off during suspend or shutdown */
 
                if (! machine_is_omap_perseus2()) {
-                       omap_set_gpio_dataout(GPIO_TIMER, 0);
-                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+                       gpio_set_value(GPIO_TIMER, 0);
+                       gpio_set_value(GPIO_IDLE, 0);
                }
 
                __raw_writew(~0, &fpga->leds);
@@ -94,7 +94,7 @@ void h2p2_dbg_leds_event(led_event_t evt)
                if (machine_is_omap_perseus2())
                        hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
                else {
-                       omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON);
+                       gpio_set_value(GPIO_TIMER, led_state & LED_TIMER_ON);
                        goto done;
                }
 
@@ -106,7 +106,7 @@ void h2p2_dbg_leds_event(led_event_t evt)
                if (machine_is_omap_perseus2())
                        hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
                else {
-                       omap_set_gpio_dataout(GPIO_IDLE, 1);
+                       gpio_set_value(GPIO_IDLE, 1);
                        goto done;
                }
 
@@ -116,7 +116,7 @@ void h2p2_dbg_leds_event(led_event_t evt)
                if (machine_is_omap_perseus2())
                        hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
                else {
-                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+                       gpio_set_value(GPIO_IDLE, 0);
                        goto done;
                }
 
index 98e789622dfd753c69522f3cd1e4d25204838d2b..499d7ad8697d175847a21fbf133a6cb772526429 100644 (file)
@@ -44,8 +44,8 @@ static void mistral_setled(void)
                green = 1;
        /* else both sides are disabled */
 
-       omap_set_gpio_dataout(GPIO_LED_GREEN, green);
-       omap_set_gpio_dataout(GPIO_LED_RED, red);
+       gpio_set_value(GPIO_LED_GREEN, green);
+       gpio_set_value(GPIO_LED_RED, red);
 }
 
 #endif
index 6cdad93c4a0031732e31fe757f425c7cf91a545b..8cbf2562dcaa79bf53d019d5bd59b3a9b257fe69 100644 (file)
@@ -47,14 +47,14 @@ omap_leds_init(void)
                 * that's a different kind of LED (just one color at a time).
                 */
                omap_cfg_reg(P18_1610_GPIO3);
-               if (omap_request_gpio(3) == 0)
-                       omap_set_gpio_direction(3, 0);
+               if (gpio_request(3, "LED red") == 0)
+                       gpio_direction_output(3, 1);
                else
                        printk(KERN_WARNING "LED: can't get GPIO3/red?\n");
 
                omap_cfg_reg(MPUIO4);
-               if (omap_request_gpio(OMAP_MPUIO(4)) == 0)
-                       omap_set_gpio_direction(OMAP_MPUIO(4), 0);
+               if (gpio_request(OMAP_MPUIO(4), "LED green") == 0)
+                       gpio_direction_output(OMAP_MPUIO(4), 1);
                else
                        printk(KERN_WARNING "LED: can't get MPUIO4/green?\n");
        }
index 770d256c790b337f169d32d0dd6d512b2a3e849c..9774c1f5311e075e34cae1bd12ebb05999688a30 100644 (file)
@@ -226,7 +226,8 @@ void omap_pm_suspend(void)
 {
        unsigned long arg0 = 0, arg1 = 0;
 
-       printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
+       printk(KERN_INFO "PM: OMAP%x is trying to enter deep sleep...\n",
+               omap_rev());
 
        omap_serial_wake_trigger(1);
 
@@ -421,7 +422,8 @@ void omap_pm_suspend(void)
 
        omap_serial_wake_trigger(0);
 
-       printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
+       printk(KERN_INFO "PM: OMAP%x is re-starting from deep sleep...\n",
+               omap_rev());
 }
 
 #if defined(DEBUG) && defined(CONFIG_PROC_FS)
index 528691d5cb51ed76899041c6285774ae2d608bd6..0002084e0655341f508a857b05f2746306685091 100644 (file)
@@ -244,22 +244,22 @@ static void __init omap_serial_set_port_wakeup(int gpio_nr)
 {
        int ret;
 
-       ret = omap_request_gpio(gpio_nr);
+       ret = gpio_request(gpio_nr, "UART wake");
        if (ret < 0) {
                printk(KERN_ERR "Could not request UART wake GPIO: %i\n",
                       gpio_nr);
                return;
        }
-       omap_set_gpio_direction(gpio_nr, 1);
-       ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt,
+       gpio_direction_input(gpio_nr);
+       ret = request_irq(gpio_to_irq(gpio_nr), &omap_serial_wake_interrupt,
                          IRQF_TRIGGER_RISING, "serial wakeup", NULL);
        if (ret) {
-               omap_free_gpio(gpio_nr);
+               gpio_free(gpio_nr);
                printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
                       gpio_nr);
                return;
        }
-       enable_irq_wake(OMAP_GPIO_IRQ(gpio_nr));
+       enable_irq_wake(gpio_to_irq(gpio_nr));
 }
 
 static int __init omap_serial_wakeup_init(void)
index 4832fcc7d04a14be864b663590aaf6b2b1258abb..3754b79092ab47ea7b924161956b4a9b62a65829 100644 (file)
@@ -55,3 +55,7 @@ config MACH_OMAP_LDP
 config MACH_OVERO
        bool "Gumstix Overo board"
        depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP3_PANDORA
+       bool "OMAP3 Pandora"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
\ No newline at end of file
index c69392372c99890f9c50f96e5c7a556b5bef98a6..bbd12bc10fdc1dc39d642227059999d74de5aec8 100644 (file)
@@ -27,9 +27,15 @@ obj-$(CONFIG_ARCH_OMAP3)             += clock34xx.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_2430SDP)                += board-2430sdp.o \
+                                          mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP_APOLLON)                += board-apollon.o
-obj-$(CONFIG_MACH_OMAP3_BEAGLE)                += board-omap3beagle.o
-obj-$(CONFIG_MACH_OMAP_LDP)            += board-ldp.o
-obj-$(CONFIG_MACH_OVERO)               += board-overo.o
+obj-$(CONFIG_MACH_OMAP3_BEAGLE)                += board-omap3beagle.o \
+                                          mmc-twl4030.o
+obj-$(CONFIG_MACH_OMAP_LDP)            += board-ldp.o \
+                                          mmc-twl4030.o
+obj-$(CONFIG_MACH_OVERO)               += board-overo.o \
+                                          mmc-twl4030.o
+obj-$(CONFIG_MACH_OMAP3_PANDORA)       += board-omap3pandora.o \
+                                          mmc-twl4030.o
 
index 24688efaa445f08939fc4fbafa4b2ab0f0aee51c..83fa37211d77c1a1b04b1c68f0f913d5ea47d97c 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
+#include <linux/i2c/twl4030.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
@@ -35,6 +36,7 @@
 #include <mach/common.h>
 #include <mach/gpmc.h>
 
+#include "mmc-twl4030.h"
 
 #define        SDP2430_FLASH_CS        0
 #define        SDP2430_SMC91X_CS       5
@@ -168,13 +170,13 @@ static inline void __init sdp2430_init_smc91x(void)
        sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f;
        udelay(100);
 
-       if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) {
+       if (gpio_request(OMAP24XX_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
                        OMAP24XX_ETHR_GPIO_IRQ);
                gpmc_cs_free(eth_cs);
                goto out;
        }
-       omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1);
+       gpio_direction_input(OMAP24XX_ETHR_GPIO_IRQ);
 
 out:
        clk_disable(gpmc_fck);
@@ -197,12 +199,58 @@ static struct omap_board_config_kernel sdp2430_config[] = {
        {OMAP_TAG_UART, &sdp2430_uart_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_platform_data sdp2430_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .gpio           = &sdp2430_gpio_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 struct twl4030_hsmmc_info mmc[] __initdata = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+               .ext_clock      = 1,
+       },
+       {}      /* Terminator */
+};
+
 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();
+       twl4030_mmc_init(mmc);
 }
 
 static void __init omap_2430sdp_map_io(void)
index 989ad152d7f87105c6b02a1ea4bf0c7fdbc3cd00..bf1e5d32c2a3415d4efcbf972dd0fb45b5917195 100644 (file)
@@ -236,13 +236,13 @@ static inline void __init apollon_init_smc91x(void)
        udelay(100);
 
        omap_cfg_reg(W4__24XX_GPIO74);
-       if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) {
+       if (gpio_request(APOLLON_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
                        APOLLON_ETHR_GPIO_IRQ);
                gpmc_cs_free(APOLLON_ETH_CS);
                goto out;
        }
-       omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
+       gpio_direction_input(APOLLON_ETHR_GPIO_IRQ);
 
 out:
        clk_disable(gpmc_fck);
@@ -261,16 +261,6 @@ static struct omap_uart_config apollon_uart_config __initdata = {
        .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2),
 };
 
-static struct omap_mmc_config apollon_mmc_config __initdata = {
-       .mmc [0] = {
-               .enabled        = 1,
-               .wire4          = 1,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
-       },
-};
-
 static struct omap_usb_config apollon_usb_config __initdata = {
        .register_dev   = 1,
        .hmc_mode       = 0x14, /* 0:dev 1:host1 2:disable */
@@ -284,7 +274,6 @@ static struct omap_lcd_config apollon_lcd_config __initdata = {
 
 static struct omap_board_config_kernel apollon_config[] = {
        { OMAP_TAG_UART,        &apollon_uart_config },
-       { OMAP_TAG_MMC,         &apollon_mmc_config },
        { OMAP_TAG_USB,         &apollon_usb_config },
        { OMAP_TAG_LCD,         &apollon_lcd_config },
 };
@@ -327,15 +316,15 @@ 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);
+       gpio_direction_input(SW_ENTER_GPIO16);
        /* Up SW - AA12 */
        omap_cfg_reg(AA12_242X_GPIO17);
        omap_request_gpio(SW_UP_GPIO17);
-       omap_set_gpio_direction(SW_UP_GPIO17, 1);
+       gpio_direction_input(SW_UP_GPIO17);
        /* Down SW - AA8 */
        omap_cfg_reg(AA8_242X_GPIO58);
        omap_request_gpio(SW_DOWN_GPIO58);
-       omap_set_gpio_direction(SW_DOWN_GPIO58, 1);
+       gpio_direction_input(SW_DOWN_GPIO58);
 
        set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQ_TYPE_EDGE_RISING);
        if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt,
@@ -359,9 +348,8 @@ static void __init apollon_usb_init(void)
        /* USB device */
        /* DEVICE_SUSPEND */
        omap_cfg_reg(P21_242X_GPIO12);
-       omap_request_gpio(12);
-       omap_set_gpio_direction(12, 0);         /* OUT */
-       omap_set_gpio_dataout(12, 0);
+       gpio_request(12, "USB suspend");
+       gpio_direction_output(12, 0);
 }
 
 static void __init omap_apollon_init(void)
index 9ba097868e72b78657a3608ef79fef647276b166..3b34c20d1df41ef5920cdc4e63a9c03cabbd6475 100644 (file)
@@ -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[] = {
        { OMAP_TAG_UART,        &generic_uart_config },
-       { OMAP_TAG_MMC,         &generic_mmc_config },
 };
 
 static void __init omap_generic_init(void)
index 2fef2c84508390daa193ef4e9c189872c44d91aa..5e9b14675b1e7bc81ff3d9c607d5d004b4bb51e0 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
+#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -372,31 +373,33 @@ static struct omap_uart_config h4_uart_config __initdata = {
        .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,
-       },
-};
-
 static struct omap_lcd_config h4_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
 static struct omap_board_config_kernel h4_config[] = {
        { OMAP_TAG_UART,        &h4_uart_config },
-       { OMAP_TAG_MMC,         &h4_mmc_config },
        { OMAP_TAG_LCD,         &h4_lcd_config },
 };
 
+static struct at24_platform_data m24c01 = {
+       .byte_len       = SZ_1K / 8,
+       .page_size      = 16,
+};
+
 static struct i2c_board_info __initdata h4_i2c_board_info[] = {
        {
                I2C_BOARD_INFO("isp1301_omap", 0x2d),
                .irq            = OMAP_GPIO_IRQ(125),
        },
+       {       /* EEPROM on mainboard */
+               I2C_BOARD_INFO("24c01", 0x52),
+               .platform_data  = &m24c01,
+       },
+       {       /* EEPROM on cpu card */
+               I2C_BOARD_INFO("24c01", 0x57),
+               .platform_data  = &m24c01,
+       },
 };
 
 static void __init omap_h4_init(void)
index 1ea59986aa7acfde5258960530f7e0435fe80568..aa6972781e4a946c9b2a0c1c4ff969635b683944 100644 (file)
@@ -21,6 +21,7 @@
 #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/delay.h>
 #include <mach/control.h>
 
+#include "mmc-twl4030.h"
+
+#define SDP3430_SMC91X_CS      3
+
+static struct resource ldp_smc911x_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 ldp_smc911x_device = {
+       .name           = "smc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ldp_smc911x_resources),
+       .resource       = ldp_smc911x_resources,
+};
+
+static struct platform_device *ldp_devices[] __initdata = {
+       &ldp_smc911x_device,
+};
+
+static inline void __init ldp_init_smc911x(void)
+{
+       int eth_cs;
+       unsigned long cs_mem_base;
+       int eth_gpio = 0;
+
+       eth_cs = LDP_SMC911X_CS;
+
+       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem for smc911x\n");
+               return;
+       }
+
+       ldp_smc911x_resources[0].start = cs_mem_base + 0x0;
+       ldp_smc911x_resources[0].end   = cs_mem_base + 0xf;
+       udelay(100);
+
+       eth_gpio = LDP_SMC911X_GPIO;
+
+       ldp_smc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+
+       if (omap_request_gpio(eth_gpio) < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+                               eth_gpio);
+               return;
+       }
+       gpio_direction_input(eth_gpio);
+}
+
 static void __init omap_ldp_init_irq(void)
 {
        omap2_init_common_hw();
        omap_init_irq();
        omap_gpio_init();
+       ldp_init_smc911x();
 }
 
 static struct omap_uart_config ldp_uart_config __initdata = {
@@ -53,20 +112,56 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
        { OMAP_TAG_UART,        &ldp_uart_config },
 };
 
+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_platform_data ldp_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .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, NULL, 0);
+       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 struct twl4030_hsmmc_info mmc[] __initdata = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {}      /* Terminator */
+};
+
 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);
        omap_serial_init();
+       twl4030_mmc_init(mmc);
 }
 
 static void __init omap_ldp_map_io(void)
index baa79674e9d551ebde498af3a29595ad2a0b5e8c..9e5ada01b5fab3e4c93d9a560b6c4ae561e141e3 100644 (file)
@@ -38,7 +38,9 @@
 #include <mach/common.h>
 #include <mach/gpmc.h>
 #include <mach/nand.h>
+#include <mach/mux.h>
 
+#include "mmc-twl4030.h"
 
 #define GPMC_CS0_BASE  0x60
 #define GPMC_CS_SIZE   0x30
@@ -103,6 +105,78 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = {
        .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct twl4030_hsmmc_info mmc[] = {
+       {
+               .mmc            = 1,
+               .wires          = 8,
+               .gpio_wp        = 29,
+       },
+       {}      /* Terminator */
+};
+
+static struct gpio_led gpio_leds[];
+
+static int beagle_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* gpio + 0 is "mmc0_cd" (input/IRQ) */
+
+       /* REVISIT: need ehci-omap hooks for external VBUS
+        * power switch and overcurrent detect
+        */
+
+       gpio_request(gpio + 1, "EHCI_nOC");
+       gpio_direction_input(gpio + 1);
+
+       /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
+       gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
+       gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
+
+       /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+       gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
+       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,
+       .use_leds       = true,
+       .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 */
+       .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();
@@ -130,6 +204,11 @@ static struct gpio_led gpio_leds[] = {
                .default_trigger        = "mmc0",
                .gpio                   = 149,
        },
+       {
+               .name                   = "beagleboard::pmu_stat",
+               .gpio                   = -EINVAL,      /* gets replaced */
+               .active_low             = true,
+       },
 };
 
 static struct gpio_led_platform_data gpio_led_info = {
@@ -218,11 +297,22 @@ static void __init omap3beagle_flash_init(void)
 
 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);
+       mmc[0].gpio_cd = gpio + 0;
+       twl4030_mmc_init(mmc);
+
+       omap_cfg_reg(J25_34XX_GPIO170);
+       gpio_request(170, "DVI_nPD");
+       /* REVISIT leave DVI powered down until it's needed ... */
+       gpio_direction_output(170, true);
+
        omap3beagle_flash_init();
 }
 
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
new file mode 100644 (file)
index 0000000..b319610
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * board-omap3pandora.c (Pandora Handheld Console)
+ *
+ * This program is free software; you can 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/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpio.h>
+#include <mach/hardware.h>
+#include <mach/mcspi.h>
+
+#include "mmc-twl4030.h"
+
+#define OMAP3_PANDORA_TS_GPIO          94
+
+static struct twl4030_hsmmc_info omap3pandora_mmc[] = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = 126,
+               .ext_clock      = 0,
+       },
+       {
+               .mmc            = 2,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = 127,
+               .ext_clock      = 1,
+       },
+       {}      /* Terminator */
+};
+
+static struct omap_uart_config omap3pandora_uart_config __initdata = {
+       .enabled_uarts  = (1 << 2), /* UART3 */
+};
+
+static int omap3pandora_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */
+       omap3pandora_mmc[0].gpio_cd = gpio + 0;
+       omap3pandora_mmc[1].gpio_cd = gpio + 1;
+       twl4030_mmc_init(omap3pandora_mmc);
+
+       return 0;
+}
+
+static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .setup          = omap3pandora_twl_gpio_setup,
+};
+
+static struct twl4030_usb_data omap3pandora_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_platform_data omap3pandora_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+       .gpio           = &omap3pandora_gpio_data,
+       .usb            = &omap3pandora_usb_data,
+};
+
+static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("tps65950", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &omap3pandora_twldata,
+       },
+};
+
+static int __init omap3pandora_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, omap3pandora_i2c_boardinfo,
+                       ARRAY_SIZE(omap3pandora_i2c_boardinfo));
+       /* i2c2 pins are not connected */
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static void __init omap3pandora_init_irq(void)
+{
+       omap2_init_common_hw();
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static void __init omap3pandora_ads7846_init(void)
+{
+       int gpio = OMAP3_PANDORA_TS_GPIO;
+       int ret;
+
+       ret = gpio_request(gpio, "ads7846_pen_down");
+       if (ret < 0) {
+               printk(KERN_ERR "Failed to request GPIO %d for "
+                               "ads7846 pen down IRQ\n", gpio);
+               return;
+       }
+
+       gpio_direction_input(gpio);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !gpio_get_value(OMAP3_PANDORA_TS_GPIO);
+}
+
+static 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,
+};
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,    /* 0: slave, 1: master */
+};
+
+static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
+       {
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &ads7846_mcspi_config,
+               .irq                    = OMAP_GPIO_IRQ(OMAP3_PANDORA_TS_GPIO),
+               .platform_data          = &ads7846_config,
+       }
+};
+
+static struct platform_device omap3pandora_lcd_device = {
+       .name           = "pandora_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap3pandora_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel omap3pandora_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap3pandora_uart_config },
+       { OMAP_TAG_LCD,         &omap3pandora_lcd_config },
+};
+
+static struct platform_device *omap3pandora_devices[] __initdata = {
+       &omap3pandora_lcd_device,
+};
+
+static void __init omap3pandora_init(void)
+{
+       omap3pandora_i2c_init();
+       platform_add_devices(omap3pandora_devices,
+                       ARRAY_SIZE(omap3pandora_devices));
+       omap_board_config = omap3pandora_config;
+       omap_board_config_size = ARRAY_SIZE(omap3pandora_config);
+       omap_serial_init();
+       spi_register_board_info(omap3pandora_spi_board_info,
+                       ARRAY_SIZE(omap3pandora_spi_board_info));
+       omap3pandora_ads7846_init();
+}
+
+static void __init omap3pandora_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap3pandora_map_io,
+       .init_irq       = omap3pandora_init_irq,
+       .init_machine   = omap3pandora_init,
+       .timer          = &omap_timer,
+MACHINE_END
index e09aa59a399c19979065f9f2c66a8a30e07698a3..82b3dc557c96736764f6fdbb235cf1f930a0a2a3 100644 (file)
@@ -26,6 +26,7 @@
 #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>
@@ -44,6 +45,8 @@
 #include <mach/hardware.h>
 #include <mach/nand.h>
 
+#include "mmc-twl4030.h"
+
 #define NAND_BLOCK_SIZE SZ_128K
 #define GPMC_CS0_BASE  0x60
 #define GPMC_CS_SIZE   0x30
@@ -139,8 +142,31 @@ 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_platform_data overo_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+       .gpio           = &overo_gpio_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;
@@ -171,6 +197,22 @@ static struct platform_device *overo_devices[] __initdata = {
        &overo_lcd_device,
 };
 
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+       {
+               .mmc            = 1,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {
+               .mmc            = 2,
+               .wires          = 4,
+               .gpio_cd        = -EINVAL,
+               .gpio_wp        = -EINVAL,
+       },
+       {}      /* Terminator */
+};
+
 static void __init overo_init(void)
 {
        overo_i2c_init();
@@ -178,6 +220,7 @@ static void __init overo_init(void)
        omap_board_config = overo_config;
        omap_board_config_size = ARRAY_SIZE(overo_config);
        omap_serial_init();
+       twl4030_mmc_init(mmc);
        overo_flash_init();
 
        if ((gpio_request(OVERO_GPIO_W2W_NRESET,
index 242a19d86ccd025f1a36d6baede741e0a7b5d03c..ff6cd14d254db7a9a098dd87b7000f1cbac1e09b 100644 (file)
@@ -2522,7 +2522,6 @@ static struct clk usbhs_ick = {
 
 static struct clk mmchs1_ick = {
        .name           = "mmchs_ick",
-       .id             = 1,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .clkdm_name     = "core_l4_clkdm",
@@ -2533,7 +2532,6 @@ static struct clk mmchs1_ick = {
 
 static struct clk mmchs1_fck = {
        .name           = "mmchs_fck",
-       .id             = 1,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .clkdm_name     = "core_l3_clkdm",
@@ -2544,7 +2542,7 @@ static struct clk mmchs1_fck = {
 
 static struct clk mmchs2_ick = {
        .name           = "mmchs_ick",
-       .id             = 2,
+       .id             = 1,
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .clkdm_name     = "core_l4_clkdm",
@@ -2555,7 +2553,7 @@ static struct clk mmchs2_ick = {
 
 static struct clk mmchs2_fck = {
        .name           = "mmchs_fck",
-       .id             = 2,
+       .id             = 1,
        .parent         = &func_96m_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
@@ -2595,7 +2593,6 @@ static struct clk mdm_intc_ick = {
 
 static struct clk mmchsdb1_fck = {
        .name           = "mmchsdb_fck",
-       .id             = 1,
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .clkdm_name     = "core_l4_clkdm",
@@ -2606,7 +2603,7 @@ static struct clk mmchsdb1_fck = {
 
 static struct clk mmchsdb2_fck = {
        .name           = "mmchsdb_fck",
-       .id             = 2,
+       .id             = 1,
        .parent         = &func_32k_ck,
        .flags          = CLOCK_IN_OMAP243X,
        .clkdm_name     = "core_l4_clkdm",
index 084e11082f80c872ada5955a4e4a687a9fefdc0a..31bb7010bd48224c8142e8c733debb4ade2b1172 100644 (file)
@@ -475,7 +475,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 (omap_rev() == OMAP3430_REV_ES1_0) {
                        /* No 3430ES1-only rates exist, so no RATE_IN_3430ES1 */
                        cpu_clkflg |= CLOCK_IN_OMAP3430ES1;
                } else {
index c38a8a09692ff3748d24208eca1ee492fe967020..a826094d89b57caade4c88c0e992638243396e7c 100644 (file)
@@ -1374,7 +1374,7 @@ static struct clk core_96m_fck = {
 
 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),
        .enable_bit     = OMAP3430ES2_EN_MMC3_SHIFT,
@@ -1385,7 +1385,7 @@ static struct clk mmchs3_fck = {
 
 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),
        .enable_bit     = OMAP3430_EN_MMC2_SHIFT,
@@ -1406,7 +1406,6 @@ static struct clk mspro_fck = {
 
 static struct clk mmchs1_fck = {
        .name           = "mmchs_fck",
-       .id             = 1,
        .parent         = &core_96m_fck,
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
        .enable_bit     = OMAP3430_EN_MMC1_SHIFT,
@@ -1722,7 +1721,7 @@ static struct clk usbtll_ick = {
 
 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),
        .enable_bit     = OMAP3430ES2_EN_MMC3_SHIFT,
@@ -1774,7 +1773,7 @@ static struct clk des2_ick = {
 
 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),
        .enable_bit     = OMAP3430_EN_MMC2_SHIFT,
@@ -1785,7 +1784,6 @@ static struct clk mmchs2_ick = {
 
 static struct clk mmchs1_ick = {
        .name           = "mmchs_ick",
-       .id             = 1,
        .parent         = &core_l4_ick,
        .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
        .enable_bit     = OMAP3430_EN_MMC1_SHIFT,
@@ -2280,8 +2278,8 @@ static struct clk wkup_32k_fck = {
        .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),
        .enable_bit     = OMAP3430_EN_GPIO1_SHIFT,
@@ -2527,8 +2525,8 @@ static struct clk per_32k_alwon_fck = {
        .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),
        .enable_bit     = OMAP3430_EN_GPIO6_SHIFT,
@@ -2537,8 +2535,8 @@ static struct clk gpio6_fck = {
        .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),
        .enable_bit     = OMAP3430_EN_GPIO5_SHIFT,
@@ -2547,8 +2545,8 @@ static struct clk gpio5_fck = {
        .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),
        .enable_bit     = OMAP3430_EN_GPIO4_SHIFT,
@@ -2557,8 +2555,8 @@ static struct clk gpio4_fck = {
        .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),
        .enable_bit     = OMAP3430_EN_GPIO3_SHIFT,
@@ -2567,8 +2565,8 @@ static struct clk gpio3_fck = {
        .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),
        .enable_bit     = OMAP3430_EN_GPIO2_SHIFT,
@@ -3170,7 +3168,7 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &usim_fck,
        &gpt1_fck,
        &wkup_32k_fck,
-       &gpio1_fck,
+       &gpio1_dbck,
        &wdt2_fck,
        &wkup_l4_ick,
        &usim_ick,
@@ -3192,11 +3190,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,
index 90af2ac469aaccc74401ceea7fe5487e63a7dd6b..9d7216ff6c9f58d4d5ffbb4a85a3bfc4f764c74e 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 
 #include <mach/hardware.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_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
 #define OMAP2_MBOX_BASE                IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
@@ -295,6 +298,171 @@ static void omap_init_sha1_md5(void)
 static inline void omap_init_sha1_md5(void) { }
 #endif
 
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP3
+
+#define MMCHS_SYSCONFIG                        0x0010
+#define MMCHS_SYSCONFIG_SWRESET                (1 << 1)
+#define MMCHS_SYSSTATUS                        0x0014
+#define MMCHS_SYSSTATUS_RESETDONE      (1 << 0)
+
+static struct platform_device dummy_pdev = {
+       .dev = {
+               .bus = &platform_bus_type,
+       },
+};
+
+/**
+ * omap_hsmmc_reset() - Full reset of each HS-MMC controller
+ *
+ * Ensure that each MMC controller is fully reset.  Controllers
+ * left in an unknown state (by bootloader) may prevent retention
+ * or OFF-mode.  This is especially important in cases where the
+ * MMC driver is not enabled, _or_ built as a module.
+ *
+ * In order for reset to work, interface, functional and debounce
+ * clocks must be enabled.  The debounce clock comes from func_32k_clk
+ * and is not under SW control, so we only enable i- and f-clocks.
+ **/
+static void __init omap_hsmmc_reset(void)
+{
+       u32 i, nr_controllers = cpu_is_omap34xx() ? OMAP34XX_NR_MMC :
+               OMAP24XX_NR_MMC;
+
+       for (i = 0; i < nr_controllers; i++) {
+               u32 v, base = 0;
+               struct clk *iclk, *fclk;
+               struct device *dev = &dummy_pdev.dev;
+
+               switch (i) {
+               case 0:
+                       base = OMAP2_MMC1_BASE;
+                       break;
+               case 1:
+                       base = OMAP2_MMC2_BASE;
+                       break;
+               case 2:
+                       base = OMAP3_MMC3_BASE;
+                       break;
+               }
+
+               dummy_pdev.id = i;
+               iclk = clk_get(dev, "mmchs_ick");
+               if (iclk && clk_enable(iclk))
+                       iclk = NULL;
+
+               fclk = clk_get(dev, "mmchs_fck");
+               if (fclk && clk_enable(fclk))
+                       fclk = NULL;
+
+               if (!iclk || !fclk) {
+                       printk(KERN_WARNING
+                              "%s: Unable to enable clocks for MMC%d, "
+                              "cannot reset.\n",  __func__, i);
+                       break;
+               }
+
+               omap_writel(MMCHS_SYSCONFIG_SWRESET, base + MMCHS_SYSCONFIG);
+               v = omap_readl(base + MMCHS_SYSSTATUS);
+               while (!(omap_readl(base + MMCHS_SYSSTATUS) &
+                        MMCHS_SYSSTATUS_RESETDONE))
+                       cpu_relax();
+
+               if (fclk) {
+                       clk_disable(fclk);
+                       clk_put(fclk);
+               }
+               if (iclk) {
+                       clk_disable(iclk);
+                       clk_put(iclk);
+               }
+       }
+}
+#else
+static inline void omap_hsmmc_reset(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].wires == 4) {
+                       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
@@ -334,6 +502,7 @@ 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_hsmmc_reset();
        omap_init_mbox();
        omap_init_mcspi();
        omap_hdq_init();
index bf45ff39a7b5fbe9d651fbc81c6ec6f2caeb7e32..b0f8e7d627987fd78e991c0fafdae4860f1d15a3 100644 (file)
 #include <mach/control.h>
 #include <mach/cpu.h>
 
-static u32 class;
-static void __iomem *tap_base;
-static u16 tap_prod_id;
-
-#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
-
-/* 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 */
-};
+static struct omap_chip_id omap_chip;
+static unsigned int omap_revision;
 
-/* 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;
+unsigned int omap_rev(void)
+{
+       return omap_revision;
+}
+EXPORT_SYMBOL(omap_rev);
 
 /**
  * omap_chip_is - test whether currently running OMAP matches a chip type
@@ -70,135 +45,41 @@ int omap_chip_is(struct omap_chip_id oci)
 }
 EXPORT_SYMBOL(omap_chip_is);
 
-static u32 __init read_tap_reg(int reg)
-{
-       unsigned int regval = 0;
-       u32 cpuid;
-
-       /* Reading the IDCODE register on 3430 ES1 results in a
-        * data abort as the register is not exposed on the OCP
-        * Hence reading the Cortex Rev
-        */
-       cpuid = read_cpuid(CPUID_ID);
-
-       /* If the processor type is Cortex-A8 and the revision is 0x0
-        * it means its Cortex r0p0 which is 3430 ES1
-        */
-       if ((((cpuid >> 4) & 0xFFF) == 0xC08) && ((cpuid & 0xF) == 0x0)) {
-
-               if (reg == tap_prod_id) {
-                       regval = 0x000F00F0;
-                       goto out;
-               }
-
-               switch (reg) {
-               case OMAP_TAP_IDCODE  : regval = 0x0B7AE02F; break;
-               /* Making DevType as 0xF in ES1 to differ from ES2 */
-               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);
-
-out:
-       return regval;
-
-}
+/*----------------------------------------------------------------------------*/
 
-/*
- * _set_system_rev - set the system_rev global based on current OMAP chip type
- *
- * Set the system_rev global.  This is primarily used by the cpu_is_omapxxxx()
- * macros.
- */
-static void __init _set_system_rev(u32 type, u8 rev)
-{
-       u32 i, ctrl_status;
-
-       /*
-        * system_rev encoding is as follows
-        * system_rev & 0xff000000 -> Omap Class (24xx/34xx)
-        * system_rev & 0xfff00000 -> Omap Sub Class (242x/343x)
-        * system_rev & 0xffff0000 -> Omap type (2420/2422/2423/2430/3430)
-        * system_rev & 0x0000f000 -> Silicon revision (ES1, ES2 )
-        * system_rev & 0x00000700 -> Device Type ( EMU/HS/GP/BAD )
-        * system_rev & 0x000000c0 -> IDCODE revision[6:7]
-        * system_rev & 0x0000003f -> sys_boot[0:5]
-        */
-       /* Embedding the ES revision info in type field */
-       system_rev = type;
-       /* Also add IDCODE revision info only two lower bits */
-       system_rev |= ((rev & 0x3) << 6);
-
-       /* Add in the device type and sys_boot fields (see above) */
-       if (cpu_is_omap24xx()) {
-               i = OMAP24XX_CONTROL_STATUS;
-       } else if (cpu_is_omap343x()) {
-               i = OMAP343X_CONTROL_STATUS;
-       } else {
-               printk(KERN_ERR "id: unknown CPU type\n");
-               BUG();
-       }
-       ctrl_status = omap_ctrl_readl(i);
-       system_rev |= (ctrl_status & (OMAP2_SYSBOOT_5_MASK |
-                                     OMAP2_SYSBOOT_4_MASK |
-                                     OMAP2_SYSBOOT_3_MASK |
-                                     OMAP2_SYSBOOT_2_MASK |
-                                     OMAP2_SYSBOOT_1_MASK |
-                                     OMAP2_SYSBOOT_0_MASK));
-       system_rev |= (ctrl_status & OMAP2_DEVICETYPE_MASK);
-}
-
-
-/*
- * _set_omap_chip - set the omap_chip global based on OMAP chip type
- *
- * Build the omap_chip bits.  This variable is used by powerdomain and
- * clockdomain code to indicate whether structures are applicable for
- * the current OMAP chip type by ANDing it against a 'platform' bitfield
- * in the structure.
- */
-static void __init _set_omap_chip(void)
-{
-       if (cpu_is_omap343x()) {
-
-               omap_chip.oc = CHIP_IS_OMAP3430;
-               if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0))
-                       omap_chip.oc |= CHIP_IS_OMAP3430ES1;
-               else if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0))
-                       omap_chip.oc |= CHIP_IS_OMAP3430ES2;
-
-       } else if (cpu_is_omap243x()) {
-
-               /* Currently only supports 2430ES2.1 and 2430-all */
-               omap_chip.oc |= CHIP_IS_OMAP2430;
-
-       } else if (cpu_is_omap242x()) {
-
-               /* Currently only supports 2420ES2.1.1 and 2420-all */
-               omap_chip.oc |= CHIP_IS_OMAP2420;
+#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 omap_revision */
+};
 
-       }
+/* 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(tap_prod_id);
@@ -220,18 +101,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)
@@ -255,23 +124,115 @@ void __init omap2_check_revision(void)
                j = i;
        }
 
-       _set_system_rev(omap_ids[j].type, rev);
+       pr_info("OMAP%04x", omap_rev() >> 16);
+       if ((omap_rev() >> 8) & 0x0f)
+               pr_info("ES%x", (omap_rev() >> 12) & 0xf);
+       pr_info("\n");
+}
 
-       _set_omap_chip();
+void __init omap34xx_check_revision(void)
+{
+       u32 cpuid, idcode;
+       u16 hawkeye;
+       u8 rev;
+       char *rev_name = "ES1.0";
 
-       pr_info("OMAP%04x", system_rev >> 16);
-       if ((system_rev >> 8) & 0x0f)
-               pr_info("ES%x", (system_rev >> 12) & 0xf);
-       pr_info("\n");
+       /*
+        * 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)) {
+               omap_revision = OMAP3430_REV_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:
+                       omap_revision = OMAP3430_REV_ES2_0;
+                       rev_name = "ES2.0";
+                       break;
+               case 2:
+                       omap_revision = OMAP3430_REV_ES2_1;
+                       rev_name = "ES2.1";
+                       break;
+               case 3:
+                       omap_revision = OMAP3430_REV_ES3_0;
+                       rev_name = "ES3.0";
+                       break;
+               default:
+                       /* Use the latest known revision as default */
+                       omap_revision = OMAP3430_REV_ES3_0;
+                       rev_name = "Unknown revision\n";
+               }
+       }
+
+out:
+       pr_info("OMAP%04x %s\n", omap_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 (omap_rev() == OMAP3430_REV_ES1_0)
+                       omap_chip.oc |= CHIP_IS_OMAP3430ES1;
+               else if (omap_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)
 {
-       class = omap2_globals->class;
+       omap_revision = omap2_globals->class;
        tap_base = omap2_globals->tap;
 
-       if (class == 0x3430)
+       if (cpu_is_omap34xx())
                tap_prod_id = 0x0210;
        else
                tap_prod_id = 0x0208;
index c40fc378a251244bce6e6c0ad9f0e177c7326a75..636e2821af7da8a9bd76f33bcbfabac5bb5fb0db 100644 (file)
@@ -23,6 +23,7 @@
 #define INTC_REVISION          0x0000
 #define INTC_SYSCONFIG         0x0010
 #define INTC_SYSSTATUS         0x0014
+#define INTC_SIR               0x0040
 #define INTC_CONTROL           0x0048
 #define INTC_MIR_CLEAR0                0x0088
 #define INTC_MIR_SET0          0x008c
@@ -60,6 +61,30 @@ static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg)
        return __raw_readl(bank->base_reg + reg);
 }
 
+static int previous_irq;
+
+/*
+ * On 34xx we can get occasional spurious interrupts if the ack from
+ * an interrupt handler does not get posted before we unmask. Warn about
+ * the interrupt handlers that need to flush posted writes.
+ */
+static int omap_check_spurious(unsigned int irq)
+{
+       u32 sir, spurious;
+
+       sir = intc_bank_read_reg(&irq_banks[0], INTC_SIR);
+       spurious = sir >> 6;
+
+       if (spurious > 1) {
+               printk(KERN_WARNING "Spurious irq %i: 0x%08x, please flush "
+                                       "posted write for irq %i\n",
+                                       irq, sir, previous_irq);
+               return spurious;
+       }
+
+       return 0;
+}
+
 /* XXX: FIQ and additional INTC support (only MPU at the moment) */
 static void omap_ack_irq(unsigned int irq)
 {
@@ -70,6 +95,20 @@ static void omap_mask_irq(unsigned int irq)
 {
        int offset = irq & (~(IRQ_BITS_PER_REG - 1));
 
+       if (cpu_is_omap34xx()) {
+               int spurious = 0;
+
+               /*
+                * INT_34XX_GPT12_IRQ is also the spurious irq. Maybe because
+                * it is the highest irq number?
+                */
+               if (irq == INT_34XX_GPT12_IRQ)
+                       spurious = omap_check_spurious(irq);
+
+               if (!spurious)
+                       previous_irq = irq;
+       }
+
        irq &= (IRQ_BITS_PER_REG - 1);
 
        intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset);
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c
new file mode 100644 (file)
index 0000000..437f520
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * linux/arch/arm/mach-omap2/mmc-twl4030.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/gpio.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <mach/control.h>
+#include <mach/mmc.h>
+#include <mach/board.h>
+
+#include "mmc-twl4030.h"
+
+#if defined(CONFIG_TWL4030_CORE) && \
+       (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
+
+#define LDO_CLR                        0x00
+#define VSEL_S2_CLR            0x40
+
+#define VMMC1_DEV_GRP          0x27
+#define VMMC1_CLR              0x00
+#define VMMC1_315V             0x03
+#define VMMC1_300V             0x02
+#define VMMC1_285V             0x01
+#define VMMC1_185V             0x00
+#define VMMC1_DEDICATED                0x2A
+
+#define VMMC2_DEV_GRP          0x2B
+#define VMMC2_CLR              0x40
+#define VMMC2_315V             0x0c
+#define VMMC2_300V             0x0b
+#define VMMC2_285V             0x0a
+#define VMMC2_260V             0x08
+#define VMMC2_185V             0x06
+#define VMMC2_DEDICATED                0x2E
+
+#define VMMC_DEV_GRP_P1                0x20
+
+static u16 control_pbias_offset;
+static u16 control_devconf1_offset;
+
+#define HSMMC_NAME_LEN 9
+
+static struct twl_mmc_controller {
+       struct omap_mmc_platform_data   *mmc;
+       u8              twl_vmmc_dev_grp;
+       u8              twl_mmc_dedicated;
+       char            name[HSMMC_NAME_LEN];
+} hsmmc[] = {
+       {
+               .twl_vmmc_dev_grp               = VMMC1_DEV_GRP,
+               .twl_mmc_dedicated              = VMMC1_DEDICATED,
+       },
+       {
+               .twl_vmmc_dev_grp               = VMMC2_DEV_GRP,
+               .twl_mmc_dedicated              = VMMC2_DEDICATED,
+       },
+};
+
+static int twl_mmc_card_detect(int irq)
+{
+       unsigned i;
+
+       for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
+               struct omap_mmc_platform_data *mmc;
+
+               mmc = hsmmc[i].mmc;
+               if (!mmc)
+                       continue;
+               if (irq != mmc->slots[0].card_detect_irq)
+                       continue;
+
+               /* NOTE: assumes card detect signal is active-low */
+               return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
+       }
+       return -ENOSYS;
+}
+
+static int twl_mmc_get_ro(struct device *dev, int slot)
+{
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+       /* NOTE: assumes write protect signal is active-high */
+       return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
+}
+
+/*
+ * MMC Slot Initialization.
+ */
+static int twl_mmc_late_init(struct device *dev)
+{
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+       int ret = 0;
+       int i;
+
+       ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd");
+       if (ret)
+               goto done;
+       ret = gpio_direction_input(mmc->slots[0].switch_pin);
+       if (ret)
+               goto err;
+
+       for (i = 0; i < ARRAY_SIZE(hsmmc); i++) {
+               if (hsmmc[i].name == mmc->slots[0].name) {
+                       hsmmc[i].mmc = mmc;
+                       break;
+               }
+       }
+
+       return 0;
+
+err:
+       gpio_free(mmc->slots[0].switch_pin);
+done:
+       mmc->slots[0].card_detect_irq = 0;
+       mmc->slots[0].card_detect = NULL;
+
+       dev_err(dev, "err %d configuring card detect\n", ret);
+       return ret;
+}
+
+static void twl_mmc_cleanup(struct device *dev)
+{
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+       gpio_free(mmc->slots[0].switch_pin);
+}
+
+#ifdef CONFIG_PM
+
+static int twl_mmc_suspend(struct device *dev, int slot)
+{
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+       disable_irq(mmc->slots[0].card_detect_irq);
+       return 0;
+}
+
+static int twl_mmc_resume(struct device *dev, int slot)
+{
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+       enable_irq(mmc->slots[0].card_detect_irq);
+       return 0;
+}
+
+#else
+#define twl_mmc_suspend        NULL
+#define twl_mmc_resume NULL
+#endif
+
+/*
+ * Sets the MMC voltage in twl4030
+ */
+static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd)
+{
+       int ret;
+       u8 vmmc, dev_grp_val;
+
+       switch (1 << vdd) {
+       case MMC_VDD_35_36:
+       case MMC_VDD_34_35:
+       case MMC_VDD_33_34:
+       case MMC_VDD_32_33:
+       case MMC_VDD_31_32:
+       case MMC_VDD_30_31:
+               if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+                       vmmc = VMMC1_315V;
+               else
+                       vmmc = VMMC2_315V;
+               break;
+       case MMC_VDD_29_30:
+               if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+                       vmmc = VMMC1_315V;
+               else
+                       vmmc = VMMC2_300V;
+               break;
+       case MMC_VDD_27_28:
+       case MMC_VDD_26_27:
+               if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+                       vmmc = VMMC1_285V;
+               else
+                       vmmc = VMMC2_285V;
+               break;
+       case MMC_VDD_25_26:
+       case MMC_VDD_24_25:
+       case MMC_VDD_23_24:
+       case MMC_VDD_22_23:
+       case MMC_VDD_21_22:
+       case MMC_VDD_20_21:
+               if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+                       vmmc = VMMC1_285V;
+               else
+                       vmmc = VMMC2_260V;
+               break;
+       case MMC_VDD_165_195:
+               if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP)
+                       vmmc = VMMC1_185V;
+               else
+                       vmmc = VMMC2_185V;
+               break;
+       default:
+               vmmc = 0;
+               break;
+       }
+
+       if (vmmc)
+               dev_grp_val = VMMC_DEV_GRP_P1;  /* Power up */
+       else
+               dev_grp_val = LDO_CLR;          /* Power down */
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                       dev_grp_val, c->twl_vmmc_dev_grp);
+       if (ret)
+               return ret;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                       vmmc, c->twl_mmc_dedicated);
+
+       return ret;
+}
+
+static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       u32 reg;
+       int ret = 0;
+       struct twl_mmc_controller *c = &hsmmc[0];
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+       if (power_on) {
+               if (cpu_is_omap2430()) {
+                       reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1);
+                       if ((1 << vdd) >= MMC_VDD_30_31)
+                               reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE;
+                       else
+                               reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE;
+                       omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1);
+               }
+
+               if (mmc->slots[0].internal_clock) {
+                       reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+                       reg |= OMAP2_MMCSDIO1ADPCLKISEL;
+                       omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0);
+               }
+
+               reg = omap_ctrl_readl(control_pbias_offset);
+               reg |= OMAP2_PBIASSPEEDCTRL0;
+               reg &= ~OMAP2_PBIASLITEPWRDNZ0;
+               omap_ctrl_writel(reg, control_pbias_offset);
+
+               ret = twl_mmc_set_voltage(c, vdd);
+
+               /* 100ms delay required for PBIAS configuration */
+               msleep(100);
+               reg = omap_ctrl_readl(control_pbias_offset);
+               reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
+               if ((1 << vdd) <= MMC_VDD_165_195)
+                       reg &= ~OMAP2_PBIASLITEVMODE0;
+               else
+                       reg |= OMAP2_PBIASLITEVMODE0;
+               omap_ctrl_writel(reg, control_pbias_offset);
+       } else {
+               reg = omap_ctrl_readl(control_pbias_offset);
+               reg &= ~OMAP2_PBIASLITEPWRDNZ0;
+               omap_ctrl_writel(reg, control_pbias_offset);
+
+               ret = twl_mmc_set_voltage(c, 0);
+
+               /* 100ms delay required for PBIAS configuration */
+               msleep(100);
+               reg = omap_ctrl_readl(control_pbias_offset);
+               reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
+                       OMAP2_PBIASLITEVMODE0);
+               omap_ctrl_writel(reg, control_pbias_offset);
+       }
+
+       return ret;
+}
+
+static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vdd)
+{
+       int ret;
+       struct twl_mmc_controller *c = &hsmmc[1];
+       struct omap_mmc_platform_data *mmc = dev->platform_data;
+
+       if (power_on) {
+               if (mmc->slots[0].internal_clock) {
+                       u32 reg;
+
+                       reg = omap_ctrl_readl(control_devconf1_offset);
+                       reg |= OMAP2_MMCSDIO2ADPCLKISEL;
+                       omap_ctrl_writel(reg, control_devconf1_offset);
+               }
+               ret = twl_mmc_set_voltage(c, vdd);
+       } else {
+               ret = twl_mmc_set_voltage(c, 0);
+       }
+
+       return ret;
+}
+
+static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata;
+
+void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers)
+{
+       struct twl4030_hsmmc_info *c;
+       int nr_hsmmc = ARRAY_SIZE(hsmmc_data);
+
+       if (cpu_is_omap2430()) {
+               control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE;
+               control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1;
+               nr_hsmmc = 2;
+       } else {
+               control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
+               control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
+       }
+
+       for (c = controllers; c->mmc; c++) {
+               struct twl_mmc_controller *twl = hsmmc + c->mmc - 1;
+               struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1];
+
+               if (!c->mmc || c->mmc > nr_hsmmc) {
+                       pr_debug("MMC%d: no such controller\n", c->mmc);
+                       continue;
+               }
+               if (mmc) {
+                       pr_debug("MMC%d: already configured\n", c->mmc);
+                       continue;
+               }
+
+               mmc = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
+               if (!mmc) {
+                       pr_err("Cannot allocate memory for mmc device!\n");
+                       return;
+               }
+
+               sprintf(twl->name, "mmc%islot%i", c->mmc, 1);
+               mmc->slots[0].name = twl->name;
+               mmc->nr_slots = 1;
+               mmc->slots[0].ocr_mask = MMC_VDD_165_195 |
+                                       MMC_VDD_26_27 | MMC_VDD_27_28 |
+                                       MMC_VDD_29_30 |
+                                       MMC_VDD_30_31 | MMC_VDD_31_32;
+               mmc->slots[0].wires = c->wires;
+               mmc->slots[0].internal_clock = !c->ext_clock;
+               mmc->dma_mask = 0xffffffff;
+
+               /* note: twl4030 card detect GPIOs normally switch VMMCx ... */
+               if (gpio_is_valid(c->gpio_cd)) {
+                       mmc->init = twl_mmc_late_init;
+                       mmc->cleanup = twl_mmc_cleanup;
+                       mmc->suspend = twl_mmc_suspend;
+                       mmc->resume = twl_mmc_resume;
+
+                       mmc->slots[0].switch_pin = c->gpio_cd;
+                       mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd);
+                       mmc->slots[0].card_detect = twl_mmc_card_detect;
+               } else
+                       mmc->slots[0].switch_pin = -EINVAL;
+
+               /* write protect normally uses an OMAP gpio */
+               if (gpio_is_valid(c->gpio_wp)) {
+                       gpio_request(c->gpio_wp, "mmc_wp");
+                       gpio_direction_input(c->gpio_wp);
+
+                       mmc->slots[0].gpio_wp = c->gpio_wp;
+                       mmc->slots[0].get_ro = twl_mmc_get_ro;
+               } else
+                       mmc->slots[0].gpio_wp = -EINVAL;
+
+               /* NOTE:  we assume OMAP's MMC1 and MMC2 use
+                * the TWL4030's VMMC1 and VMMC2, respectively;
+                * and that OMAP's MMC3 isn't used.
+                */
+
+               switch (c->mmc) {
+               case 1:
+                       mmc->slots[0].set_power = twl_mmc1_set_power;
+                       break;
+               case 2:
+                       mmc->slots[0].set_power = twl_mmc2_set_power;
+                       break;
+               default:
+                       pr_err("MMC%d configuration not supported!\n", c->mmc);
+                       continue;
+               }
+               hsmmc_data[c->mmc - 1] = mmc;
+       }
+
+       omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
+}
+
+#endif
diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h
new file mode 100644 (file)
index 0000000..e1c8076
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * MMC definitions 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.
+ */
+
+struct twl4030_hsmmc_info {
+       u8      mmc;            /* controller 1/2/3 */
+       u8      wires;          /* 1/4/8 wires */
+       int     gpio_cd;        /* or -EINVAL */
+       int     gpio_wp;        /* or -EINVAL */
+       int     ext_clock:1;    /* use external pin for input clock */
+};
+
+#if    defined(CONFIG_TWL4030_CORE) && \
+       (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
+        defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE))
+
+void twl4030_mmc_init(struct twl4030_hsmmc_info *);
+
+#else
+
+static inline void twl4030_mmc_init(struct twl4030_hsmmc_info *info)
+{
+}
+
+#endif
index b1393673d95d802b97f2a24494cddad16340de0d..dacb41f130c077f5c7d205e02bcde051051e00e3 100644 (file)
@@ -203,6 +203,15 @@ MUX_CFG_24XX("AE9_2430_USB0HS_NXT",        0x13D,  0,      0,      0,      1)
 MUX_CFG_24XX("AC7_2430_USB0HS_DATA7",  0x13E,  0,      0,      0,      1)
 
 /* 2430 McBSP */
+MUX_CFG_24XX("AD6_2430_MCBSP_CLKS",    0x011E, 0,      0,      0,      1)
+
+MUX_CFG_24XX("AB2_2430_MCBSP1_CLKR",   0x011A, 0,      0,      0,      1)
+MUX_CFG_24XX("AD5_2430_MCBSP1_FSR",    0x011B, 0,      0,      0,      1)
+MUX_CFG_24XX("AA1_2430_MCBSP1_DX",     0x011C, 0,      0,      0,      1)
+MUX_CFG_24XX("AF3_2430_MCBSP1_DR",     0x011D, 0,      0,      0,      1)
+MUX_CFG_24XX("AB3_2430_MCBSP1_FSX",    0x011F, 0,      0,      0,      1)
+MUX_CFG_24XX("Y9_2430_MCBSP1_CLKX",    0x0120, 0,      0,      0,      1)
+
 MUX_CFG_24XX("AC10_2430_MCBSP2_FSX",   0x012E, 1,      0,      0,      1)
 MUX_CFG_24XX("AD16_2430_MCBSP2_CLX",   0x012F, 1,      0,      0,      1)
 MUX_CFG_24XX("AE13_2430_MCBSP2_DX",    0x0130, 1,      0,      0,      1)
@@ -211,6 +220,31 @@ MUX_CFG_24XX("AC10_2430_MCBSP2_FSX_OFF",0x012E,    0,      0,      0,      1)
 MUX_CFG_24XX("AD16_2430_MCBSP2_CLX_OFF",0x012F,        0,      0,      0,      1)
 MUX_CFG_24XX("AE13_2430_MCBSP2_DX_OFF",        0x0130, 0,      0,      0,      1)
 MUX_CFG_24XX("AD13_2430_MCBSP2_DR_OFF",        0x0131, 0,      0,      0,      1)
+
+MUX_CFG_24XX("AC9_2430_MCBSP3_CLKX",   0x0103, 0,      0,      0,      1)
+MUX_CFG_24XX("AE4_2430_MCBSP3_FSX",    0x0104, 0,      0,      0,      1)
+MUX_CFG_24XX("AE2_2430_MCBSP3_DR",     0x0105, 0,      0,      0,      1)
+MUX_CFG_24XX("AF4_2430_MCBSP3_DX",     0x0106, 0,      0,      0,      1)
+
+MUX_CFG_24XX("N3_2430_MCBSP4_CLKX",    0x010B, 1,      0,      0,      1)
+MUX_CFG_24XX("AD23_2430_MCBSP4_DR",    0x010C, 1,      0,      0,      1)
+MUX_CFG_24XX("AB25_2430_MCBSP4_DX",    0x010D, 1,      0,      0,      1)
+MUX_CFG_24XX("AC25_2430_MCBSP4_FSX",   0x010E, 1,      0,      0,      1)
+
+MUX_CFG_24XX("AE16_2430_MCBSP5_CLKX",  0x00ED, 1,      0,      0,      1)
+MUX_CFG_24XX("AF12_2430_MCBSP5_FSX",   0x00ED, 1,      0,      0,      1)
+MUX_CFG_24XX("K7_2430_MCBSP5_DX",      0x00EF, 1,      0,      0,      1)
+MUX_CFG_24XX("M1_2430_MCBSP5_DR",      0x00F0, 1,      0,      0,      1)
+
+/* 2430 MCSPI1 */
+MUX_CFG_24XX("Y18_2430_MCSPI1_CLK",    0x010F, 0,      0,      0,      1)
+MUX_CFG_24XX("AD15_2430_MCSPI1_SIMO",  0x0110, 0,      0,      0,      1)
+MUX_CFG_24XX("AE17_2430_MCSPI1_SOMI",  0x0111, 0,      0,      0,      1)
+MUX_CFG_24XX("U1_2430_MCSPI1_CS0",     0x0112, 0,      0,      0,      1)
+
+/* Touchscreen GPIO */
+MUX_CFG_24XX("AF19_2430_GPIO_85",      0x0113, 3,      0,      0,      1)
+
 };
 
 #define OMAP24XX_PINS_SZ       ARRAY_SIZE(omap24xx_pins)
@@ -417,6 +451,14 @@ MUX_CFG_34XX("AD2_3430_USB3FS_PHY_MM3_TXDAT", 0x188,
 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)
@@ -452,7 +494,7 @@ static void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u16 r
 #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;
index 10ef464d6be7f3f2768a1a7d95d6adb68e88ed17..15e509013def69cda9cf2ff4d431e70868d676c0 100644 (file)
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 
 #include <linux/usb/musb.h>
 
 #include <mach/gpmc.h>
-#include <mach/gpio.h>
 #include <mach/mux.h>
 
 
@@ -292,12 +292,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
                        );
 
        /* IRQ */
-       status = omap_request_gpio(irq);
+       status = gpio_request(irq, "TUSB6010 irq");
        if (status < 0) {
                printk(error, 3, status);
                return status;
        }
-       omap_set_gpio_direction(irq, 1);
+       gpio_direction_input(irq);
        tusb_resources[2].start = irq + IH_GPIO_BASE;
 
        /* set up memory timings ... can speed them up later */
index 3d4a1bc123551ca16dcf7e450b9c858b8c042122..edc38e2c856faf18ea0202364d86912c579632cd 100644 (file)
@@ -1,4 +1,4 @@
-obj-y                          += common.o addr-map.o pci.o gpio.o irq.o mpp.o
+obj-y                          += common.o addr-map.o pci.o irq.o mpp.o
 obj-$(CONFIG_MACH_DB88F5281)   += db88f5281-setup.o
 obj-$(CONFIG_MACH_RD88F5182)   += rd88f5182-setup.o
 obj-$(CONFIG_MACH_KUROBOX_PRO) += kurobox_pro-setup.o
index 437065c25c9cdf4c6a902576c32ae15d3d3bdc20..0a623379789f03c4603cc43f33ebabcb2a8759b4 100644 (file)
@@ -72,6 +72,7 @@ void __init orion5x_map_io(void)
  ****************************************************************************/
 static struct orion_ehci_data orion5x_ehci_data = {
        .dram           = &orion5x_mbus_dram_info,
+       .phy_version    = EHCI_PHY_ORION,
 };
 
 static u64 ehci_dmamask = 0xffffffffUL;
index a000c7c6ee96191ec7592055492f588b22bdfcd4..798b9a5e3da919852265ad8266615f7fe6a50cf7 100644 (file)
@@ -51,13 +51,6 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
 struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
 int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
 
-/*
- * Valid GPIO pins according to MPP setup, used by machine-setup.
- * (/mach-orion/gpio.c).
- */
-void orion5x_gpio_set_valid(unsigned pin, int valid);
-void gpio_display(void);       /* debug */
-
 struct machine_desc;
 struct meminfo;
 struct tag;
index 3e66098340a538b146c357d51d0fab4218ee313a..0722d6510df17579e5f74d5cdbd3c026827b50a0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
+#include <linux/ata_platform.h>
 #include <asm/mach-types.h>
 #include <asm/gpio.h>
 #include <asm/mach/arch.h>
@@ -64,9 +65,21 @@ static struct hw_pci dns323_pci __initdata = {
        .map_irq        = dns323_pci_map_irq,
 };
 
+static int __init dns323_dev_id(void)
+{
+       u32 dev, rev;
+
+       orion5x_pcie_id(&dev, &rev);
+
+       return dev;
+}
+
 static int __init dns323_pci_init(void)
 {
-       if (machine_is_dns323())
+       /* The 5182 doesn't really use it's PCI bus, and initialising PCI
+        * gets in the way of initialising the SATA controller.
+        */
+       if (machine_is_dns323() && dns323_dev_id() != MV88F5182_DEV_ID)
                pci_common_init(&dns323_pci);
 
        return 0;
@@ -74,14 +87,6 @@ static int __init dns323_pci_init(void)
 
 subsys_initcall(dns323_pci_init);
 
-/****************************************************************************
- * Ethernet
- */
-
-static struct mv643xx_eth_platform_data dns323_eth_data = {
-       .phy_addr = MV643XX_ETH_PHY_ADDR(8),
-};
-
 /****************************************************************************
  * 8MiB NOR flash (Spansion S29GL064M90TFIR4)
  *
@@ -142,6 +147,90 @@ static struct platform_device dns323_nor_flash = {
        .num_resources  = 1,
 };
 
+/****************************************************************************
+ * Ethernet
+ */
+
+static struct mv643xx_eth_platform_data dns323_eth_data = {
+       .phy_addr = MV643XX_ETH_PHY_ADDR(8),
+};
+
+/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
+ * functions be kept somewhere?
+ */
+static int __init dns323_parse_hex_nibble(char n)
+{
+       if (n >= '0' && n <= '9')
+               return n - '0';
+
+       if (n >= 'A' && n <= 'F')
+               return n - 'A' + 10;
+
+       if (n >= 'a' && n <= 'f')
+               return n - 'a' + 10;
+
+       return -1;
+}
+
+static int __init dns323_parse_hex_byte(const char *b)
+{
+       int hi;
+       int lo;
+
+       hi = dns323_parse_hex_nibble(b[0]);
+       lo = dns323_parse_hex_nibble(b[1]);
+
+       if (hi < 0 || lo < 0)
+               return -1;
+
+       return (hi << 4) | lo;
+}
+
+static int __init dns323_read_mac_addr(void)
+{
+       u_int8_t addr[6];
+       int i;
+       char *mac_page;
+
+       /* MAC address is stored as a regular ol' string in /dev/mtdblock4
+        * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
+        */
+       mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024);
+       if (!mac_page)
+               return -ENOMEM;
+
+       /* Sanity check the string we're looking at */
+       for (i = 0; i < 5; i++) {
+               if (*(mac_page + (i * 3) + 2) != ':') {
+                       goto error_fail;
+               }
+       }
+
+       for (i = 0; i < 6; i++) {
+               int byte;
+
+               byte = dns323_parse_hex_byte(mac_page + (i * 3));
+               if (byte < 0) {
+                       goto error_fail;
+               }
+
+               addr[i] = byte;
+       }
+
+       iounmap(mac_page);
+       printk("DNS323: Found ethernet MAC address: ");
+       for (i = 0; i < 6; i++)
+               printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n");
+
+       memcpy(dns323_eth_data.mac_addr, addr, 6);
+
+       return 0;
+
+error_fail:
+       iounmap(mac_page);
+       return -EINVAL;
+}
+
 /****************************************************************************
  * GPIO LEDs (simple - doesn't use hardware blinking support)
  */
@@ -207,10 +296,17 @@ static struct platform_device dns323_button_device = {
        },
 };
 
+/*****************************************************************************
+ * SATA
+ */
+static struct mv_sata_platform_data dns323_sata_data = {
+       .n_ports        = 2,
+};
+
 /****************************************************************************
  * General Setup
  */
-static struct orion5x_mpp_mode dns323_mpp_modes[] __initdata = {
+static struct orion5x_mpp_mode dns323_mv88f5181_mpp_modes[] __initdata = {
        {  0, MPP_PCIE_RST_OUTn },
        {  1, MPP_GPIO },               /* right amber LED (sata ch0) */
        {  2, MPP_GPIO },               /* left amber LED (sata ch1) */
@@ -234,6 +330,30 @@ static struct orion5x_mpp_mode dns323_mpp_modes[] __initdata = {
        { -1 },
 };
 
+static struct orion5x_mpp_mode dns323_mv88f5182_mpp_modes[] __initdata = {
+       {  0, MPP_UNUSED },
+       {  1, MPP_GPIO },               /* right amber LED (sata ch0) */
+       {  2, MPP_GPIO },               /* left amber LED (sata ch1) */
+       {  3, MPP_UNUSED },
+       {  4, MPP_GPIO },               /* power button LED */
+       {  5, MPP_GPIO },               /* power button LED */
+       {  6, MPP_GPIO },               /* GMT G751-2f overtemp */
+       {  7, MPP_GPIO },               /* M41T80 nIRQ/OUT/SQW */
+       {  8, MPP_GPIO },               /* triggers power off */
+       {  9, MPP_GPIO },               /* power button switch */
+       { 10, MPP_GPIO },               /* reset button switch */
+       { 11, MPP_UNUSED },
+       { 12, MPP_SATA_LED },
+       { 13, MPP_SATA_LED },
+       { 14, MPP_SATA_LED },
+       { 15, MPP_SATA_LED },
+       { 16, MPP_UNUSED },
+       { 17, MPP_UNUSED },
+       { 18, MPP_UNUSED },
+       { 19, MPP_UNUSED },
+       { -1 },
+};
+
 /*
  * On the DNS-323 the following devices are attached via I2C:
  *
@@ -264,16 +384,15 @@ static void __init dns323_init(void)
        /* Setup basic Orion functions. Need to be called early. */
        orion5x_init();
 
-       orion5x_mpp_conf(dns323_mpp_modes);
-       writel(0, MPP_DEV_CTRL);                /* DEV_D[31:16] */
-
-       /*
-        * Configure peripherals.
+       /* Just to be tricky, the 5182 has a completely different
+        * set of MPP modes to the 5181.
         */
-       orion5x_ehci0_init();
-       orion5x_eth_init(&dns323_eth_data);
-       orion5x_i2c_init();
-       orion5x_uart0_init();
+       if (dns323_dev_id() == MV88F5182_DEV_ID)
+               orion5x_mpp_conf(dns323_mv88f5182_mpp_modes);
+       else {
+               orion5x_mpp_conf(dns323_mv88f5181_mpp_modes);
+               writel(0, MPP_DEV_CTRL);                /* DEV_D[31:16] */
+       }
 
        /* setup flash mapping
         * CS3 holds a 8 MB Spansion S29GL064M90TFIR4
@@ -288,6 +407,23 @@ static void __init dns323_init(void)
        i2c_register_board_info(0, dns323_i2c_devices,
                                ARRAY_SIZE(dns323_i2c_devices));
 
+       /*
+        * Configure peripherals.
+        */
+       if (dns323_read_mac_addr() < 0)
+               printk("DNS323: Failed to read MAC address\n");
+
+       orion5x_ehci0_init();
+       orion5x_eth_init(&dns323_eth_data);
+       orion5x_i2c_init();
+       orion5x_uart0_init();
+
+       /* The 5182 has it's SATA controller on-chip, and needs it's own little
+        * init routine.
+        */
+       if (dns323_dev_id() == MV88F5182_DEV_ID)
+               orion5x_sata_init(&dns323_sata_data);
+
        /* register dns323 specific power-off method */
        if (gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0 ||
            gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)
diff --git a/arch/arm/mach-orion5x/gpio.c b/arch/arm/mach-orion5x/gpio.c
deleted file mode 100644 (file)
index f99d088..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * arch/arm/mach-orion5x/gpio.c
- *
- * GPIO functions for Marvell Orion System On Chip
- *
- * Maintainer: Tzachi Perelstein <tzachi@marvell.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/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-#include <linux/io.h>
-#include <asm/gpio.h>
-#include <mach/orion5x.h>
-#include "common.h"
-
-static DEFINE_SPINLOCK(gpio_lock);
-static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)];
-static const char *gpio_label[GPIO_MAX];  /* non null for allocated GPIOs */
-
-void __init orion5x_gpio_set_valid(unsigned pin, int valid)
-{
-       if (valid)
-               __set_bit(pin, gpio_valid);
-       else
-               __clear_bit(pin, gpio_valid);
-}
-
-/*
- * GENERIC_GPIO primitives
- */
-int gpio_direction_input(unsigned pin)
-{
-       unsigned long flags;
-
-       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       /*
-        * Some callers might have not used the gpio_request(),
-        * so flag this pin as requested now.
-        */
-       if (!gpio_label[pin])
-               gpio_label[pin] = "?";
-
-       orion5x_setbits(GPIO_IO_CONF, 1 << pin);
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-       return 0;
-}
-EXPORT_SYMBOL(gpio_direction_input);
-
-int gpio_direction_output(unsigned pin, int value)
-{
-       unsigned long flags;
-       int mask;
-
-       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       /*
-        * Some callers might have not used the gpio_request(),
-        * so flag this pin as requested now.
-        */
-       if (!gpio_label[pin])
-               gpio_label[pin] = "?";
-
-       mask = 1 << pin;
-       orion5x_clrbits(GPIO_BLINK_EN, mask);
-       if (value)
-               orion5x_setbits(GPIO_OUT, mask);
-       else
-               orion5x_clrbits(GPIO_OUT, mask);
-       orion5x_clrbits(GPIO_IO_CONF, mask);
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-       return 0;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-int gpio_get_value(unsigned pin)
-{
-       int val, mask = 1 << pin;
-
-       if (readl(GPIO_IO_CONF) & mask)
-               val = readl(GPIO_DATA_IN) ^ readl(GPIO_IN_POL);
-       else
-               val = readl(GPIO_OUT);
-
-       return val & mask;
-}
-EXPORT_SYMBOL(gpio_get_value);
-
-void gpio_set_value(unsigned pin, int value)
-{
-       unsigned long flags;
-       int mask = 1 << pin;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       orion5x_clrbits(GPIO_BLINK_EN, mask);
-       if (value)
-               orion5x_setbits(GPIO_OUT, mask);
-       else
-               orion5x_clrbits(GPIO_OUT, mask);
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-}
-EXPORT_SYMBOL(gpio_set_value);
-
-void orion5x_gpio_set_blink(unsigned pin, int blink)
-{
-       unsigned long flags;
-       int mask = 1 << pin;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       orion5x_clrbits(GPIO_OUT, mask);
-       if (blink)
-               orion5x_setbits(GPIO_BLINK_EN, mask);
-       else
-               orion5x_clrbits(GPIO_BLINK_EN, mask);
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-}
-EXPORT_SYMBOL(orion5x_gpio_set_blink);
-
-int gpio_request(unsigned pin, const char *label)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       if (gpio_label[pin]) {
-               pr_debug("%s: GPIO %d already used as %s\n",
-                        __func__, pin, gpio_label[pin]);
-               ret = -EBUSY;
-       } else
-               gpio_label[pin] = label ? label : "?";
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-       return ret;
-}
-EXPORT_SYMBOL(gpio_request);
-
-void gpio_free(unsigned pin)
-{
-       might_sleep();
-
-       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
-               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
-               return;
-       }
-
-       if (!gpio_label[pin])
-               pr_warning("%s: GPIO %d already freed\n", __func__, pin);
-       else
-               gpio_label[pin] = NULL;
-}
-EXPORT_SYMBOL(gpio_free);
-
-/* Debug helper */
-void gpio_display(void)
-{
-       int i;
-
-       for (i = 0; i < GPIO_MAX; i++) {
-               printk(KERN_DEBUG "Pin-%d: ", i);
-
-               if (!test_bit(i, gpio_valid)) {
-                       printk("non-GPIO\n");
-               } else if (!gpio_label[i]) {
-                       printk("GPIO, free\n");
-               } else {
-                       printk("GPIO, used by %s, ", gpio_label[i]);
-                       if (readl(GPIO_IO_CONF) & (1 << i)) {
-                               printk("input, active %s, level %s, edge %s\n",
-                               ((readl(GPIO_IN_POL) >> i) & 1) ? "low" : "high",
-                               ((readl(GPIO_LEVEL_MASK) >> i) & 1) ? "enabled" : "masked",
-                               ((readl(GPIO_EDGE_MASK) >> i) & 1) ? "enabled" : "masked");
-                       } else {
-                               printk("output, val=%d\n", (readl(GPIO_OUT) >> i) & 1);
-                       }
-               }
-       }
-
-       printk(KERN_DEBUG "MPP_0_7_CTRL (0x%08x) = 0x%08x\n",
-                               MPP_0_7_CTRL, readl(MPP_0_7_CTRL));
-       printk(KERN_DEBUG "MPP_8_15_CTRL (0x%08x) = 0x%08x\n",
-                               MPP_8_15_CTRL, readl(MPP_8_15_CTRL));
-       printk(KERN_DEBUG "MPP_16_19_CTRL (0x%08x) = 0x%08x\n",
-                               MPP_16_19_CTRL, readl(MPP_16_19_CTRL));
-       printk(KERN_DEBUG "MPP_DEV_CTRL (0x%08x) = 0x%08x\n",
-                               MPP_DEV_CTRL, readl(MPP_DEV_CTRL));
-       printk(KERN_DEBUG "GPIO_OUT (0x%08x) = 0x%08x\n",
-                               GPIO_OUT, readl(GPIO_OUT));
-       printk(KERN_DEBUG "GPIO_IO_CONF (0x%08x) = 0x%08x\n",
-                               GPIO_IO_CONF, readl(GPIO_IO_CONF));
-       printk(KERN_DEBUG "GPIO_BLINK_EN (0x%08x) = 0x%08x\n",
-                               GPIO_BLINK_EN, readl(GPIO_BLINK_EN));
-       printk(KERN_DEBUG "GPIO_IN_POL (0x%08x) = 0x%08x\n",
-                               GPIO_IN_POL, readl(GPIO_IN_POL));
-       printk(KERN_DEBUG "GPIO_DATA_IN (0x%08x) = 0x%08x\n",
-                               GPIO_DATA_IN, readl(GPIO_DATA_IN));
-       printk(KERN_DEBUG "GPIO_LEVEL_MASK (0x%08x) = 0x%08x\n",
-                               GPIO_LEVEL_MASK, readl(GPIO_LEVEL_MASK));
-       printk(KERN_DEBUG "GPIO_EDGE_CAUSE (0x%08x) = 0x%08x\n",
-                               GPIO_EDGE_CAUSE, readl(GPIO_EDGE_CAUSE));
-       printk(KERN_DEBUG "GPIO_EDGE_MASK (0x%08x) = 0x%08x\n",
-                               GPIO_EDGE_MASK, readl(GPIO_EDGE_MASK));
-}
diff --git a/arch/arm/mach-orion5x/include/mach/dma.h b/arch/arm/mach-orion5x/include/mach/dma.h
deleted file mode 100644 (file)
index 40a8c17..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
index 65dc136a86f70e22de74ad1e3d2267498fb2ad42..d8182e87ac16ede59c955ad7108688ea04fcfa85 100644 (file)
@@ -2,18 +2,26 @@
  * arch/arm/mach-orion5x/include/mach/gpio.h
  *
  * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
+ * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
 
-extern int gpio_request(unsigned pin, const char *label);
-extern void gpio_free(unsigned pin);
-extern int gpio_direction_input(unsigned pin);
-extern int gpio_direction_output(unsigned pin, int value);
-extern int gpio_get_value(unsigned pin);
-extern void gpio_set_value(unsigned pin, int value);
-extern void orion5x_gpio_set_blink(unsigned pin, int blink);
-extern void gpio_display(void);                /* debug */
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <mach/irqs.h>
+#include <plat/gpio.h>
+#include <asm-generic/gpio.h>          /* cansleep wrappers */
+
+#define GPIO_MAX               32
+#define GPIO_OUT(pin)          ORION5X_DEV_BUS_REG(0x100)
+#define GPIO_IO_CONF(pin)      ORION5X_DEV_BUS_REG(0x104)
+#define GPIO_BLINK_EN(pin)     ORION5X_DEV_BUS_REG(0x108)
+#define GPIO_IN_POL(pin)       ORION5X_DEV_BUS_REG(0x10c)
+#define GPIO_DATA_IN(pin)      ORION5X_DEV_BUS_REG(0x110)
+#define GPIO_EDGE_CAUSE(pin)   ORION5X_DEV_BUS_REG(0x114)
+#define GPIO_EDGE_MASK(pin)    ORION5X_DEV_BUS_REG(0x118)
+#define GPIO_LEVEL_MASK(pin)   ORION5X_DEV_BUS_REG(0x11c)
 
 static inline int gpio_to_irq(int pin)
 {
@@ -25,4 +33,5 @@ static inline int irq_to_gpio(int irq)
        return irq - IRQ_ORION5X_GPIO_START;
 }
 
-#include <asm-generic/gpio.h>          /* cansleep wrappers */
+
+#endif
index f24b2513f7f366d896bf016bd81bf9b3dd7eee56..c47b033bd999e67588e037522aa897aefae6bc12 100644 (file)
@@ -38,14 +38,9 @@ __arch_iounmap(void __iomem *addr)
                __iounmap(addr);
 }
 
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-
 #define __arch_ioremap(p, s, m)        __arch_ioremap(p, s, m)
 #define __arch_iounmap(a)      __arch_iounmap(a)
-#define __io(a)                        __io(a)
+#define __io(a)                        __typesafe_io(a)
 #define __mem_pci(a)           (a)
 
 
index d5b0fbf6b9657f1f6a4f79909c8902dd64ccd9d1..a6fa9d8f12d88846d5018c26cb924aefc08d6db4 100644 (file)
@@ -13,8 +13,6 @@
 #ifndef __ASM_ARCH_IRQS_H
 #define __ASM_ARCH_IRQS_H
 
-#include "orion5x.h"   /* need GPIO_MAX */
-
 /*
  * Orion Main Interrupt Controller
  */
@@ -54,7 +52,7 @@
  * Orion General Purpose Pins
  */
 #define IRQ_ORION5X_GPIO_START 32
-#define NR_GPIO_IRQS           GPIO_MAX
+#define NR_GPIO_IRQS           32
 
 #define NR_IRQS                        (IRQ_ORION5X_GPIO_START + NR_GPIO_IRQS)
 
index 54dd76b013f266f4d5abc0fe1818630990168c27..52a2955d0f87a8ec63f6ed86fd91be1ab7e85a96 100644 (file)
@@ -9,8 +9,4 @@
 
 #define PHYS_OFFSET    UL(0x00000000)
 
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
-
 #endif
index 9f5ce1ce5840845d2a6f42d2306ed0f75689d717..67bda31406dd7d540a61f1e30deb66418aeb0cf7 100644 (file)
 #define MPP_16_19_CTRL         ORION5X_DEV_BUS_REG(0x050)
 #define MPP_DEV_CTRL           ORION5X_DEV_BUS_REG(0x008)
 #define MPP_RESET_SAMPLE       ORION5X_DEV_BUS_REG(0x010)
-#define GPIO_OUT               ORION5X_DEV_BUS_REG(0x100)
-#define GPIO_IO_CONF           ORION5X_DEV_BUS_REG(0x104)
-#define GPIO_BLINK_EN          ORION5X_DEV_BUS_REG(0x108)
-#define GPIO_IN_POL            ORION5X_DEV_BUS_REG(0x10c)
-#define GPIO_DATA_IN           ORION5X_DEV_BUS_REG(0x110)
-#define GPIO_EDGE_CAUSE                ORION5X_DEV_BUS_REG(0x114)
-#define GPIO_EDGE_MASK         ORION5X_DEV_BUS_REG(0x118)
-#define GPIO_LEVEL_MASK                ORION5X_DEV_BUS_REG(0x11c)
 #define DEV_BANK_0_PARAM       ORION5X_DEV_BUS_REG(0x45c)
 #define DEV_BANK_1_PARAM       ORION5X_DEV_BUS_REG(0x460)
 #define DEV_BANK_2_PARAM       ORION5X_DEV_BUS_REG(0x464)
 #define DEV_BUS_CTRL           ORION5X_DEV_BUS_REG(0x4c0)
 #define DEV_BUS_INT_CAUSE      ORION5X_DEV_BUS_REG(0x4d0)
 #define DEV_BUS_INT_MASK       ORION5X_DEV_BUS_REG(0x4d4)
-#define GPIO_MAX               32
 
 /***************************************************************************
  * Orion CPU Bridge Registers
index 632a36f5cf1492473ae1409522457a83dc23981a..0caae43301e54e472d82187680ed69fca4feda72 100644 (file)
 #include <plat/irq.h>
 #include "common.h"
 
-/*****************************************************************************
- * Orion GPIO IRQ
- *
- * GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same
- * value of the line or the opposite value.
- *
- * Level IRQ handlers: DATA_IN is used directly as cause register.
- *                     Interrupt are masked by LEVEL_MASK registers.
- * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
- *                     Interrupt are masked by EDGE_MASK registers.
- * Both-edge handlers: Similar to regular Edge handlers, but also swaps
- *                     the polarity to catch the next line transaction.
- *                     This is a race condition that might not perfectly
- *                     work on some use cases.
- *
- * Every eight GPIO lines are grouped (OR'ed) before going up to main
- * cause register.
- *
- *                    EDGE  cause    mask
- *        data-in   /--------| |-----| |----\
- *     -----| |-----                         ---- to main cause reg
- *           X      \----------------| |----/
- *        polarity    LEVEL          mask
- *
- ****************************************************************************/
-static void orion5x_gpio_irq_ack(u32 irq)
-{
-       int pin = irq_to_gpio(irq);
-       if (irq_desc[irq].status & IRQ_LEVEL)
-               /*
-                * Mask bit for level interrupt
-                */
-               orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin);
-       else
-               /*
-                * Clear casue bit for egde interrupt
-                */
-               orion5x_clrbits(GPIO_EDGE_CAUSE, 1 << pin);
-}
-
-static void orion5x_gpio_irq_mask(u32 irq)
-{
-       int pin = irq_to_gpio(irq);
-       if (irq_desc[irq].status & IRQ_LEVEL)
-               orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin);
-       else
-               orion5x_clrbits(GPIO_EDGE_MASK, 1 << pin);
-}
-
-static void orion5x_gpio_irq_unmask(u32 irq)
+static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-       int pin = irq_to_gpio(irq);
-       if (irq_desc[irq].status & IRQ_LEVEL)
-               orion5x_setbits(GPIO_LEVEL_MASK, 1 << pin);
-       else
-               orion5x_setbits(GPIO_EDGE_MASK, 1 << pin);
-}
-
-static int orion5x_gpio_set_irq_type(u32 irq, u32 type)
-{
-       int pin = irq_to_gpio(irq);
-       struct irq_desc *desc;
-
-       if ((readl(GPIO_IO_CONF) & (1 << pin)) == 0) {
-               printk(KERN_ERR "orion5x_gpio_set_irq_type failed "
-                               "(irq %d, pin %d).\n", irq, pin);
-               return -EINVAL;
-       }
-
-       desc = irq_desc + irq;
-
-       switch (type) {
-       case IRQ_TYPE_LEVEL_HIGH:
-               desc->handle_irq = handle_level_irq;
-               desc->status |= IRQ_LEVEL;
-               orion5x_clrbits(GPIO_IN_POL, (1 << pin));
-               break;
-       case IRQ_TYPE_LEVEL_LOW:
-               desc->handle_irq = handle_level_irq;
-               desc->status |= IRQ_LEVEL;
-               orion5x_setbits(GPIO_IN_POL, (1 << pin));
-               break;
-       case IRQ_TYPE_EDGE_RISING:
-               desc->handle_irq = handle_edge_irq;
-               desc->status &= ~IRQ_LEVEL;
-               orion5x_clrbits(GPIO_IN_POL, (1 << pin));
-               break;
-       case IRQ_TYPE_EDGE_FALLING:
-               desc->handle_irq = handle_edge_irq;
-               desc->status &= ~IRQ_LEVEL;
-               orion5x_setbits(GPIO_IN_POL, (1 << pin));
-               break;
-       case IRQ_TYPE_EDGE_BOTH:
-               desc->handle_irq = handle_edge_irq;
-               desc->status &= ~IRQ_LEVEL;
-               /*
-                * set initial polarity based on current input level
-                */
-               if ((readl(GPIO_IN_POL) ^ readl(GPIO_DATA_IN))
-                   & (1 << pin))
-                       orion5x_setbits(GPIO_IN_POL, (1 << pin)); /* falling */
-               else
-                       orion5x_clrbits(GPIO_IN_POL, (1 << pin)); /* rising */
-
-               break;
-       default:
-               printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type);
-               return -EINVAL;
-       }
-
-       desc->status &= ~IRQ_TYPE_SENSE_MASK;
-       desc->status |= type & IRQ_TYPE_SENSE_MASK;
-
-       return 0;
-}
-
-static struct irq_chip orion5x_gpio_irq_chip = {
-       .name           = "Orion-IRQ-GPIO",
-       .ack            = orion5x_gpio_irq_ack,
-       .mask           = orion5x_gpio_irq_mask,
-       .unmask         = orion5x_gpio_irq_unmask,
-       .set_type       = orion5x_gpio_set_irq_type,
-};
-
-static void orion5x_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       u32 cause, offs, pin;
-
        BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31);
-       offs = (irq - IRQ_ORION5X_GPIO_0_7) * 8;
-       cause = (readl(GPIO_DATA_IN) & readl(GPIO_LEVEL_MASK)) |
-               (readl(GPIO_EDGE_CAUSE) & readl(GPIO_EDGE_MASK));
 
-       for (pin = offs; pin < offs + 8; pin++) {
-               if (cause & (1 << pin)) {
-                       irq = gpio_to_irq(pin);
-                       desc = irq_desc + irq;
-                       if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
-                               /* Swap polarity (race with GPIO line) */
-                               u32 polarity = readl(GPIO_IN_POL);
-                               polarity ^= 1 << pin;
-                               writel(polarity, GPIO_IN_POL);
-                       }
-                       generic_handle_irq(irq);
-               }
-       }
+       orion_gpio_irq_handler((irq - IRQ_ORION5X_GPIO_0_7) << 3);
 }
 
-static void __init orion5x_init_gpio_irq(void)
+void __init orion5x_init_irq(void)
 {
        int i;
-       struct irq_desc *desc;
+
+       orion_irq_init(0, (void __iomem *)MAIN_IRQ_MASK);
 
        /*
         * Mask and clear GPIO IRQ interrupts
         */
-       writel(0x0, GPIO_LEVEL_MASK);
-       writel(0x0, GPIO_EDGE_MASK);
-       writel(0x0, GPIO_EDGE_CAUSE);
+       writel(0x0, GPIO_LEVEL_MASK(0));
+       writel(0x0, GPIO_EDGE_MASK(0));
+       writel(0x0, GPIO_EDGE_CAUSE(0));
 
        /*
         * Register chained level handlers for GPIO IRQs by default.
         * User can use set_type() if he wants to use edge types handlers.
         */
        for (i = IRQ_ORION5X_GPIO_START; i < NR_IRQS; i++) {
-               set_irq_chip(i, &orion5x_gpio_irq_chip);
+               set_irq_chip(i, &orion_gpio_irq_level_chip);
                set_irq_handler(i, handle_level_irq);
-               desc = irq_desc + i;
-               desc->status |= IRQ_LEVEL;
+               irq_desc[i].status |= IRQ_LEVEL;
                set_irq_flags(i, IRQF_VALID);
        }
-       set_irq_chained_handler(IRQ_ORION5X_GPIO_0_7, orion5x_gpio_irq_handler);
-       set_irq_chained_handler(IRQ_ORION5X_GPIO_8_15, orion5x_gpio_irq_handler);
-       set_irq_chained_handler(IRQ_ORION5X_GPIO_16_23, orion5x_gpio_irq_handler);
-       set_irq_chained_handler(IRQ_ORION5X_GPIO_24_31, orion5x_gpio_irq_handler);
-}
-
-/*****************************************************************************
- * Orion Main IRQ
- ****************************************************************************/
-static void __init orion5x_init_main_irq(void)
-{
-       orion_irq_init(0, (void __iomem *)MAIN_IRQ_MASK);
-}
-
-void __init orion5x_init_irq(void)
-{
-       orion5x_init_main_irq();
-       orion5x_init_gpio_irq();
+       set_irq_chained_handler(IRQ_ORION5X_GPIO_0_7, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_ORION5X_GPIO_8_15, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_ORION5X_GPIO_16_23, gpio_irq_handler);
+       set_irq_chained_handler(IRQ_ORION5X_GPIO_24_31, gpio_irq_handler);
 }
index 640ea2a3fc6cf758b774877b639e64c12853fec1..e23a3f91d6c61b777356187df9aceddfc1dae160 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/mbus.h>
 #include <linux/io.h>
+#include <asm/gpio.h>
 #include <mach/hardware.h>
 #include "common.h"
 #include "mpp.h"
@@ -152,7 +153,10 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
                *reg &= ~(0xf << shift);
                *reg |= (num_type & 0xf) << shift;
 
-               orion5x_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
+               if (mode->type == MPP_UNUSED && (mode->mpp < 16 || is_5182()))
+                       orion_gpio_set_unused(mode->mpp);
+
+               orion_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
 
                mode++;
        }
index ac2f70eddb9e8e49034bf53257893e63be3de5f1..425f7188505ed4bac57decaaa09b6fd1ab37e3f2 100644 (file)
@@ -25,9 +25,8 @@
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <asm/dma-mapping.h>
-#include <asm/mach/dma.h>
 #include <mach/clock.h>
 
 static struct dma_channel {
index 5442d04fc57536188103dbb1a98a707bbc9d8ca2..f094bf8bfb1819c96ecd43349091bc3fda182433 100644 (file)
@@ -16,8 +16,6 @@
 
 #include "platform.h"
 
-#define MAX_DMA_ADDRESS                0xffffffff
-
 #define MAX_DMA_CHANNELS       8
 
 #define DMAC_BASE              IO_ADDRESS(PNX4008_DMA_CONFIG_BASE)
index c6206f25839d16ed65f0990ce266fa2467ea1567..cbf0904540ea4ed2d930a4e348b9f292f15aeffd 100644 (file)
@@ -15,7 +15,7 @@
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 5789a2d16f5a03da63b233229549217ef0bcbae0..0e8770081058954ab1ce1f255453e8a0d3d9505d 100644 (file)
@@ -16,9 +16,6 @@
 /*
  * Physical DRAM offset.
  */
-#define PHYS_OFFSET     (0x80000000)
-
-#define __virt_to_bus(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
-#define __bus_to_virt(x) ((x) + PAGE_OFFSET - PHYS_OFFSET)
+#define PHYS_OFFSET    UL(0x80000000)
 
 #endif
index a062235e83a8b4c3b272c3d7af016d85dcd8b2ba..8eea7306f29bc7bbe97e4b9657fbda59f5576a9b 100644 (file)
@@ -19,20 +19,34 @@ config CPU_PXA320
 config CPU_PXA930
        bool "PXA930 (codename Tavor-P)"
 
+config CPU_PXA935
+       bool "PXA935 (codename Tavor-P65)"
+
 endmenu
 
 endif
 
 config ARCH_GUMSTIX
-       bool "Gumstix XScale boards"
+       bool "Gumstix XScale 255 boards"
+       select PXA25x
        help
-         Say Y here if you intend to run this kernel on a
-         Gumstix Full Function Minature Computer.
+         Say Y here if you intend to run this kernel on
+         Basix, Connex, ws-200ax, ws-400ax systems
 
-config MACH_GUMSTIX_F
-       bool "Basix, Connex, ws-200ax, ws-400ax systems"
+choice
+       prompt "Gumstix Carrier/Expansion Board"
        depends on ARCH_GUMSTIX
-       select PXA25x
+
+config GUMSTIX_AM200EPD
+       bool "Enable AM200EPD board support"
+
+endchoice
+
+config MACH_INTELMOTE2
+       bool "Intel Mote 2 Platform"
+       select PXA27x
+       select IWMMXT
+       select PXA_HAVE_BOARD_IRQS
 
 config ARCH_LUBBOCK
        bool "Intel DBPXA250 Development Platform"
@@ -199,6 +213,10 @@ config MACH_E800
 config TRIZEPS_PXA
        bool "PXA based Keith und Koep Trizeps DIMM-Modules"
 
+config MACH_H5000
+       bool "HP iPAQ h5000"
+       select PXA25x
+
 config MACH_TRIZEPS4
        bool "Keith und Koep Trizeps4 DIMM-Module"
        depends on TRIZEPS_PXA
@@ -283,7 +301,6 @@ config MACH_MIOA701
        bool "Mitac Mio A701 Support"
        select PXA27x
        select IWMMXT
-       select LEDS_GPIO
        select HAVE_PWM
        select GPIO_SYSFS
        help
@@ -342,10 +359,6 @@ config PCM990_DISPLAY_NONE
 
 endchoice
 
-config MACH_AM200EPD
-       depends on MACH_GUMSTIX_F
-       bool "Enable AM200EPD board support"
-
 config PXA_EZX
        bool "Motorola EZX Platform"
        select PXA27x
@@ -386,16 +399,25 @@ endmenu
 
 config PXA25x
        bool
+       select CPU_XSCALE
        help
          Select code specific to PXA21x/25x/26x variants
 
 config PXA27x
        bool
+       select CPU_XSCALE
        help
          Select code specific to PXA27x variants
 
+config CPU_PXA26x
+       bool
+       select PXA25x
+       help
+         Select code specific to PXA26x (codename Dalhart)
+
 config PXA3xx
        bool
+       select CPU_XSC3
        help
          Select code specific to PXA3xx variants
 
index d64c68b232e3ff8265b9c52df59863b2423004b0..7b28bb561d63c07830ea3ad04551d9ec44bd92fe 100644 (file)
@@ -27,7 +27,7 @@ obj-$(CONFIG_CPU_PXA930)      += pxa930.o
 
 # Specific board support
 obj-$(CONFIG_ARCH_GUMSTIX)     += gumstix.o
-obj-$(CONFIG_MACH_AM200EPD)    += am200epd.o
+obj-$(CONFIG_GUMSTIX_AM200EPD) += am200epd.o
 obj-$(CONFIG_ARCH_LUBBOCK)     += lubbock.o
 obj-$(CONFIG_MACH_LOGICPD_PXA270) += lpd270.o
 obj-$(CONFIG_MACH_MAINSTONE)   += mainstone.o
@@ -35,6 +35,7 @@ obj-$(CONFIG_MACH_MP900C)     += mp900.o
 obj-$(CONFIG_ARCH_PXA_IDP)     += idp.o
 obj-$(CONFIG_MACH_TRIZEPS4)    += trizeps4.o
 obj-$(CONFIG_MACH_COLIBRI)     += colibri.o
+obj-$(CONFIG_MACH_H5000)       += h5000.o
 obj-$(CONFIG_PXA_SHARP_C7xx)   += corgi.o sharpsl_pm.o corgi_pm.o
 obj-$(CONFIG_PXA_SHARP_Cxx00)  += spitz.o sharpsl_pm.o spitz_pm.o
 obj-$(CONFIG_CORGI_SSP_DEPRECATED)     += corgi_ssp.o corgi_lcd.o
@@ -69,6 +70,8 @@ obj-$(CONFIG_MACH_ARMCORE)      += cm-x2xx.o cm-x255.o cm-x270.o
 obj-$(CONFIG_MACH_CM_X300)      += cm-x300.o
 obj-$(CONFIG_PXA_EZX)           += ezx.o
 
+obj-$(CONFIG_MACH_INTELMOTE2)   += imote2.o
+
 # Support for blinky lights
 led-y := leds.o
 led-$(CONFIG_ARCH_LUBBOCK)     += leds-lubbock.o
index b965085a37b9afe98d59b42403650c6ceaf0f055..77ee80e5e47b028574b553a56597165f251375ab 100644 (file)
 #include <linux/irq.h>
 #include <linux/gpio.h>
 
+#include <mach/gumstix.h>
+#include <mach/mfp-pxa25x.h>
 #include <mach/pxafb.h>
 
+#include "generic.h"
+
 #include <video/metronomefb.h>
 
 static unsigned int panel_type = 6;
@@ -331,7 +335,16 @@ static struct metronome_board am200_board = {
        .cleanup                = am200_cleanup,
 };
 
-static int __init am200_init(void)
+static unsigned long am200_pin_config[] __initdata = {
+       GPIO51_GPIO,
+       GPIO49_GPIO,
+       GPIO48_GPIO,
+       GPIO32_GPIO,
+       GPIO17_GPIO,
+       GPIO16_GPIO,
+};
+
+int __init am200_init(void)
 {
        int ret;
 
@@ -339,6 +352,8 @@ static int __init am200_init(void)
         * creation events */
        fb_register_client(&am200_fb_notif);
 
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(am200_pin_config));
+
        /* request our platform independent driver */
        request_module("metronomefb");
 
@@ -367,8 +382,6 @@ static int __init am200_init(void)
 module_param(panel_type, uint, 0);
 MODULE_PARM_DESC(panel_type, "Select the panel type: 6, 8, 97");
 
-module_init(am200_init);
-
 MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
 MODULE_AUTHOR("Jaya Kumar");
 MODULE_LICENSE("GPL");
index ca8e205381577ab07f05fec6e573f77554672c3c..40b77408451488cc11f1408ab8c768f92980a16b 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 
+#include <asm/clkdev.h>
 #include <mach/pxa2xx-regs.h>
-#include <mach/pxa2xx-gpio.h>
 #include <mach/hardware.h>
 
 #include "devices.h"
 #include "generic.h"
 #include "clock.h"
 
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
 static DEFINE_SPINLOCK(clocks_lock);
 
-static struct clk *clk_lookup(struct device *dev, const char *id)
-{
-       struct clk *p;
-
-       list_for_each_entry(p, &clocks, node)
-               if (strcmp(id, p->name) == 0 && p->dev == dev)
-                       return p;
-
-       return NULL;
-}
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       p = clk_lookup(dev, id);
-       if (!p)
-               p = clk_lookup(NULL, id);
-       if (p)
-               clk = p;
-       mutex_unlock(&clocks_mutex);
-
-       if (!IS_ERR(clk) && clk->ops == NULL)
-               clk = clk->other;
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
 int clk_enable(struct clk *clk)
 {
        unsigned long flags;
@@ -116,37 +79,27 @@ const struct clkops clk_cken_ops = {
        .disable        = clk_cken_disable,
 };
 
-void clks_register(struct clk *clks, size_t num)
+void clks_register(struct clk_lookup *clks, size_t num)
 {
        int i;
 
-       mutex_lock(&clocks_mutex);
        for (i = 0; i < num; i++)
-               list_add(&clks[i].node, &clocks);
-       mutex_unlock(&clocks_mutex);
+               clkdev_add(&clks[i]);
 }
 
 int clk_add_alias(char *alias, struct device *alias_dev, char *id,
        struct device *dev)
 {
-       struct clk *r = clk_lookup(dev, id);
-       struct clk *new;
+       struct clk *r = clk_get(dev, id);
+       struct clk_lookup *l;
 
        if (!r)
                return -ENODEV;
 
-       new = kzalloc(sizeof(struct clk), GFP_KERNEL);
-
-       if (!new)
-               return -ENOMEM;
-
-       new->name = alias;
-       new->dev = alias_dev;
-       new->other = r;
-
-       mutex_lock(&clocks_mutex);
-       list_add(&new->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-
+       l = clkdev_alloc(r, alias, alias_dev ? dev_name(alias_dev) : NULL);
+       clk_put(r);
+       if (!l)
+               return -ENODEV;
+       clkdev_add(l);
        return 0;
 }
index 73be795fe3bfe5dcb04a25fa95c2488910efa20c..4e9c613c6767e24b557f83281927e4c9df01ce6e 100644 (file)
@@ -1,6 +1,4 @@
-#include <linux/list.h>
-
-struct clk;
+#include <asm/clkdev.h>
 
 struct clkops {
        void                    (*enable)(struct clk *);
@@ -9,9 +7,6 @@ struct clkops {
 };
 
 struct clk {
-       struct list_head        node;
-       const char              *name;
-       struct device           *dev;
        const struct clkops     *ops;
        unsigned long           rate;
        unsigned int            cken;
@@ -20,41 +15,31 @@ struct clk {
        struct clk              *other;
 };
 
-#define INIT_CKEN(_name, _cken, _rate, _delay, _dev)   \
+#define INIT_CLKREG(_clk,_devname,_conname)            \
        {                                               \
-               .name   = _name,                        \
-               .dev    = _dev,                         \
+               .clk            = _clk,                 \
+               .dev_id         = _devname,             \
+               .con_id         = _conname,             \
+       }
+
+#define DEFINE_CKEN(_name, _cken, _rate, _delay)       \
+struct clk clk_##_name = {                             \
                .ops    = &clk_cken_ops,                \
                .rate   = _rate,                        \
                .cken   = CKEN_##_cken,                 \
                .delay  = _delay,                       \
        }
 
-#define INIT_CK(_name, _cken, _ops, _dev)              \
-       {                                               \
-               .name   = _name,                        \
-               .dev    = _dev,                         \
+#define DEFINE_CK(_name, _cken, _ops)                  \
+struct clk clk_##_name = {                             \
                .ops    = _ops,                         \
                .cken   = CKEN_##_cken,                 \
        }
 
-/*
- * This is a placeholder to alias one clock device+name pair
- * to another struct clk.
- */
-#define INIT_CKOTHER(_name, _other, _dev)              \
-       {                                               \
-               .name   = _name,                        \
-               .dev    = _dev,                         \
-               .other  = _other,                       \
-       }
-
-#define INIT_CLK(_name, _ops, _rate, _delay, _dev)      \
-       {                                               \
-               .name   = _name,                        \
-               .dev    = _dev,                         \
-               .ops    = _ops,                         \
-               .rate   = _rate,                        \
+#define DEFINE_CLK(_name, _ops, _rate, _delay)         \
+struct clk clk_##_name = {                             \
+               .ops    = _ops,                         \
+               .rate   = _rate,                        \
                .delay  = _delay,                       \
        }
 
@@ -64,20 +49,16 @@ void clk_cken_enable(struct clk *clk);
 void clk_cken_disable(struct clk *clk);
 
 #ifdef CONFIG_PXA3xx
-#define PXA3xx_CKEN(_name, _cken, _rate, _delay, _dev) \
-       {                                               \
-               .name   = _name,                        \
-               .dev    = _dev,                         \
+#define DEFINE_PXA3_CKEN(_name, _cken, _rate, _delay)  \
+struct clk clk_##_name = {                             \
                .ops    = &clk_pxa3xx_cken_ops,         \
                .rate   = _rate,                        \
                .cken   = CKEN_##_cken,                 \
                .delay  = _delay,                       \
        }
 
-#define PXA3xx_CK(_name, _cken, _ops, _dev)            \
-       {                                               \
-               .name   = _name,                        \
-               .dev    = _dev,                         \
+#define DEFINE_PXA3_CK(_name, _cken, _ops)             \
+struct clk clk_##_name = {                             \
                .ops    = _ops,                         \
                .cken   = CKEN_##_cken,                 \
        }
@@ -87,7 +68,7 @@ extern void clk_pxa3xx_cken_enable(struct clk *);
 extern void clk_pxa3xx_cken_disable(struct clk *);
 #endif
 
-void clks_register(struct clk *clks, size_t num);
+void clks_register(struct clk_lookup *clks, size_t num);
 int clk_add_alias(char *alias, struct device *alias_dev, char *id,
        struct device *dev);
 
index 0b3ce3b6d896e4f348d04a408e13849ccce5538d..d99fd9e4d8885d6e1300a42dbfbae76e6a2cbe51 100644 (file)
@@ -210,10 +210,8 @@ static struct pxafb_mode_info generic_stn_320x240_mode = {
 static struct pxafb_mach_info generic_stn_320x240 = {
        .modes          = &generic_stn_320x240_mode,
        .num_modes      = 1,
-       .lccr0          = 0,
-       .lccr3          = (LCCR3_PixClkDiv(0x03) |
-                          LCCR3_Acb(0xff) |
-                          LCCR3_PCP),
+       .lcd_conn       = LCD_COLOR_STN_8BPP | LCD_PCLK_EDGE_FALL |\
+                         LCD_AC_BIAS_FREQ(0xff),
        .cmap_inverse   = 0,
        .cmap_static    = 0,
 };
@@ -236,10 +234,8 @@ static struct pxafb_mode_info generic_tft_640x480_mode = {
 static struct pxafb_mach_info generic_tft_640x480 = {
        .modes          = &generic_tft_640x480_mode,
        .num_modes      = 1,
-       .lccr0          = (LCCR0_PAS),
-       .lccr3          = (LCCR3_PixClkDiv(0x01) |
-                          LCCR3_Acb(0xff) |
-                          LCCR3_PCP),
+       .lcd_conn       = LCD_COLOR_TFT_8BPP | LCD_PCLK_EDGE_FALL |\
+                         LCD_AC_BIAS_FREQ(0xff),
        .cmap_inverse   = 0,
        .cmap_static    = 0,
 };
@@ -263,9 +259,7 @@ static struct pxafb_mode_info generic_crt_640x480_mode = {
 static struct pxafb_mach_info generic_crt_640x480 = {
        .modes          = &generic_crt_640x480_mode,
        .num_modes      = 1,
-       .lccr0          = (LCCR0_PAS),
-       .lccr3          = (LCCR3_PixClkDiv(0x01) |
-                          LCCR3_Acb(0xff)),
+       .lcd_conn       = LCD_COLOR_TFT_8BPP | LCD_AC_BIAS_FREQ(0xff),
        .cmap_inverse   = 0,
        .cmap_static    = 0,
 };
@@ -289,9 +283,7 @@ static struct pxafb_mode_info generic_crt_800x600_mode = {
 static struct pxafb_mach_info generic_crt_800x600 = {
        .modes          = &generic_crt_800x600_mode,
        .num_modes      = 1,
-       .lccr0          = (LCCR0_PAS),
-       .lccr3          = (LCCR3_PixClkDiv(0x02) |
-                          LCCR3_Acb(0xff)),
+       .lcd_conn       = LCD_COLOR_TFT_8BPP | LCD_AC_BIAS_FREQ(0xff),
        .cmap_inverse   = 0,
        .cmap_static    = 0,
 };
@@ -314,10 +306,7 @@ static struct pxafb_mode_info generic_tft_320x240_mode = {
 static struct pxafb_mach_info generic_tft_320x240 = {
        .modes          = &generic_tft_320x240_mode,
        .num_modes      = 1,
-       .lccr0          = (LCCR0_PAS),
-       .lccr3          = (LCCR3_PixClkDiv(0x06) |
-                          LCCR3_Acb(0xff) |
-                          LCCR3_PCP),
+       .lcd_conn       = LCD_COLOR_TFT_16BPP | LCD_AC_BIAS_FREQ(0xff),
        .cmap_inverse   = 0,
        .cmap_static    = 0,
 };
@@ -341,9 +330,7 @@ static struct pxafb_mode_info generic_stn_640x480_mode = {
 static struct pxafb_mach_info generic_stn_640x480 = {
        .modes          = &generic_stn_640x480_mode,
        .num_modes      = 1,
-       .lccr0          = 0,
-       .lccr3          = (LCCR3_PixClkDiv(0x02) |
-                          LCCR3_Acb(0xff)),
+       .lcd_conn       = LCD_COLOR_STN_8BPP | LCD_AC_BIAS_FREQ(0xff),
        .cmap_inverse   = 0,
        .cmap_static    = 0,
 };
index deb46cd144bff4330a975788556b3e72f9ee7c9e..ff0c577cd1ac6213ffdc474acb0803d581744693 100644 (file)
@@ -31,7 +31,6 @@
 #include <mach/mfp-pxa300.h>
 
 #include <mach/hardware.h>
-#include <mach/gpio.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
@@ -137,6 +136,10 @@ static mfp_cfg_t cm_x300_mfp_cfg[] __initdata = {
        GPIO82_GPIO | MFP_PULL_HIGH,    /* MMC CD */
        GPIO85_GPIO,                    /* MMC WP */
        GPIO99_GPIO,                    /* Ethernet IRQ */
+
+       /* Standard I2C */
+       GPIO21_I2C_SCL,
+       GPIO22_I2C_SDA,
 };
 
 #if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
index 65558d6aa220d396e1e10c350ae5ebbc679f53bf..c5e28a46b2929cc92133073608eaf84606971ca6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/fs.h>
 #include <linux/interrupt.h>
 #include <linux/mmc/host.h>
+#include <linux/mtd/physmap.h>
 #include <linux/pm.h>
 #include <linux/gpio.h>
 #include <linux/backlight.h>
@@ -541,11 +542,42 @@ err_free_1:
 static inline void corgi_init_spi(void) {}
 #endif
 
+static struct mtd_partition sharpsl_rom_parts[] = {
+       {
+               .name   ="Boot PROM Filesystem",
+               .offset = 0x00120000,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data sharpsl_rom_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(sharpsl_rom_parts),
+       .parts          = sharpsl_rom_parts,
+};
+
+static struct resource sharpsl_rom_resources[] = {
+       {
+               .start  = 0x00000000,
+               .end    = 0x007fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device sharpsl_rom_device = {
+       .name   = "physmap-flash",
+       .id     = -1,
+       .resource = sharpsl_rom_resources,
+       .num_resources = ARRAY_SIZE(sharpsl_rom_resources),
+       .dev.platform_data = &sharpsl_rom_data,
+};
+
 static struct platform_device *devices[] __initdata = {
        &corgiscoop_device,
        &corgifb_device,
        &corgikbd_device,
        &corgiled_device,
+       &sharpsl_rom_device,
 };
 
 static void corgi_poweroff(void)
index 1f272ea83f36e63c824822acc98ec388018d71ae..771dd4eac93508ac7494db0bc5b4f7f230e9b457 100644 (file)
@@ -64,7 +64,7 @@ typedef struct {
 
 /* Define the refresh period in mSec for the SDRAM and the number of rows */
 #define SDRAM_TREF     64      /* standard 64ms SDRAM */
-#define SDRAM_ROWS     4096    /* 64MB=8192 32MB=4096 */
+static unsigned int sdram_rows;
 
 #define CCLKCFG_TURBO          0x1
 #define CCLKCFG_FCS            0x2
@@ -73,6 +73,9 @@ typedef struct {
 #define MDREFR_DB2_MASK                (MDREFR_K2DB2 | MDREFR_K1DB2)
 #define MDREFR_DRI_MASK                0xFFF
 
+#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3)
+#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3)
+
 /*
  * PXA255 definitions
  */
@@ -109,6 +112,10 @@ static struct cpufreq_frequency_table
 static struct cpufreq_frequency_table
        pxa255_turbo_freq_table[NUM_PXA25x_TURBO_FREQS+1];
 
+static unsigned int pxa255_turbo_table;
+module_param(pxa255_turbo_table, uint, 0);
+MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table, !0 = turbo table)");
+
 /*
  * PXA270 definitions
  *
@@ -158,22 +165,16 @@ static struct cpufreq_frequency_table
 
 extern unsigned get_clk_frequency_khz(int info);
 
-static void find_freq_tables(struct cpufreq_policy *policy,
-                            struct cpufreq_frequency_table **freq_table,
+static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
                             pxa_freqs_t **pxa_freqs)
 {
        if (cpu_is_pxa25x()) {
-               if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+               if (!pxa255_turbo_table) {
                        *pxa_freqs = pxa255_run_freqs;
                        *freq_table = pxa255_run_freq_table;
-               } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
+               } else {
                        *pxa_freqs = pxa255_turbo_freqs;
                        *freq_table = pxa255_turbo_freq_table;
-               } else {
-                       printk("CPU PXA: Unknown policy found. "
-                              "Using CPUFREQ_POLICY_PERFORMANCE\n");
-                       *pxa_freqs = pxa255_run_freqs;
-                       *freq_table = pxa255_run_freq_table;
                }
        }
        if (cpu_is_pxa27x()) {
@@ -194,14 +195,28 @@ static void pxa27x_guess_max_freq(void)
        }
 }
 
+static void init_sdram_rows(void)
+{
+       uint32_t mdcnfg = MDCNFG;
+       unsigned int drac2 = 0, drac0 = 0;
+
+       if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3))
+               drac2 = MDCNFG_DRAC2(mdcnfg);
+
+       if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1))
+               drac0 = MDCNFG_DRAC0(mdcnfg);
+
+       sdram_rows = 1 << (11 + max(drac0, drac2));
+}
+
 static u32 mdrefr_dri(unsigned int freq)
 {
        u32 dri = 0;
 
        if (cpu_is_pxa25x())
-               dri = ((freq * SDRAM_TREF) / (SDRAM_ROWS * 32));
+               dri = ((freq * SDRAM_TREF) / (sdram_rows * 32));
        if (cpu_is_pxa27x())
-               dri = ((freq * SDRAM_TREF) / (SDRAM_ROWS - 31)) / 32;
+               dri = ((freq * SDRAM_TREF) / (sdram_rows - 31)) / 32;
        return dri;
 }
 
@@ -212,7 +227,7 @@ static int pxa_verify_policy(struct cpufreq_policy *policy)
        pxa_freqs_t *pxa_freqs;
        int ret;
 
-       find_freq_tables(policy, &pxa_freqs_table, &pxa_freqs);
+       find_freq_tables(&pxa_freqs_table, &pxa_freqs);
        ret = cpufreq_frequency_table_verify(policy, pxa_freqs_table);
 
        if (freq_debug)
@@ -240,7 +255,7 @@ static int pxa_set_target(struct cpufreq_policy *policy,
        unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
 
        /* Get the current policy */
-       find_freq_tables(policy, &pxa_freqs_table, &pxa_freq_settings);
+       find_freq_tables(&pxa_freqs_table, &pxa_freq_settings);
 
        /* Lookup the next frequency */
        if (cpufreq_frequency_table_target(policy, pxa_freqs_table,
@@ -329,11 +344,15 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
 {
        int i;
        unsigned int freq;
+       struct cpufreq_frequency_table *pxa255_freq_table;
+       pxa_freqs_t *pxa255_freqs;
 
        /* try to guess pxa27x cpu */
        if (cpu_is_pxa27x())
                pxa27x_guess_max_freq();
 
+       init_sdram_rows();
+
        /* set default policy and cpuinfo */
        policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
        policy->cur = get_clk_frequency_khz(0);    /* current freq */
@@ -354,6 +373,8 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
        }
        pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
 
+       pxa255_turbo_table = !!pxa255_turbo_table;
+
        /* Generate the pxa27x cpufreq_frequency_table struct */
        for (i = 0; i < NUM_PXA27x_FREQS; i++) {
                freq = pxa27x_freqs[i].khz;
@@ -368,8 +389,12 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
         * Set the policy's minimum and maximum frequencies from the tables
         * just constructed.  This sets cpuinfo.mxx_freq, min and max.
         */
-       if (cpu_is_pxa25x())
-               cpufreq_frequency_table_cpuinfo(policy, pxa255_run_freq_table);
+       if (cpu_is_pxa25x()) {
+               find_freq_tables(&pxa255_freq_table, &pxa255_freqs);
+               pr_info("PXA255 cpufreq using %s frequency table\n",
+                       pxa255_turbo_table ? "turbo" : "run");
+               cpufreq_frequency_table_cpuinfo(policy, pxa255_freq_table);
+       }
        else if (cpu_is_pxa27x())
                cpufreq_frequency_table_cpuinfo(policy, pxa27x_freq_table);
 
index 35736fc08634bb5033b5cf8d2c5a54fbb019fcde..e16f8e3d58d349200fb64be936345e4f63b15d46 100644 (file)
@@ -4,13 +4,12 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 
-#include <mach/gpio.h>
+#include <mach/pxa-regs.h>
 #include <mach/udc.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/i2c.h>
-#include <mach/mfp-pxa27x.h>
 #include <mach/ohci.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
@@ -156,8 +155,8 @@ void __init set_pxa_fb_parent(struct device *parent_dev)
 
 static struct resource pxa_resource_ffuart[] = {
        {
-               .start  = __PREG(FFUART),
-               .end    = __PREG(FFUART) + 35,
+               .start  = 0x40100000,
+               .end    = 0x40100023,
                .flags  = IORESOURCE_MEM,
        }, {
                .start  = IRQ_FFUART,
@@ -175,8 +174,8 @@ struct platform_device pxa_device_ffuart= {
 
 static struct resource pxa_resource_btuart[] = {
        {
-               .start  = __PREG(BTUART),
-               .end    = __PREG(BTUART) + 35,
+               .start  = 0x40200000,
+               .end    = 0x40200023,
                .flags  = IORESOURCE_MEM,
        }, {
                .start  = IRQ_BTUART,
@@ -194,8 +193,8 @@ struct platform_device pxa_device_btuart = {
 
 static struct resource pxa_resource_stuart[] = {
        {
-               .start  = __PREG(STUART),
-               .end    = __PREG(STUART) + 35,
+               .start  = 0x40700000,
+               .end    = 0x40700023,
                .flags  = IORESOURCE_MEM,
        }, {
                .start  = IRQ_STUART,
@@ -213,8 +212,8 @@ struct platform_device pxa_device_stuart = {
 
 static struct resource pxa_resource_hwuart[] = {
        {
-               .start  = __PREG(HWUART),
-               .end    = __PREG(HWUART) + 47,
+               .start  = 0x41600000,
+               .end    = 0x4160002F,
                .flags  = IORESOURCE_MEM,
        }, {
                .start  = IRQ_HWUART,
@@ -249,18 +248,53 @@ struct platform_device pxa_device_i2c = {
        .num_resources  = ARRAY_SIZE(pxai2c_resources),
 };
 
-static unsigned long pxa27x_i2c_mfp_cfg[] = {
-       GPIO117_I2C_SCL,
-       GPIO118_I2C_SDA,
-};
-
 void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
 {
-       if (cpu_is_pxa27x())
-               pxa2xx_mfp_config(ARRAY_AND_SIZE(pxa27x_i2c_mfp_cfg));
        pxa_register_device(&pxa_device_i2c, info);
 }
 
+#ifdef CONFIG_PXA27x
+static struct resource pxa27x_resources_i2c_power[] = {
+       {
+               .start  = 0x40f00180,
+               .end    = 0x40f001a3,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_PWRI2C,
+               .end    = IRQ_PWRI2C,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device pxa27x_device_i2c_power = {
+       .name           = "pxa2xx-i2c",
+       .id             = 1,
+       .resource       = pxa27x_resources_i2c_power,
+       .num_resources  = ARRAY_SIZE(pxa27x_resources_i2c_power),
+};
+#endif
+
+#ifdef CONFIG_PXA3xx
+static struct resource pxa3xx_resources_i2c_power[] = {
+       {
+               .start  = 0x40f500c0,
+               .end    = 0x40f500d3,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = IRQ_PWRI2C,
+               .end    = IRQ_PWRI2C,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device pxa3xx_device_i2c_power = {
+       .name           = "pxa2xx-i2c",
+       .id             = 1,
+       .resource       = pxa3xx_resources_i2c_power,
+       .num_resources  = ARRAY_SIZE(pxa3xx_resources_i2c_power),
+};
+#endif
+
 static struct resource pxai2s_resources[] = {
        {
                .start  = 0x40400000,
@@ -296,11 +330,36 @@ void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
        pxa_register_device(&pxa_device_ficp, info);
 }
 
-struct platform_device pxa_device_rtc = {
+static struct resource pxa_rtc_resources[] = {
+       [0] = {
+               .start  = 0x40900000,
+               .end    = 0x40900000 + 0x3b,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_RTC1Hz,
+               .end    = IRQ_RTC1Hz,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_RTCAlrm,
+               .end    = IRQ_RTCAlrm,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device sa1100_device_rtc = {
        .name           = "sa1100-rtc",
        .id             = -1,
 };
 
+struct platform_device pxa_device_rtc = {
+       .name           = "pxa-rtc",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(pxa_rtc_resources),
+       .resource       = pxa_rtc_resources,
+};
+
 static struct resource pxa_ac97_resources[] = {
        [0] = {
                .start  = 0x40500000,
index bb04af4b0aa3f7706b6124cd3ce1539e55d86288..ecc24a4dca6d52dce5dcefb88fbf24153d34a8ba 100644 (file)
@@ -11,6 +11,7 @@ extern struct platform_device pxa_device_hwuart;
 extern struct platform_device pxa_device_i2c;
 extern struct platform_device pxa_device_i2s;
 extern struct platform_device pxa_device_ficp;
+extern struct platform_device sa1100_device_rtc;
 extern struct platform_device pxa_device_rtc;
 extern struct platform_device pxa_device_ac97;
 
index c0be17e0ab82f4285921f63b7d178deeea07fa14..b1514fb20d3a6b829ccfbab0388a3fb59a7d26a0 100644 (file)
@@ -21,7 +21,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 #include <mach/pxa-regs.h>
 
index d488eded2058be2053752d5e62dbe3dc88d47042..1bd7f740427c6101e814457db68dfbe0b518ce64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Hardware definitions for the Toshiba eseries PDAs
+ * Hardware definitions for the Toshiba e330 PDAs
  *
  * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
  *
@@ -12,6 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/tc6387xb.h>
 
 #include <asm/setup.h>
 #include <asm/mach/arch.h>
 
 #include <mach/mfp-pxa25x.h>
 #include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/eseries-gpio.h>
 #include <mach/udc.h>
 
 #include "generic.h"
 #include "eseries.h"
+#include "clock.h"
+
+/* -------------------- e330 tc6387xb parameters -------------------- */
+
+static struct tc6387xb_platform_data e330_tc6387xb_info = {
+       .enable   = &eseries_tmio_enable,
+       .disable  = &eseries_tmio_disable,
+       .suspend  = &eseries_tmio_suspend,
+       .resume   = &eseries_tmio_resume,
+};
+
+static struct platform_device e330_tc6387xb_device = {
+       .name           = "tc6387xb",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &e330_tc6387xb_info,
+       },
+       .num_resources = 2,
+       .resource      = eseries_tmio_resources,
+};
+
+/* --------------------------------------------------------------- */
+
+static struct platform_device *devices[] __initdata = {
+       &e330_tc6387xb_device,
+};
 
 static void __init e330_init(void)
 {
+       eseries_register_clks();
+       eseries_get_tmio_gpios();
+       platform_add_devices(devices, ARRAY_SIZE(devices));
        pxa_set_udc_info(&e7xx_udc_mach_info);
 }
 
index 8ecbc5479828625d91f583324c17abbb80720618..251129391d7dbcde5b723346cc402a2e4b07b4df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Hardware definitions for the Toshiba eseries PDAs
+ * Hardware definitions for the Toshiba e350 PDAs
  *
  * Copyright (c) 2003 Ian Molton <spyro@f2s.com>
  *
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/t7l66xb.h>
 
 #include <asm/setup.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 
 #include <mach/mfp-pxa25x.h>
+#include <mach/pxa-regs.h>
 #include <mach/hardware.h>
+#include <mach/eseries-gpio.h>
 #include <mach/udc.h>
 
 #include "generic.h"
 #include "eseries.h"
+#include "clock.h"
+
+/* -------------------- e350 t7l66xb parameters -------------------- */
+
+static struct t7l66xb_platform_data e350_t7l66xb_info = {
+       .irq_base               = IRQ_BOARD_START,
+       .enable                 = &eseries_tmio_enable,
+       .suspend                = &eseries_tmio_suspend,
+       .resume                 = &eseries_tmio_resume,
+};
+
+static struct platform_device e350_t7l66xb_device = {
+       .name           = "t7l66xb",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &e350_t7l66xb_info,
+       },
+       .num_resources = 2,
+       .resource      = eseries_tmio_resources,
+};
+
+/* ---------------------------------------------------------- */
+
+static struct platform_device *devices[] __initdata = {
+       &e350_t7l66xb_device,
+};
 
 static void __init e350_init(void)
 {
+       eseries_register_clks();
+       eseries_get_tmio_gpios();
+       platform_add_devices(devices, ARRAY_SIZE(devices));
        pxa_set_udc_info(&e7xx_udc_mach_info);
 }
 
index 544bbaa20621eddc0e54147855407cd704117643..bed0336aca3d1c1366d4c3a5826bbefed4875c59 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/t7l66xb.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 
 #include <asm/setup.h>
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 
-#include <mach/pxa-regs.h>
 #include <mach/mfp-pxa25x.h>
+#include <mach/pxa-regs.h>
 #include <mach/hardware.h>
-
+#include <mach/eseries-gpio.h>
 #include <mach/pxafb.h>
 #include <mach/udc.h>
 
 #include "generic.h"
 #include "eseries.h"
+#include "clock.h"
 
 /* ------------------------ E400 LCD definitions ------------------------ */
 
@@ -46,7 +52,7 @@ static struct pxafb_mode_info e400_pxafb_mode_info = {
 static struct pxafb_mach_info e400_pxafb_mach_info = {
        .modes          = &e400_pxafb_mode_info,
        .num_modes      = 1,
-       .lccr0          = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+       .lcd_conn       = LCD_COLOR_TFT_16BPP,
        .lccr3          = 0,
        .pxafb_backlight_power  = NULL,
 };
@@ -65,7 +71,10 @@ static unsigned long e400_pin_config[] __initdata = {
        GPIO42_BTUART_RXD,
        GPIO43_BTUART_TXD,
        GPIO44_BTUART_CTS,
-       GPIO45_GPIO, /* Used by TMIO for #SUSPEND */
+
+       /* TMIO controller */
+       GPIO19_GPIO, /* t7l66xb #PCLR */
+       GPIO45_GPIO, /* t7l66xb #SUSPEND (NOT BTUART!) */
 
        /* wakeup */
        GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,
@@ -73,10 +82,60 @@ static unsigned long e400_pin_config[] __initdata = {
 
 /* ---------------------------------------------------------------------- */
 
+static struct mtd_partition partition_a = {
+       .name = "Internal NAND flash",
+       .offset =  0,
+       .size =  MTDPART_SIZ_FULL,
+};
+
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+static struct nand_bbt_descr e400_t7l66xb_nand_bbt = {
+       .options = 0,
+       .offs = 4,
+       .len = 2,
+       .pattern = scan_ff_pattern
+};
+
+static struct tmio_nand_data e400_t7l66xb_nand_config = {
+       .num_partitions = 1,
+       .partition = &partition_a,
+       .badblock_pattern = &e400_t7l66xb_nand_bbt,
+};
+
+static struct t7l66xb_platform_data e400_t7l66xb_info = {
+       .irq_base               = IRQ_BOARD_START,
+       .enable                 = &eseries_tmio_enable,
+       .suspend                = &eseries_tmio_suspend,
+       .resume                 = &eseries_tmio_resume,
+
+       .nand_data              = &e400_t7l66xb_nand_config,
+};
+
+static struct platform_device e400_t7l66xb_device = {
+       .name           = "t7l66xb",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &e400_t7l66xb_info,
+       },
+       .num_resources = 2,
+       .resource      = eseries_tmio_resources,
+};
+
+/* ---------------------------------------------------------- */
+
+static struct platform_device *devices[] __initdata = {
+       &e400_t7l66xb_device,
+};
+
 static void __init e400_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e400_pin_config));
+       /* Fixme - e400 may have a switched clock */
+       eseries_register_clks();
+       eseries_get_tmio_gpios();
        set_pxa_fb_info(&e400_pxafb_mach_info);
+       platform_add_devices(devices, ARRAY_SIZE(devices));
        pxa_set_udc_info(&e7xx_udc_mach_info);
 }
 
index c57a15b37f0d0ed2c39dc0decbb57f1eeede05a5..b00d670b2ea6cb65039acf903b0da0e1a99fab72 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/fb.h>
+#include <linux/clk.h>
+#include <linux/mfd/t7l66xb.h>
 
 #include <video/w100fb.h>
 
 #include <asm/mach-types.h>
 
 #include <mach/mfp-pxa25x.h>
+#include <mach/pxa-regs.h>
 #include <mach/hardware.h>
+#include <mach/eseries-gpio.h>
 #include <mach/udc.h>
+#include <mach/irda.h>
 
 #include "generic.h"
 #include "eseries.h"
-
+#include "clock.h"
+#include "devices.h"
 
 /* ------------------------ e740 video support --------------------------- */
 
@@ -116,7 +122,17 @@ static unsigned long e740_pin_config[] __initdata = {
        GPIO42_BTUART_RXD,
        GPIO43_BTUART_TXD,
        GPIO44_BTUART_CTS,
-       GPIO45_GPIO, /* Used by TMIO for #SUSPEND */
+
+       /* TMIO controller */
+       GPIO19_GPIO, /* t7l66xb #PCLR */
+       GPIO45_GPIO, /* t7l66xb #SUSPEND (NOT BTUART!) */
+
+       /* UDC */
+       GPIO13_GPIO,
+       GPIO3_GPIO,
+
+       /* IrDA */
+       GPIO38_GPIO | MFP_LPM_DRIVE_HIGH,
 
        /* PC Card */
        GPIO8_GPIO,   /* CD0 */
@@ -142,17 +158,43 @@ static unsigned long e740_pin_config[] __initdata = {
        GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,
 };
 
+/* -------------------- e740 t7l66xb parameters -------------------- */
+
+static struct t7l66xb_platform_data e740_t7l66xb_info = {
+       .irq_base               = IRQ_BOARD_START,
+       .enable                 = &eseries_tmio_enable,
+       .suspend                = &eseries_tmio_suspend,
+       .resume                 = &eseries_tmio_resume,
+};
+
+static struct platform_device e740_t7l66xb_device = {
+       .name           = "t7l66xb",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &e740_t7l66xb_info,
+       },
+       .num_resources = 2,
+       .resource      = eseries_tmio_resources,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static struct platform_device *devices[] __initdata = {
        &e740_fb_device,
+       &e740_t7l66xb_device,
 };
 
 static void __init e740_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(e740_pin_config));
+       eseries_register_clks();
+       clk_add_alias("CLK_CK48M", &e740_t7l66xb_device.dev,
+                       "UDCCLK", &pxa25x_device_udc.dev),
+       eseries_get_tmio_gpios();
        platform_add_devices(devices, ARRAY_SIZE(devices));
        pxa_set_udc_info(&e7xx_udc_mach_info);
+       e7xx_irda_init();
+       pxa_set_ficp_info(&e7xx_ficp_platform_data);
 }
 
 MACHINE_START(E740, "Toshiba e740")
index 640e738b85df44b96d9b7493ad5b0c5ada1f98b5..84d7c1aac58d713658a2f2a8de2278e02ad5f86c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/fb.h>
+#include <linux/mfd/tc6393xb.h>
 
 #include <video/w100fb.h>
 
 #include <asm/mach-types.h>
 
 #include <mach/mfp-pxa25x.h>
+#include <mach/pxa-regs.h>
 #include <mach/hardware.h>
+#include <mach/eseries-gpio.h>
 #include <mach/udc.h>
+#include <mach/irda.h>
 
 #include "generic.h"
 #include "eseries.h"
+#include "clock.h"
 
 /* ---------------------- E750 LCD definitions -------------------- */
 
@@ -100,16 +105,45 @@ static struct platform_device e750_fb_device = {
        .resource       = e750_fb_resources,
 };
 
-/* ----------------------------------------------------------------------- */
+/* ----------------- e750 tc6393xb parameters ------------------ */
+
+static struct tc6393xb_platform_data e750_tc6393xb_info = {
+       .irq_base       = IRQ_BOARD_START,
+       .scr_pll2cr     = 0x0cc1,
+       .scr_gper       = 0,
+       .gpio_base      = -1,
+       .suspend        = &eseries_tmio_suspend,
+       .resume         = &eseries_tmio_resume,
+       .enable         = &eseries_tmio_enable,
+       .disable        = &eseries_tmio_disable,
+};
+
+static struct platform_device e750_tc6393xb_device = {
+       .name           = "tc6393xb",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &e750_tc6393xb_info,
+       },
+       .num_resources = 2,
+       .resource      = eseries_tmio_resources,
+};
+
+/* ------------------------------------------------------------- */
 
 static struct platform_device *devices[] __initdata = {
        &e750_fb_device,
+       &e750_tc6393xb_device,
 };
 
 static void __init e750_init(void)
 {
+       clk_add_alias("CLK_CK3P6MI", &e750_tc6393xb_device.dev,
+                       "GPIO11_CLK", NULL),
+       eseries_get_tmio_gpios();
        platform_add_devices(devices, ARRAY_SIZE(devices));
        pxa_set_udc_info(&e7xx_udc_mach_info);
+       e7xx_irda_init();
+       pxa_set_ficp_info(&e7xx_ficp_platform_data);
 }
 
 MACHINE_START(E750, "Toshiba e750")
index a293e09bfe2530f38dfc7c01090244e9a9f70534..9a86a426f92408093485ddb9917b7a3857a1b81d 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/fb.h>
+#include <linux/mfd/tc6393xb.h>
 
 #include <video/w100fb.h>
 
 #include <asm/mach-types.h>
 
 #include <mach/mfp-pxa25x.h>
+#include <mach/pxa-regs.h>
 #include <mach/hardware.h>
 #include <mach/eseries-gpio.h>
 #include <mach/udc.h>
 
 #include "generic.h"
 #include "eseries.h"
+#include "clock.h"
 
 /* ------------------------ e800 LCD definitions ------------------------- */
 
@@ -160,14 +163,41 @@ static struct pxa2xx_udc_mach_info e800_udc_mach_info = {
        .gpio_pullup_inverted = 1
 };
 
+/* ----------------- e800 tc6393xb parameters ------------------ */
+
+static struct tc6393xb_platform_data e800_tc6393xb_info = {
+       .irq_base       = IRQ_BOARD_START,
+       .scr_pll2cr     = 0x0cc1,
+       .scr_gper       = 0,
+       .gpio_base      = -1,
+       .suspend        = &eseries_tmio_suspend,
+       .resume         = &eseries_tmio_resume,
+       .enable         = &eseries_tmio_enable,
+       .disable        = &eseries_tmio_disable,
+};
+
+static struct platform_device e800_tc6393xb_device = {
+       .name           = "tc6393xb",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &e800_tc6393xb_info,
+       },
+       .num_resources = 2,
+       .resource      = eseries_tmio_resources,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static struct platform_device *devices[] __initdata = {
        &e800_fb_device,
+       &e800_tc6393xb_device,
 };
 
 static void __init e800_init(void)
 {
+       clk_add_alias("CLK_CK3P6MI", &e800_tc6393xb_device.dev,
+                       "GPIO11_CLK", NULL),
+       eseries_get_tmio_gpios();
        platform_add_devices(devices, ARRAY_SIZE(devices));
        pxa_set_udc_info(&e800_udc_mach_info);
 }
index d28849b50a142f7a9bce40994c92e050d50fd34c..dfce7d5b659e64a19ee22736c8a0cb38364b1196 100644 (file)
@@ -12,6 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
 
 #include <asm/setup.h>
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/eseries-gpio.h>
 #include <mach/udc.h>
+#include <mach/irda.h>
 
 #include "generic.h"
+#include "clock.h"
 
 /* Only e800 has 128MB RAM */
 void __init eseries_fixup(struct machine_desc *desc,
@@ -43,3 +48,122 @@ struct pxa2xx_udc_mach_info e7xx_udc_mach_info = {
        .gpio_pullup_inverted = 1
 };
 
+static void e7xx_irda_transceiver_mode(struct device *dev, int mode)
+{
+       if (mode & IR_OFF) {
+               gpio_set_value(GPIO_E7XX_IR_OFF, 1);
+               pxa2xx_transceiver_mode(dev, mode);
+       } else {
+               pxa2xx_transceiver_mode(dev, mode);
+               gpio_set_value(GPIO_E7XX_IR_OFF, 0);
+       }
+}
+
+int e7xx_irda_init(void)
+{
+       int ret;
+
+       ret = gpio_request(GPIO_E7XX_IR_OFF, "IrDA power");
+       if (ret)
+               goto out;
+
+       ret = gpio_direction_output(GPIO_E7XX_IR_OFF, 0);
+       if (ret)
+               goto out;
+
+       e7xx_irda_transceiver_mode(NULL, IR_SIRMODE | IR_OFF);
+out:
+       return ret;
+}
+
+static void e7xx_irda_shutdown(struct device *dev)
+{
+       e7xx_irda_transceiver_mode(dev, IR_SIRMODE | IR_OFF);
+       gpio_free(GPIO_E7XX_IR_OFF);
+}
+
+struct pxaficp_platform_data e7xx_ficp_platform_data = {
+       .transceiver_cap  = IR_SIRMODE | IR_OFF,
+       .transceiver_mode = e7xx_irda_transceiver_mode,
+       .shutdown = e7xx_irda_shutdown,
+};
+
+int eseries_tmio_enable(struct platform_device *dev)
+{
+       /* Reset - bring SUSPEND high before PCLR */
+       gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 0);
+       gpio_set_value(GPIO_ESERIES_TMIO_PCLR, 0);
+       msleep(1);
+       gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 1);
+       msleep(1);
+       gpio_set_value(GPIO_ESERIES_TMIO_PCLR, 1);
+       msleep(1);
+       return 0;
+}
+
+int eseries_tmio_disable(struct platform_device *dev)
+{
+       gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 0);
+       gpio_set_value(GPIO_ESERIES_TMIO_PCLR, 0);
+       return 0;
+}
+
+int eseries_tmio_suspend(struct platform_device *dev)
+{
+       gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 0);
+       return 0;
+}
+
+int eseries_tmio_resume(struct platform_device *dev)
+{
+       gpio_set_value(GPIO_ESERIES_TMIO_SUSPEND, 1);
+       msleep(1);
+       return 0;
+}
+
+void eseries_get_tmio_gpios(void)
+{
+       gpio_request(GPIO_ESERIES_TMIO_SUSPEND, NULL);
+       gpio_request(GPIO_ESERIES_TMIO_PCLR, NULL);
+       gpio_direction_output(GPIO_ESERIES_TMIO_SUSPEND, 0);
+       gpio_direction_output(GPIO_ESERIES_TMIO_PCLR, 0);
+}
+
+/* TMIO controller uses the same resources on all e-series machines. */
+struct resource eseries_tmio_resources[] = {
+       [0] = {
+               .start  = PXA_CS4_PHYS,
+               .end    = PXA_CS4_PHYS + 0x1fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_GPIO(GPIO_ESERIES_TMIO_IRQ),
+               .end    = IRQ_GPIO(GPIO_ESERIES_TMIO_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+/* Some e-series hardware cannot control the 32K clock */
+static void clk_32k_dummy(struct clk *clk)
+{
+}
+
+static const struct clkops clk_32k_dummy_ops = {
+       .enable         = clk_32k_dummy,
+       .disable        = clk_32k_dummy,
+};
+
+static struct clk tmio_dummy_clk = {
+       .ops    = &clk_32k_dummy_ops,
+       .rate   = 32768,
+};
+
+static struct clk_lookup eseries_clkregs[] = {
+       INIT_CLKREG(&tmio_dummy_clk, NULL, "CLK_CK32K"),
+};
+
+void eseries_register_clks(void)
+{
+       clks_register(eseries_clkregs, ARRAY_SIZE(eseries_clkregs));
+}
+
index a83f88d4b6ad813dfbcd569f1ad57edb7a2ace80..5930f5e2a1239edb02155e71501380416abf9067 100644 (file)
@@ -2,3 +2,15 @@ void __init eseries_fixup(struct machine_desc *desc,
        struct tag *tags, char **cmdline, struct meminfo *mi);
 
 extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info;
+extern struct pxaficp_platform_data e7xx_ficp_platform_data;
+extern int e7xx_irda_init(void);
+
+extern int eseries_tmio_enable(struct platform_device *dev);
+extern int eseries_tmio_disable(struct platform_device *dev);
+extern int eseries_tmio_suspend(struct platform_device *dev);
+extern int eseries_tmio_resume(struct platform_device *dev);
+extern void eseries_get_tmio_gpios(void);
+extern struct resource eseries_tmio_resources[];
+extern struct platform_device e300_tc6387xb_device;
+extern void eseries_register_clks(void);
+
index cc3d850cc0b6bc961cd42c6a46f09e476efdcaee..df5f822f3b6cd79cf351dafb861ae2b5aac5c032 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/pwm_backlight.h>
+#include <linux/input.h>
 
 #include <asm/setup.h>
 #include <mach/pxafb.h>
 #include <mach/ohci.h>
 #include <mach/i2c.h>
+#include <mach/hardware.h>
+#include <mach/pxa27x_keypad.h>
 
 #include <mach/mfp-pxa27x.h>
 #include <mach/pxa-regs.h>
@@ -101,120 +104,732 @@ static unsigned long ezx_pin_config[] __initdata = {
        GPIO44_BTUART_CTS,
        GPIO45_BTUART_RTS,
 
-       /* STUART */
-       GPIO46_STUART_RXD,
-       GPIO47_STUART_TXD,
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
 
-       /* For A780 support (connected with Neptune GSM chip) */
-       GPIO30_USB_P3_2,        /* ICL_TXENB */
-       GPIO31_USB_P3_6,        /* ICL_VPOUT */
-       GPIO90_USB_P3_5,        /* ICL_VPIN */
-       GPIO91_USB_P3_1,        /* ICL_XRXD */
-       GPIO56_USB_P3_4,        /* ICL_VMOUT */
-       GPIO113_USB_P3_3,       /* /ICL_VMIN */
+       /* PCAP SSP */
+       GPIO29_SSP1_SCLK,
+       GPIO25_SSP1_TXD,
+       GPIO26_SSP1_RXD,
+       GPIO24_GPIO,                            /* pcap chip select */
+       GPIO1_GPIO,                             /* pcap interrupt */
+       GPIO4_GPIO,                             /* WDI_AP */
+       GPIO55_GPIO,                            /* SYS_RESTART */
+
+       /* MMC */
+       GPIO32_MMC_CLK,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+       GPIO112_MMC_CMD,
+       GPIO11_GPIO,                            /* mmc detect */
+
+       /* usb to external transceiver */
+       GPIO34_USB_P2_2,
+       GPIO35_USB_P2_1,
+       GPIO36_USB_P2_4,
+       GPIO39_USB_P2_6,
+       GPIO40_USB_P2_5,
+       GPIO53_USB_P2_3,
+
+       /* usb to Neptune GSM chip */
+       GPIO30_USB_P3_2,
+       GPIO31_USB_P3_6,
+       GPIO90_USB_P3_5,
+       GPIO91_USB_P3_1,
+       GPIO56_USB_P3_4,
+       GPIO113_USB_P3_3,
+};
+
+#if defined(CONFIG_MACH_EZX_A780) || defined(CONFIG_MACH_EZX_E680)
+static unsigned long gen1_pin_config[] __initdata = {
+       /* flip / lockswitch */
+       GPIO12_GPIO,
+
+       /* bluetooth (bcm2035) */
+       GPIO14_GPIO | WAKEUP_ON_LEVEL_HIGH,     /* HOSTWAKE */
+       GPIO48_GPIO,                            /* RESET */
+       GPIO28_GPIO,                            /* WAKEUP */
+
+       /* Neptune handshake */
+       GPIO0_GPIO | WAKEUP_ON_LEVEL_HIGH,      /* BP_RDY */
+       GPIO57_GPIO,                            /* AP_RDY */
+       GPIO13_GPIO | WAKEUP_ON_LEVEL_HIGH,     /* WDI */
+       GPIO3_GPIO | WAKEUP_ON_LEVEL_HIGH,      /* WDI2 */
+       GPIO82_GPIO,                            /* RESET */
+       GPIO99_GPIO,                            /* TC_MM_EN */
+
+       /* sound */
+       GPIO52_SSP3_SCLK,
+       GPIO83_SSP3_SFRM,
+       GPIO81_SSP3_TXD,
+       GPIO89_SSP3_RXD,
+
+       /* ssp2 pins to in */
+       GPIO22_GPIO,                            /* SSP2_SCLK */
+       GPIO37_GPIO,                            /* SSP2_SFRM */
+       GPIO38_GPIO,                            /* SSP2_TXD */
+       GPIO88_GPIO,                            /* SSP2_RXD */
+
+       /* camera */
+       GPIO23_CIF_MCLK,
+       GPIO54_CIF_PCLK,
+       GPIO85_CIF_LV,
+       GPIO84_CIF_FV,
+       GPIO27_CIF_DD_0,
+       GPIO114_CIF_DD_1,
+       GPIO51_CIF_DD_2,
+       GPIO115_CIF_DD_3,
+       GPIO95_CIF_DD_4,
+       GPIO94_CIF_DD_5,
+       GPIO17_CIF_DD_6,
+       GPIO108_CIF_DD_7,
+       GPIO50_GPIO,                            /* CAM_EN */
+       GPIO19_GPIO,                            /* CAM_RST */
+
+       /* EMU */
+       GPIO120_GPIO,                           /* EMU_MUX1 */
+       GPIO119_GPIO,                           /* EMU_MUX2 */
+       GPIO86_GPIO,                            /* SNP_INT_CTL */
+       GPIO87_GPIO,                            /* SNP_INT_IN */
+};
+#endif
+
+#if defined(CONFIG_MACH_EZX_A1200) || defined(CONFIG_MACH_EZX_A910) || \
+       defined(CONFIG_MACH_EZX_E2) || defined(CONFIG_MACH_EZX_E6)
+static unsigned long gen2_pin_config[] __initdata = {
+       /* flip / lockswitch */
+       GPIO15_GPIO,
+
+       /* EOC */
+       GPIO10_GPIO,
+
+       /* bluetooth (bcm2045) */
+       GPIO13_GPIO | WAKEUP_ON_LEVEL_HIGH,     /* HOSTWAKE */
+       GPIO37_GPIO,                            /* RESET */
+       GPIO57_GPIO,                            /* WAKEUP */
+
+       /* Neptune handshake */
+       GPIO0_GPIO | WAKEUP_ON_LEVEL_HIGH,      /* BP_RDY */
+       GPIO96_GPIO,                            /* AP_RDY */
+       GPIO3_GPIO | WAKEUP_ON_LEVEL_HIGH,      /* WDI */
+       GPIO116_GPIO,                           /* RESET */
+       GPIO41_GPIO,                            /* BP_FLASH */
+
+       /* sound */
+       GPIO52_SSP3_SCLK,
+       GPIO83_SSP3_SFRM,
+       GPIO81_SSP3_TXD,
+       GPIO82_SSP3_RXD,
+
+       /* ssp2 pins to in */
+       GPIO22_GPIO,                            /* SSP2_SCLK */
+       GPIO14_GPIO,                            /* SSP2_SFRM */
+       GPIO38_GPIO,                            /* SSP2_TXD */
+       GPIO88_GPIO,                            /* SSP2_RXD */
+
+       /* camera */
+       GPIO23_CIF_MCLK,
+       GPIO54_CIF_PCLK,
+       GPIO85_CIF_LV,
+       GPIO84_CIF_FV,
+       GPIO27_CIF_DD_0,
+       GPIO114_CIF_DD_1,
+       GPIO51_CIF_DD_2,
+       GPIO115_CIF_DD_3,
+       GPIO95_CIF_DD_4,
+       GPIO48_CIF_DD_5,
+       GPIO93_CIF_DD_6,
+       GPIO12_CIF_DD_7,
+       GPIO50_GPIO,                            /* CAM_EN */
+       GPIO28_GPIO,                            /* CAM_RST */
+       GPIO17_GPIO,                            /* CAM_FLASH */
+};
+#endif
+
+#ifdef CONFIG_MACH_EZX_A780
+static unsigned long a780_pin_config[] __initdata = {
+       /* keypad */
+       GPIO93_KP_DKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO98_KP_MKIN_4 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO103_KP_MKOUT_0,
+       GPIO104_KP_MKOUT_1,
+       GPIO105_KP_MKOUT_2,
+       GPIO106_KP_MKOUT_3,
+       GPIO107_KP_MKOUT_4,
+
+       /* attenuate sound */
+       GPIO96_GPIO,
+};
+#endif
+
+#ifdef CONFIG_MACH_EZX_E680
+static unsigned long e680_pin_config[] __initdata = {
+       /* keypad */
+       GPIO93_KP_DKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO96_KP_DKIN_3 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO97_KP_DKIN_4 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO98_KP_DKIN_5 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO103_KP_MKOUT_0,
+       GPIO104_KP_MKOUT_1,
+       GPIO105_KP_MKOUT_2,
+       GPIO106_KP_MKOUT_3,
+
+       /* MIDI */
+       GPIO79_GPIO,                            /* VA_SEL_BUL */
+       GPIO80_GPIO,                            /* FLT_SEL_BUL */
+       GPIO78_GPIO,                            /* MIDI_RESET */
+       GPIO33_GPIO,                            /* MIDI_CS */
+       GPIO15_GPIO,                            /* MIDI_IRQ */
+       GPIO49_GPIO,                            /* MIDI_NPWE */
+       GPIO18_GPIO,                            /* MIDI_RDY */
+
+       /* leds */
+       GPIO46_GPIO,
+       GPIO47_GPIO,
+};
+#endif
+
+#ifdef CONFIG_MACH_EZX_A1200
+static unsigned long a1200_pin_config[] __initdata = {
+       /* keypad */
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO98_KP_MKIN_4 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO103_KP_MKOUT_0,
+       GPIO104_KP_MKOUT_1,
+       GPIO105_KP_MKOUT_2,
+       GPIO106_KP_MKOUT_3,
+       GPIO107_KP_MKOUT_4,
+       GPIO108_KP_MKOUT_5,
+};
+#endif
+
+#ifdef CONFIG_MACH_EZX_A910
+static unsigned long a910_pin_config[] __initdata = {
+       /* keypad */
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO98_KP_MKIN_4 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO103_KP_MKOUT_0,
+       GPIO104_KP_MKOUT_1,
+       GPIO105_KP_MKOUT_2,
+       GPIO106_KP_MKOUT_3,
+       GPIO107_KP_MKOUT_4,
+       GPIO108_KP_MKOUT_5,
+
+       /* WLAN */
+       GPIO89_GPIO,                            /* RESET */
+       GPIO33_GPIO,                            /* WAKEUP */
+       GPIO94_GPIO | WAKEUP_ON_LEVEL_HIGH,     /* HOSTWAKE */
+
+       /* MMC CS */
+       GPIO20_GPIO,
+};
+#endif
+
+#ifdef CONFIG_MACH_EZX_E2
+static unsigned long e2_pin_config[] __initdata = {
+       /* keypad */
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO98_KP_MKIN_4 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO103_KP_MKOUT_0,
+       GPIO104_KP_MKOUT_1,
+       GPIO105_KP_MKOUT_2,
+       GPIO106_KP_MKOUT_3,
+       GPIO107_KP_MKOUT_4,
+       GPIO108_KP_MKOUT_5,
 };
+#endif
+
+#ifdef CONFIG_MACH_EZX_E6
+static unsigned long e6_pin_config[] __initdata = {
+       /* keypad */
+       GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO97_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO98_KP_MKIN_4 | WAKEUP_ON_LEVEL_HIGH,
+       GPIO103_KP_MKOUT_0,
+       GPIO104_KP_MKOUT_1,
+       GPIO105_KP_MKOUT_2,
+       GPIO106_KP_MKOUT_3,
+       GPIO107_KP_MKOUT_4,
+       GPIO108_KP_MKOUT_5,
+};
+#endif
+
+/* KEYPAD */
+#ifdef CONFIG_MACH_EZX_A780
+static unsigned int a780_key_map[] = {
+       KEY(0, 0, KEY_SEND),
+       KEY(0, 1, KEY_BACK),
+       KEY(0, 2, KEY_END),
+       KEY(0, 3, KEY_PAGEUP),
+       KEY(0, 4, KEY_UP),
+
+       KEY(1, 0, KEY_NUMERIC_1),
+       KEY(1, 1, KEY_NUMERIC_2),
+       KEY(1, 2, KEY_NUMERIC_3),
+       KEY(1, 3, KEY_SELECT),
+       KEY(1, 4, KEY_KPENTER),
+
+       KEY(2, 0, KEY_NUMERIC_4),
+       KEY(2, 1, KEY_NUMERIC_5),
+       KEY(2, 2, KEY_NUMERIC_6),
+       KEY(2, 3, KEY_RECORD),
+       KEY(2, 4, KEY_LEFT),
+
+       KEY(3, 0, KEY_NUMERIC_7),
+       KEY(3, 1, KEY_NUMERIC_8),
+       KEY(3, 2, KEY_NUMERIC_9),
+       KEY(3, 3, KEY_HOME),
+       KEY(3, 4, KEY_RIGHT),
+
+       KEY(4, 0, KEY_NUMERIC_STAR),
+       KEY(4, 1, KEY_NUMERIC_0),
+       KEY(4, 2, KEY_NUMERIC_POUND),
+       KEY(4, 3, KEY_PAGEDOWN),
+       KEY(4, 4, KEY_DOWN),
+};
+
+static struct pxa27x_keypad_platform_data a780_keypad_platform_data = {
+       .matrix_key_rows = 5,
+       .matrix_key_cols = 5,
+       .matrix_key_map = a780_key_map,
+       .matrix_key_map_size = ARRAY_SIZE(a780_key_map),
+
+       .direct_key_map = { KEY_CAMERA },
+       .direct_key_num = 1,
+
+       .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_EZX_A780 */
+
+#ifdef CONFIG_MACH_EZX_E680
+static unsigned int e680_key_map[] = {
+       KEY(0, 0, KEY_UP),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_RESERVED),
+       KEY(0, 3, KEY_SEND),
+
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_LEFT),
+       KEY(1, 2, KEY_PAGEUP),
+       KEY(1, 3, KEY_PAGEDOWN),
+
+       KEY(2, 0, KEY_RESERVED),
+       KEY(2, 1, KEY_RESERVED),
+       KEY(2, 2, KEY_RESERVED),
+       KEY(2, 3, KEY_KPENTER),
+};
+
+static struct pxa27x_keypad_platform_data e680_keypad_platform_data = {
+       .matrix_key_rows = 3,
+       .matrix_key_cols = 4,
+       .matrix_key_map = e680_key_map,
+       .matrix_key_map_size = ARRAY_SIZE(e680_key_map),
+
+       .direct_key_map = {
+               KEY_CAMERA,
+               KEY_RESERVED,
+               KEY_RESERVED,
+               KEY_F1,
+               KEY_CANCEL,
+               KEY_F2,
+       },
+       .direct_key_num = 6,
+
+       .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_EZX_E680 */
+
+#ifdef CONFIG_MACH_EZX_A1200
+static unsigned int a1200_key_map[] = {
+       KEY(0, 0, KEY_RESERVED),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_PAGEDOWN),
+       KEY(0, 3, KEY_RESERVED),
+       KEY(0, 4, KEY_RESERVED),
+       KEY(0, 5, KEY_RESERVED),
+
+       KEY(1, 0, KEY_RESERVED),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_CAMERA),
+       KEY(1, 3, KEY_RESERVED),
+       KEY(1, 4, KEY_RESERVED),
+       KEY(1, 5, KEY_RESERVED),
+
+       KEY(2, 0, KEY_RESERVED),
+       KEY(2, 1, KEY_KPENTER),
+       KEY(2, 2, KEY_RECORD),
+       KEY(2, 3, KEY_RESERVED),
+       KEY(2, 4, KEY_RESERVED),
+       KEY(2, 5, KEY_SELECT),
+
+       KEY(3, 0, KEY_RESERVED),
+       KEY(3, 1, KEY_UP),
+       KEY(3, 2, KEY_SEND),
+       KEY(3, 3, KEY_RESERVED),
+       KEY(3, 4, KEY_RESERVED),
+       KEY(3, 5, KEY_RESERVED),
+
+       KEY(4, 0, KEY_RESERVED),
+       KEY(4, 1, KEY_LEFT),
+       KEY(4, 2, KEY_PAGEUP),
+       KEY(4, 3, KEY_RESERVED),
+       KEY(4, 4, KEY_RESERVED),
+       KEY(4, 5, KEY_RESERVED),
+};
+
+static struct pxa27x_keypad_platform_data a1200_keypad_platform_data = {
+       .matrix_key_rows = 5,
+       .matrix_key_cols = 6,
+       .matrix_key_map = a1200_key_map,
+       .matrix_key_map_size = ARRAY_SIZE(a1200_key_map),
+
+       .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_EZX_A1200 */
+
+#ifdef CONFIG_MACH_EZX_E6
+static unsigned int e6_key_map[] = {
+       KEY(0, 0, KEY_RESERVED),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_PAGEDOWN),
+       KEY(0, 3, KEY_RESERVED),
+       KEY(0, 4, KEY_RESERVED),
+       KEY(0, 5, KEY_NEXTSONG),
+
+       KEY(1, 0, KEY_RESERVED),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_PROG1),
+       KEY(1, 3, KEY_RESERVED),
+       KEY(1, 4, KEY_RESERVED),
+       KEY(1, 5, KEY_RESERVED),
+
+       KEY(2, 0, KEY_RESERVED),
+       KEY(2, 1, KEY_ENTER),
+       KEY(2, 2, KEY_CAMERA),
+       KEY(2, 3, KEY_RESERVED),
+       KEY(2, 4, KEY_RESERVED),
+       KEY(2, 5, KEY_WWW),
+
+       KEY(3, 0, KEY_RESERVED),
+       KEY(3, 1, KEY_UP),
+       KEY(3, 2, KEY_SEND),
+       KEY(3, 3, KEY_RESERVED),
+       KEY(3, 4, KEY_RESERVED),
+       KEY(3, 5, KEY_PLAYPAUSE),
+
+       KEY(4, 0, KEY_RESERVED),
+       KEY(4, 1, KEY_LEFT),
+       KEY(4, 2, KEY_PAGEUP),
+       KEY(4, 3, KEY_RESERVED),
+       KEY(4, 4, KEY_RESERVED),
+       KEY(4, 5, KEY_PREVIOUSSONG),
+};
+
+static struct pxa27x_keypad_platform_data e6_keypad_platform_data = {
+       .matrix_key_rows = 5,
+       .matrix_key_cols = 6,
+       .matrix_key_map = e6_key_map,
+       .matrix_key_map_size = ARRAY_SIZE(e6_key_map),
 
-static void __init ezx_init(void)
+       .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_EZX_E6 */
+
+#ifdef CONFIG_MACH_EZX_A910
+static unsigned int a910_key_map[] = {
+       KEY(0, 0, KEY_NUMERIC_6),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_PAGEDOWN),
+       KEY(0, 3, KEY_KPENTER),
+       KEY(0, 4, KEY_NUMERIC_5),
+       KEY(0, 5, KEY_CAMERA),
+
+       KEY(1, 0, KEY_NUMERIC_8),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_RESERVED),
+       KEY(1, 3, KEY_F1), /* Left SoftKey */
+       KEY(1, 4, KEY_NUMERIC_STAR),
+       KEY(1, 5, KEY_RESERVED),
+
+       KEY(2, 0, KEY_NUMERIC_7),
+       KEY(2, 1, KEY_NUMERIC_9),
+       KEY(2, 2, KEY_RECORD),
+       KEY(2, 3, KEY_F2), /* Right SoftKey */
+       KEY(2, 4, KEY_BACK),
+       KEY(2, 5, KEY_SELECT),
+
+       KEY(3, 0, KEY_NUMERIC_2),
+       KEY(3, 1, KEY_UP),
+       KEY(3, 2, KEY_SEND),
+       KEY(3, 3, KEY_NUMERIC_0),
+       KEY(3, 4, KEY_NUMERIC_1),
+       KEY(3, 5, KEY_RECORD),
+
+       KEY(4, 0, KEY_NUMERIC_4),
+       KEY(4, 1, KEY_LEFT),
+       KEY(4, 2, KEY_PAGEUP),
+       KEY(4, 3, KEY_NUMERIC_POUND),
+       KEY(4, 4, KEY_NUMERIC_3),
+       KEY(4, 5, KEY_RESERVED),
+};
+
+static struct pxa27x_keypad_platform_data a910_keypad_platform_data = {
+       .matrix_key_rows = 5,
+       .matrix_key_cols = 6,
+       .matrix_key_map = a910_key_map,
+       .matrix_key_map_size = ARRAY_SIZE(a910_key_map),
+
+       .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_EZX_A910 */
+
+#ifdef CONFIG_MACH_EZX_E2
+static unsigned int e2_key_map[] = {
+       KEY(0, 0, KEY_NUMERIC_6),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_NUMERIC_9),
+       KEY(0, 3, KEY_NEXTSONG),
+       KEY(0, 4, KEY_NUMERIC_5),
+       KEY(0, 5, KEY_F1), /* Left SoftKey */
+
+       KEY(1, 0, KEY_NUMERIC_8),
+       KEY(1, 1, KEY_DOWN),
+       KEY(1, 2, KEY_RESERVED),
+       KEY(1, 3, KEY_PAGEUP),
+       KEY(1, 4, KEY_NUMERIC_STAR),
+       KEY(1, 5, KEY_F2), /* Right SoftKey */
+
+       KEY(2, 0, KEY_NUMERIC_7),
+       KEY(2, 1, KEY_KPENTER),
+       KEY(2, 2, KEY_RECORD),
+       KEY(2, 3, KEY_PAGEDOWN),
+       KEY(2, 4, KEY_BACK),
+       KEY(2, 5, KEY_NUMERIC_0),
+
+       KEY(3, 0, KEY_NUMERIC_2),
+       KEY(3, 1, KEY_UP),
+       KEY(3, 2, KEY_SEND),
+       KEY(3, 3, KEY_PLAYPAUSE),
+       KEY(3, 4, KEY_NUMERIC_1),
+       KEY(3, 5, KEY_SOUND), /* Music SoftKey */
+
+       KEY(4, 0, KEY_NUMERIC_4),
+       KEY(4, 1, KEY_LEFT),
+       KEY(4, 2, KEY_NUMERIC_POUND),
+       KEY(4, 3, KEY_PREVIOUSSONG),
+       KEY(4, 4, KEY_NUMERIC_3),
+       KEY(4, 5, KEY_RESERVED),
+};
+
+static struct pxa27x_keypad_platform_data e2_keypad_platform_data = {
+       .matrix_key_rows = 5,
+       .matrix_key_cols = 6,
+       .matrix_key_map = e2_key_map,
+       .matrix_key_map_size = ARRAY_SIZE(e2_key_map),
+
+       .debounce_interval = 30,
+};
+#endif /* CONFIG_MACH_EZX_E2 */
+
+#ifdef CONFIG_MACH_EZX_A780
+static void __init a780_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(gen1_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(a780_pin_config));
+
        pxa_set_i2c_info(NULL);
-       if (machine_is_ezx_a780() || machine_is_ezx_e680())
-               set_pxa_fb_info(&ezx_fb_info_1);
-       else
-               set_pxa_fb_info(&ezx_fb_info_2);
 
-       platform_add_devices(devices, ARRAY_SIZE(devices));
-}
+       set_pxa_fb_info(&ezx_fb_info_1);
 
-static void __init ezx_fixup(struct machine_desc *desc, struct tag *tags,
-               char **cmdline, struct meminfo *mi)
-{
-       /* We have two ram chips. First one with 32MB at 0xA0000000 and a second
-        * 16MB one at 0xAC000000
-        */
-       mi->nr_banks = 2;
-       mi->bank[0].start = 0xa0000000;
-       mi->bank[0].node = 0;
-       mi->bank[0].size = (32*1024*1024);
-       mi->bank[1].start = 0xac000000;
-       mi->bank[1].node = 1;
-       mi->bank[1].size = (16*1024*1024);
+       pxa_set_keypad_info(&a780_keypad_platform_data);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
-#ifdef CONFIG_MACH_EZX_A780
 MACHINE_START(EZX_A780, "Motorola EZX A780")
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
-       .fixup                  = ezx_fixup,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
-       .init_machine   = &ezx_init,
+       .init_machine   = a780_init,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_E680
+static struct i2c_board_info __initdata e680_i2c_board_info[] = {
+       { I2C_BOARD_INFO("tea5767", 0x81) },
+};
+
+static void __init e680_init(void)
+{
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(gen1_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(e680_pin_config));
+
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(e680_i2c_board_info));
+
+       set_pxa_fb_info(&ezx_fb_info_1);
+
+       pxa_set_keypad_info(&e680_keypad_platform_data);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
 MACHINE_START(EZX_E680, "Motorola EZX E680")
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
-       .fixup                  = ezx_fixup,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
-       .init_machine   = &ezx_init,
+       .init_machine   = e680_init,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_A1200
+static struct i2c_board_info __initdata a1200_i2c_board_info[] = {
+       { I2C_BOARD_INFO("tea5767", 0x81) },
+};
+
+static void __init a1200_init(void)
+{
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(a1200_pin_config));
+
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(a1200_i2c_board_info));
+
+       set_pxa_fb_info(&ezx_fb_info_2);
+
+       pxa_set_keypad_info(&a1200_keypad_platform_data);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
 MACHINE_START(EZX_A1200, "Motorola EZX A1200")
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
-       .fixup                  = ezx_fixup,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
-       .init_machine   = &ezx_init,
+       .init_machine   = a1200_init,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_A910
+static void __init a910_init(void)
+{
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(a910_pin_config));
+
+       pxa_set_i2c_info(NULL);
+
+       set_pxa_fb_info(&ezx_fb_info_2);
+
+       pxa_set_keypad_info(&a910_keypad_platform_data);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
 MACHINE_START(EZX_A910, "Motorola EZX A910")
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
-       .fixup                  = ezx_fixup,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
-       .init_machine   = &ezx_init,
+       .init_machine   = a910_init,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_E6
+static struct i2c_board_info __initdata e6_i2c_board_info[] = {
+       { I2C_BOARD_INFO("tea5767", 0x81) },
+};
+
+static void __init e6_init(void)
+{
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(e6_pin_config));
+
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(e6_i2c_board_info));
+
+       set_pxa_fb_info(&ezx_fb_info_2);
+
+       pxa_set_keypad_info(&e6_keypad_platform_data);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
 MACHINE_START(EZX_E6, "Motorola EZX E6")
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
-       .fixup                  = ezx_fixup,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
-       .init_machine   = &ezx_init,
+       .init_machine   = e6_init,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_EZX_E2
+static struct i2c_board_info __initdata e2_i2c_board_info[] = {
+       { I2C_BOARD_INFO("tea5767", 0x81) },
+};
+
+static void __init e2_init(void)
+{
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(ezx_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(gen2_pin_config));
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(e2_pin_config));
+
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(e2_i2c_board_info));
+
+       set_pxa_fb_info(&ezx_fb_info_2);
+
+       pxa_set_keypad_info(&e2_keypad_platform_data);
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
 MACHINE_START(EZX_E2, "Motorola EZX E2")
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
-       .fixup                  = ezx_fixup,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
-       .init_machine   = &ezx_init,
+       .init_machine   = e2_init,
 MACHINE_END
 #endif
index 85ed0b33331f93ec3887cb47d076a148f61037c7..0ccc91c92c44e54722384cf0322afd53147c9ecd 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/mach/map.h>
+#include <asm/mach-types.h>
 
 #include <mach/pxa-regs.h>
 #include <mach/reset.h>
@@ -39,6 +40,21 @@ void clear_reset_status(unsigned int mask)
                pxa3xx_clear_reset_status(mask);
 }
 
+unsigned long get_clock_tick_rate(void)
+{
+       unsigned long clock_tick_rate;
+
+       if (cpu_is_pxa25x())
+               clock_tick_rate = 3686400;
+       else if (machine_is_mainstone())
+               clock_tick_rate = 3249600;
+       else
+               clock_tick_rate = 3250000;
+
+       return clock_tick_rate;
+}
+EXPORT_SYMBOL(get_clock_tick_rate);
+
 /*
  * Get the clock frequency as reflected by CCCR and the turbo flag.
  * We assume these values have been applied via a fcs.
index 14930cf8be7b58d27d523310c02a7e6fe65f3ed4..5fec1e479cb30e5f757ec08364bf7dc345bae06c 100644 (file)
 
 #include "generic.h"
 
+#define GPIO0_BASE     ((void __iomem *)io_p2v(0x40E00000))
+#define GPIO1_BASE     ((void __iomem *)io_p2v(0x40E00004))
+#define GPIO2_BASE     ((void __iomem *)io_p2v(0x40E00008))
+#define GPIO3_BASE     ((void __iomem *)io_p2v(0x40E00100))
+
+#define GPLR_OFFSET    0x00
+#define GPDR_OFFSET    0x0C
+#define GPSR_OFFSET    0x18
+#define GPCR_OFFSET    0x24
+#define GRER_OFFSET    0x30
+#define GFER_OFFSET    0x3C
+#define GEDR_OFFSET    0x48
 
 struct pxa_gpio_chip {
        struct gpio_chip chip;
@@ -33,6 +45,18 @@ struct pxa_gpio_chip {
 
 int pxa_last_gpio;
 
+#ifdef CONFIG_CPU_PXA26x
+/* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
+ * as well as their Alternate Function value being '1' for GPIO in GAFRx.
+ */
+static int __gpio_is_inverted(unsigned gpio)
+{
+       return cpu_is_pxa25x() && gpio > 85;
+}
+#else
+#define __gpio_is_inverted(gpio)       (0)
+#endif
+
 /*
  * Configure pins for GPIO or other functions
  */
@@ -75,7 +99,10 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
        gpdr = pxa->regbase + GPDR_OFFSET;
        local_irq_save(flags);
        value = __raw_readl(gpdr);
-       value &= ~mask;
+       if (__gpio_is_inverted(chip->base + offset))
+               value |= mask;
+       else
+               value &= ~mask;
        __raw_writel(value, gpdr);
        local_irq_restore(flags);
 
@@ -97,7 +124,10 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
        gpdr = pxa->regbase + GPDR_OFFSET;
        local_irq_save(flags);
        tmp = __raw_readl(gpdr);
-       tmp |= mask;
+       if (__gpio_is_inverted(chip->base + offset))
+               tmp &= ~mask;
+       else
+               tmp |= mask;
        __raw_writel(tmp, gpdr);
        local_irq_restore(flags);
 
@@ -173,10 +203,17 @@ static unsigned long GPIO_IRQ_mask[4];
  */
 static int __gpio_is_occupied(unsigned gpio)
 {
-       if (cpu_is_pxa25x() || cpu_is_pxa27x())
-               return GAFR(gpio) & (0x3 << (((gpio) & 0xf) * 2));
-       else
-               return 0;
+       if (cpu_is_pxa27x() || cpu_is_pxa25x()) {
+               int af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
+               int dir = GPDR(gpio) & GPIO_bit(gpio);
+
+               if (__gpio_is_inverted(gpio))
+                       return af != 1 || dir == 0;
+               else
+                       return af != 0 || dir != 0;
+       }
+
+       return 0;
 }
 
 static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
@@ -190,9 +227,8 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
                /* Don't mess with enabled GPIOs using preconfigured edges or
                 * GPIOs set to alternate function or to output during probe
                 */
-               if ((GPIO_IRQ_rising_edge[idx] |
-                    GPIO_IRQ_falling_edge[idx] |
-                    GPDR(gpio)) & GPIO_bit(gpio))
+               if ((GPIO_IRQ_rising_edge[idx] & GPIO_bit(gpio)) ||
+                   (GPIO_IRQ_falling_edge[idx] & GPIO_bit(gpio)))
                        return 0;
 
                if (__gpio_is_occupied(gpio))
@@ -201,7 +237,10 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
                type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
        }
 
-       GPDR(gpio) &= ~GPIO_bit(gpio);
+       if (__gpio_is_inverted(gpio))
+               GPDR(gpio) |= GPIO_bit(gpio);
+       else
+               GPDR(gpio) &= ~GPIO_bit(gpio);
 
        if (type & IRQ_TYPE_EDGE_RISING)
                __set_bit(gpio, GPIO_IRQ_rising_edge);
index d8962a0fb98d98d4a113db16b5f2e7ef41fc4537..e296ce11658c48633aae5c696fbcaab1355e9ec2 100644 (file)
@@ -184,15 +184,22 @@ static unsigned long gumstix_pin_config[] __initdata = {
        GPIO6_MMC_CLK,
        GPIO53_MMC_CLK,
        GPIO8_MMC_CS0,
-       /* these are used by AM200EPD */
-       GPIO51_GPIO,
-       GPIO49_GPIO,
-       GPIO48_GPIO,
-       GPIO32_GPIO,
-       GPIO17_GPIO,
-       GPIO16_GPIO,
 };
 
+int __attribute__((weak)) am200_init(void)
+{
+       return 0;
+}
+
+static void __init carrier_board_init(void)
+{
+       /*
+        * put carrier/expansion board init here if
+        * they cannot be detected programatically
+        */
+       am200_init();
+}
+
 static void __init gumstix_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(gumstix_pin_config));
@@ -201,6 +208,7 @@ static void __init gumstix_init(void)
        gumstix_udc_init();
        gumstix_mmc_init();
        (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+       carrier_board_init();
 }
 
 MACHINE_START(GUMSTIX, "Gumstix")
diff --git a/arch/arm/mach-pxa/h5000.c b/arch/arm/mach-pxa/h5000.c
new file mode 100644 (file)
index 0000000..da6e442
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Hardware definitions for HP iPAQ h5xxx Handheld Computers
+ *
+ * Copyright 2000-2003  Hewlett-Packard Company.
+ * Copyright 2002       Jamey Hicks <jamey.hicks@hp.com>
+ * Copyright 2004-2005  Phil Blundell <pb@handhelds.org>
+ * Copyright 2007-2008  Anton Vorontsov <cbouatmailru@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.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Jamey Hicks.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/h5000.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-regs.h>
+#include <mach/mfp-pxa25x.h>
+#include <mach/udc.h>
+#include "generic.h"
+
+/*
+ * Flash
+ */
+
+static struct mtd_partition h5000_flash0_partitions[] = {
+       {
+               .name = "bootldr",
+               .size = 0x00040000,
+               .offset = 0,
+               .mask_flags = MTD_WRITEABLE,
+       },
+       {
+               .name = "root",
+               .size = MTDPART_SIZ_FULL,
+               .offset = MTDPART_OFS_APPEND,
+       },
+};
+
+static struct mtd_partition h5000_flash1_partitions[] = {
+       {
+               .name = "second root",
+               .size = SZ_16M - 0x00040000,
+               .offset = 0,
+       },
+       {
+               .name = "asset",
+               .size = MTDPART_SIZ_FULL,
+               .offset = MTDPART_OFS_APPEND,
+               .mask_flags = MTD_WRITEABLE,
+       },
+};
+
+static struct physmap_flash_data h5000_flash0_data = {
+       .width = 4,
+       .parts = h5000_flash0_partitions,
+       .nr_parts = ARRAY_SIZE(h5000_flash0_partitions),
+};
+
+static struct physmap_flash_data h5000_flash1_data = {
+       .width = 4,
+       .parts = h5000_flash1_partitions,
+       .nr_parts = ARRAY_SIZE(h5000_flash1_partitions),
+};
+
+static struct resource h5000_flash0_resources = {
+       .start = PXA_CS0_PHYS,
+       .end = PXA_CS0_PHYS + SZ_32M - 1,
+       .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
+};
+
+static struct resource h5000_flash1_resources = {
+       .start = PXA_CS0_PHYS + SZ_32M,
+       .end = PXA_CS0_PHYS + SZ_32M + SZ_16M - 1,
+       .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
+};
+
+static struct platform_device h5000_flash[] = {
+       {
+               .name = "physmap-flash",
+               .id = 0,
+               .resource = &h5000_flash0_resources,
+               .num_resources = 1,
+               .dev = {
+                       .platform_data = &h5000_flash0_data,
+               },
+       },
+       {
+               .name = "physmap-flash",
+               .id = 1,
+               .resource = &h5000_flash1_resources,
+               .num_resources = 1,
+               .dev = {
+                       .platform_data = &h5000_flash1_data,
+               },
+       },
+};
+
+/*
+ * USB Device Controller
+ */
+
+static struct pxa2xx_udc_mach_info h5000_udc_mach_info __initdata = {
+       .gpio_pullup = H5000_GPIO_USB_PULLUP,
+};
+
+/*
+ * GPIO setup
+ */
+
+static unsigned long h5000_pin_config[] __initdata = {
+       /* Crystal and Clock Signals */
+       GPIO12_32KHz,
+
+       /* SDRAM and Static Memory I/O Signals */
+       GPIO15_nCS_1,
+       GPIO78_nCS_2,
+       GPIO79_nCS_3,
+       GPIO80_nCS_4,
+
+       /* FFUART */
+       GPIO34_FFUART_RXD,
+       GPIO35_FFUART_CTS,
+       GPIO36_FFUART_DCD,
+       GPIO37_FFUART_DSR,
+       GPIO38_FFUART_RI,
+       GPIO39_FFUART_TXD,
+       GPIO40_FFUART_DTR,
+       GPIO41_FFUART_RTS,
+
+       /* BTUART */
+       GPIO42_BTUART_RXD,
+       GPIO43_BTUART_TXD,
+       GPIO44_BTUART_CTS,
+       GPIO45_BTUART_RTS,
+
+       /* SSP1 */
+       GPIO23_SSP1_SCLK,
+       GPIO25_SSP1_TXD,
+       GPIO26_SSP1_RXD,
+};
+
+/*
+ * Localbus setup:
+ * CS0: Flash;
+ * CS1: MediaQ chip, select 16-bit bus and vlio;
+ * CS5: SAMCOP.
+ */
+
+static void fix_msc(void)
+{
+       MSC0 = 0x129c24f2;
+       MSC1 = 0x7ff424fa;
+       MSC2 = 0x7ff47ff4;
+
+       MDREFR |= 0x02080000;
+}
+
+/*
+ * Platform devices
+ */
+
+static struct platform_device *devices[] __initdata = {
+       &h5000_flash[0],
+       &h5000_flash[1],
+};
+
+static void __init h5000_init(void)
+{
+       fix_msc();
+
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(h5000_pin_config));
+       pxa_set_udc_info(&h5000_udc_mach_info);
+       platform_add_devices(ARRAY_AND_SIZE(devices));
+}
+
+MACHINE_START(H5400, "HP iPAQ H5000")
+       .phys_io = 0x40000000,
+       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .boot_params = 0xa0000100,
+       .map_io = pxa_map_io,
+       .init_irq = pxa25x_init_irq,
+       .timer = &pxa_timer,
+       .init_machine = h5000_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/imote2.c b/arch/arm/mach-pxa/imote2.c
new file mode 100644 (file)
index 0000000..364c5e2
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * linux/arch/arm/mach-pxa/imote2.c
+ *
+ * Author:     Ed C. Epp
+ * Created:    Nov 05, 2002
+ * Copyright:  Intel Corp.
+ *
+ * Modified 2008:  Jonathan Cameron
+ *
+ * The Imote2 is a wireless sensor node platform sold
+ * by Crossbow (www.xbow.com).
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/mfd/da903x.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/i2c.h>
+#include <mach/pxa-regs.h>
+#include <mach/pxa2xx-regs.h>
+#include <mach/mfp-pxa27x.h>
+#include <mach/regs-ssp.h>
+#include <mach/udc.h>
+#include <mach/mmc.h>
+#include <mach/pxa2xx_spi.h>
+#include <mach/pxa27x-udc.h>
+
+#include "devices.h"
+#include "generic.h"
+
+static unsigned long imote2_pin_config[] __initdata = {
+
+       /* Device Identification for wakeup*/
+       GPIO102_GPIO,
+
+       /* Button */
+       GPIO91_GPIO,
+
+       /* DA9030 */
+       GPIO1_GPIO,
+
+       /* MMC */
+       GPIO32_MMC_CLK,
+       GPIO112_MMC_CMD,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+
+       /* 802.15.4 radio - driver out of mainline */
+       GPIO22_GPIO,                    /* CC_RSTN */
+       GPIO114_GPIO,                   /* CC_FIFO */
+       GPIO116_GPIO,                   /* CC_CCA */
+       GPIO0_GPIO,                     /* CC_FIFOP */
+       GPIO16_GPIO,                    /* CCSFD */
+       GPIO39_GPIO,                    /* CSn */
+       GPIO115_GPIO,                   /* Power enable */
+
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
+
+       /* SSP 3 - 802.15.4 radio */
+       GPIO39_GPIO,                    /* Chip Select */
+       GPIO34_SSP3_SCLK,
+       GPIO35_SSP3_TXD,
+       GPIO41_SSP3_RXD,
+
+       /* SSP 2 - to daughter boards */
+       GPIO37_GPIO,                    /* Chip Select */
+       GPIO36_SSP2_SCLK,
+       GPIO38_SSP2_TXD,
+       GPIO11_SSP2_RXD,
+
+       /* SSP 1 - to daughter boards */
+       GPIO24_GPIO,                    /* Chip Select */
+       GPIO23_SSP1_SCLK,
+       GPIO25_SSP1_TXD,
+       GPIO26_SSP1_RXD,
+
+       /* BTUART Basic Connector*/
+       GPIO42_BTUART_RXD,
+       GPIO43_BTUART_TXD,
+       GPIO44_BTUART_CTS,
+       GPIO45_BTUART_RTS,
+
+       /* STUART Serial console via debug board*/
+       GPIO46_STUART_RXD,
+       GPIO47_STUART_TXD,
+
+       /* Basic sensor board */
+       GPIO96_GPIO,    /* accelerometer interrupt */
+       GPIO99_GPIO,    /* ADC interrupt */
+
+       /* Connector pins specified as gpios */
+       GPIO94_GPIO, /* large basic connector pin 14 */
+       GPIO10_GPIO, /* large basic connector pin 23 */
+
+       /* LEDS */
+       GPIO103_GPIO, /* red led */
+       GPIO104_GPIO, /* green led */
+       GPIO105_GPIO, /* blue led */
+};
+
+static struct gpio_led imote2_led_pins[] = {
+       {
+               .name       =  "imote2:red",
+               .gpio       = 103,
+               .active_low = 1,
+       }, {
+               .name       = "imote2:green",
+               .gpio       = 104,
+               .active_low = 1,
+       }, {
+               .name       = "imote2:blue",
+               .gpio       = 105,
+               .active_low = 1,
+       },
+};
+
+static struct gpio_led_platform_data imote2_led_data = {
+       .num_leds = ARRAY_SIZE(imote2_led_pins),
+       .leds     = imote2_led_pins,
+};
+
+static struct platform_device imote2_leds = {
+       .name = "leds-gpio",
+       .id   = -1,
+       .dev = {
+               .platform_data = &imote2_led_data,
+       },
+};
+
+/* Reverse engineered partly from Platformx drivers */
+enum imote2_ldos{
+       vcc_vref,
+       vcc_cc2420,
+       vcc_mica,
+       vcc_bt,
+       /* The two voltages available to sensor boards */
+       vcc_sensor_1_8,
+       vcc_sensor_3,
+
+       vcc_sram_ext, /* directly connected to the pxa271 */
+       vcc_pxa_pll,
+       vcc_pxa_usim, /* Reference voltage for certain gpios */
+       vcc_pxa_mem,
+       vcc_pxa_flash,
+       vcc_pxa_core, /*Dc-Dc buck not yet supported */
+       vcc_lcd,
+       vcc_bb,
+       vcc_bbio,
+       vcc_io, /* cc2420 802.15.4 radio and pxa vcc_io ?*/
+};
+
+/* The values of the various regulator constraints are obviously dependent
+ * on exactly what is wired to each ldo.  Unfortunately this information is
+ * not generally available.  More information has been requested from Xbow
+ * but as of yet they haven't been forthcoming.
+ *
+ * Some of these are clearly Stargate 2 related (no way of plugging
+ * in an lcd on the IM2 for example!).
+ */
+static struct regulator_init_data imote2_ldo_init_data[] = {
+       [vcc_bbio] = {
+               .constraints = { /* board default 1.8V */
+                       .name = "vcc_bbio",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_bb] = {
+               .constraints = { /* board default 2.8V */
+                       .name = "vcc_bb",
+                       .min_uV = 2700000,
+                       .max_uV = 3000000,
+               },
+       },
+       [vcc_pxa_flash] = {
+               .constraints = {/* default is 1.8V */
+                       .name = "vcc_pxa_flash",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_cc2420] = { /* also vcc_io */
+               .constraints = {
+                       /* board default is 2.8V */
+                       .name = "vcc_cc2420",
+                       .min_uV = 2700000,
+                       .max_uV = 3300000,
+               },
+       },
+       [vcc_vref] = { /* Reference for what? */
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_vref",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_sram_ext] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_sram_ext",
+                       .min_uV = 2800000,
+                       .max_uV = 2800000,
+               },
+       },
+       [vcc_mica] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_mica",
+                       .min_uV = 2800000,
+                       .max_uV = 2800000,
+               },
+       },
+       [vcc_bt] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_bt",
+                       .min_uV = 2800000,
+                       .max_uV = 2800000,
+               },
+       },
+       [vcc_lcd] = {
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_lcd",
+                       .min_uV = 2700000,
+                       .max_uV = 3300000,
+               },
+       },
+       [vcc_io] = { /* Same or higher than everything
+                         * bar vccbat and vccusb */
+               .constraints = { /* default 2.8V */
+                       .name = "vcc_io",
+                       .min_uV = 2692000,
+                       .max_uV = 3300000,
+               },
+       },
+       [vcc_sensor_1_8] = {
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_sensor_1_8",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+       [vcc_sensor_3] = { /* curiously default 2.8V */
+               .constraints = {
+                       .name = "vcc_sensor_3",
+                       .min_uV = 2800000,
+                       .max_uV = 3000000,
+               },
+       },
+       [vcc_pxa_pll] = { /* 1.17V - 1.43V, default 1.3V*/
+               .constraints = {
+                       .name = "vcc_pxa_pll",
+                       .min_uV = 1170000,
+                       .max_uV = 1430000,
+               },
+       },
+       [vcc_pxa_usim] = {
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_pxa_usim",
+                       .min_uV = 1710000,
+                       .max_uV = 2160000,
+               },
+       },
+       [vcc_pxa_mem] = {
+               .constraints = { /* default 1.8V */
+                       .name = "vcc_pxa_mem",
+                       .min_uV = 1800000,
+                       .max_uV = 1800000,
+               },
+       },
+};
+
+static struct da903x_subdev_info imote2_da9030_subdevs[] = {
+       {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO2,
+               .platform_data = &imote2_ldo_init_data[vcc_bbio],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO3,
+               .platform_data = &imote2_ldo_init_data[vcc_bb],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO4,
+               .platform_data = &imote2_ldo_init_data[vcc_pxa_flash],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO5,
+               .platform_data = &imote2_ldo_init_data[vcc_cc2420],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO6,
+               .platform_data = &imote2_ldo_init_data[vcc_vref],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO7,
+               .platform_data = &imote2_ldo_init_data[vcc_sram_ext],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO8,
+               .platform_data = &imote2_ldo_init_data[vcc_mica],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO9,
+               .platform_data = &imote2_ldo_init_data[vcc_bt],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO10,
+               .platform_data = &imote2_ldo_init_data[vcc_sensor_1_8],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO11,
+               .platform_data = &imote2_ldo_init_data[vcc_sensor_3],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO12,
+               .platform_data = &imote2_ldo_init_data[vcc_lcd],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO15,
+               .platform_data = &imote2_ldo_init_data[vcc_pxa_pll],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO17,
+               .platform_data = &imote2_ldo_init_data[vcc_pxa_usim],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO18,
+               .platform_data = &imote2_ldo_init_data[vcc_io],
+       }, {
+               .name = "da903x-regulator",
+               .id = DA9030_ID_LDO19,
+               .platform_data = &imote2_ldo_init_data[vcc_pxa_mem],
+       },
+};
+
+static struct da903x_platform_data imote2_da9030_pdata = {
+       .num_subdevs = ARRAY_SIZE(imote2_da9030_subdevs),
+       .subdevs = imote2_da9030_subdevs,
+};
+
+/* As the the imote2 doesn't currently have a conventional SD slot
+ * there is no option to hotplug cards, making all this rather simple
+ */
+static int imote2_mci_get_ro(struct device *dev)
+{
+       return 0;
+}
+
+/* Rather simple case as hotplugging not possible */
+static struct pxamci_platform_data imote2_mci_platform_data = {
+       .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* default anyway */
+       .get_ro = imote2_mci_get_ro,
+};
+
+static struct mtd_partition imote2flash_partitions[] = {
+       {
+               .name = "Bootloader",
+               .size = 0x00040000,
+               .offset = 0,
+               .mask_flags = MTD_WRITEABLE,
+       }, {
+               .name = "Kernel",
+               .size = 0x00200000,
+               .offset = 0x00040000,
+               .mask_flags = 0,
+       }, {
+               .name = "Filesystem",
+               .size = 0x01DC0000,
+               .offset = 0x00240000,
+               .mask_flags = 0,
+       },
+};
+
+static struct resource flash_resources = {
+       .start = PXA_CS0_PHYS,
+       .end = PXA_CS0_PHYS + SZ_32M - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct flash_platform_data imote2_flash_data = {
+       .map_name = "cfi_probe",
+       .parts = imote2flash_partitions,
+       .nr_parts = ARRAY_SIZE(imote2flash_partitions),
+       .name = "PXA27xOnChipROM",
+       .width = 2,
+};
+
+static struct platform_device imote2_flash_device = {
+       .name = "pxa2xx-flash",
+       .id = 0,
+       .dev = {
+               .platform_data = &imote2_flash_data,
+       },
+       .resource = &flash_resources,
+       .num_resources = 1,
+};
+
+/* Some of the drivers here are out of kernel at the moment (parts of IIO)
+ * and it may be a while before they are in the mainline.
+ */
+static struct i2c_board_info __initdata imote2_i2c_board_info[] = {
+       { /* UCAM sensor board */
+               .type = "max1238",
+               .addr = 0x35,
+       }, { /* ITS400 Sensor board only */
+               .type = "max1363",
+               .addr = 0x34,
+               /* Through a nand gate - Also beware, on V2 sensor board the
+                * pull up resistors are missing.
+                */
+               .irq = IRQ_GPIO(99),
+       }, { /* ITS400 Sensor board only */
+               .type = "tsl2561",
+               .addr = 0x49,
+               /* Through a nand gate - Also beware, on V2 sensor board the
+                * pull up resistors are missing.
+                */
+               .irq = IRQ_GPIO(99),
+       }, { /* ITS400 Sensor board only */
+               .type = "tmp175",
+               .addr = 0x4A,
+               .irq = IRQ_GPIO(96),
+       },
+};
+
+static struct i2c_board_info __initdata imote2_pwr_i2c_board_info[] = {
+       {
+               .type = "da9030",
+               .addr = 0x49,
+               .platform_data = &imote2_da9030_pdata,
+               .irq = gpio_to_irq(1),
+       },
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_0_info = {
+       .num_chipselect = 1,
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_1_info = {
+       .num_chipselect = 1,
+};
+
+static struct pxa2xx_spi_master pxa_ssp_master_2_info = {
+       .num_chipselect = 1,
+};
+
+/* Patch posted by Eric Miao <eric.miao@marvell.com> will remove
+ * the need for these functions.
+ */
+static void spi1control(u32 command)
+{
+       gpio_set_value(24, command & PXA2XX_CS_ASSERT ? 0 : 1);
+};
+
+static void spi3control(u32 command)
+{
+       gpio_set_value(39, command & PXA2XX_CS_ASSERT ? 0 : 1);
+};
+
+static struct pxa2xx_spi_chip staccel_chip_info = {
+       .tx_threshold = 8,
+       .rx_threshold = 8,
+       .dma_burst_size = 8,
+       .timeout = 235,
+       .cs_control = spi1control,
+};
+
+static struct pxa2xx_spi_chip cc2420_info = {
+       .tx_threshold = 8,
+       .rx_threshold = 8,
+       .dma_burst_size = 8,
+       .timeout = 235,
+       .cs_control = spi3control,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+       { /* Driver in IIO */
+               .modalias = "lis3l02dq",
+               .max_speed_hz = 8000000,/* 8MHz max spi frequency at 3V */
+               .bus_num = 1,
+               .chip_select = 0,
+               .controller_data = &staccel_chip_info,
+               .irq = IRQ_GPIO(96),
+       }, { /* Driver out of kernel as it needs considerable rewriting */
+               .modalias = "cc2420",
+               .max_speed_hz = 6500000,
+               .bus_num = 3,
+               .chip_select = 0,
+               .controller_data = &cc2420_info,
+       },
+};
+
+static void im2_udc_command(int cmd)
+{
+       switch (cmd) {
+       case PXA2XX_UDC_CMD_CONNECT:
+               UP2OCR |=  UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE;
+               break;
+       case PXA2XX_UDC_CMD_DISCONNECT:
+               UP2OCR &= ~(UP2OCR_HXOE | UP2OCR_DPPUE | UP2OCR_DPPUBE);
+               break;
+       }
+}
+
+static struct pxa2xx_udc_mach_info imote2_udc_info __initdata = {
+       .udc_command            = im2_udc_command,
+};
+
+static struct platform_device *imote2_devices[] = {
+       &imote2_flash_device,
+       &imote2_leds,
+};
+
+static struct i2c_pxa_platform_data i2c_pwr_pdata = {
+       .fast_mode = 1,
+};
+
+static struct i2c_pxa_platform_data i2c_pdata = {
+       .fast_mode = 1,
+};
+
+static void __init imote2_init(void)
+{
+
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(imote2_pin_config));
+       /* SPI chip select directions - all other directions should
+        * be handled by drivers.*/
+       gpio_direction_output(37, 0);
+       gpio_direction_output(24, 0);
+       gpio_direction_output(39, 0);
+
+       platform_add_devices(imote2_devices, ARRAY_SIZE(imote2_devices));
+
+       pxa2xx_set_spi_info(1, &pxa_ssp_master_0_info);
+       pxa2xx_set_spi_info(2, &pxa_ssp_master_1_info);
+       pxa2xx_set_spi_info(3, &pxa_ssp_master_2_info);
+
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+       i2c_register_board_info(0, imote2_i2c_board_info,
+                               ARRAY_SIZE(imote2_i2c_board_info));
+       i2c_register_board_info(1, imote2_pwr_i2c_board_info,
+                               ARRAY_SIZE(imote2_pwr_i2c_board_info));
+
+       pxa27x_set_i2c_power_info(&i2c_pwr_pdata);
+       pxa_set_i2c_info(&i2c_pdata);
+
+       pxa_set_mci_info(&imote2_mci_platform_data);
+       pxa_set_udc_info(&imote2_udc_info);
+}
+
+MACHINE_START(INTELMOTE2, "IMOTE 2")
+       .phys_io        = 0x40000000,
+       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
+       .map_io         = pxa_map_io,
+       .init_irq       = pxa27x_init_irq,
+       .timer          = &pxa_timer,
+       .init_machine   = imote2_init,
+       .boot_params    = 0xA0000100,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/include/mach/clkdev.h b/arch/arm/mach-pxa/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
index 955bfe60606754e598856afb3eb792760371b0f7..7804637a6df3de4c32b435b865cec0721dc0e431 100644 (file)
@@ -30,10 +30,6 @@ typedef enum {
        DMA_PRIO_LOW = 2
 } pxa_dma_prio;
 
-#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
-#define HAVE_ARCH_PCI_SET_DMA_MASK     1
-#endif
-
 /*
  * DMA registration
  */
index 4c90b131027043225721531965dbed74805b5965..efbd2aa9ecec394e7cf98270dfd38a0df993ad26 100644 (file)
 #define GPIO_E800_PCMCIA_PWR1    73
 
 /* e7xx IrDA power control */
-#define GPIO_E7XX_IR_O         38
+#define GPIO_E7XX_IR_OFF         38
 
 /* ASIC related GPIOs */
 #define GPIO_ESERIES_TMIO_IRQ        5
+#define GPIO_ESERIES_TMIO_PCLR      19
+#define GPIO_ESERIES_TMIO_SUSPEND   45
 #define GPIO_E800_ANGELX_IRQ      8
index 42ee1956750ebc1de1c36ed05eec19421c070da0..099f54a41de4cf1f45cb8905241d1503660899fb 100644 (file)
@@ -94,3 +94,7 @@ has detected a cable insertion; driven low otherwise. */
 #define GPIO26_PRDY_nBSY_MD            (GPIO26_PRDY_nBSY | GPIO_IN)
 #define GPIO27_PRDY_nBSY_MD            (GPIO27_PRDY_nBSY | GPIO_IN)
 #define GPIO36_nCD_MD                  (GPIO36_nCD | GPIO_IN)
+
+/* for expansion boards that can't be programatically detected */
+extern int am200_init(void);
+
diff --git a/arch/arm/mach-pxa/include/mach/h5000.h b/arch/arm/mach-pxa/include/mach/h5000.h
new file mode 100644 (file)
index 0000000..2a5ae38
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Hardware definitions for HP iPAQ h5xxx Handheld Computers
+ *
+ * Copyright(20)02 Hewlett-Packard Company.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Author: Jamey Hicks
+ */
+
+#ifndef __ASM_ARCH_H5000_H
+#define __ASM_ARCH_H5000_H
+
+#include <mach/mfp-pxa25x.h>
+
+/*
+ * CPU GPIOs
+ */
+
+#define H5000_GPIO_POWER_BUTTON   (0)
+#define H5000_GPIO_RESET_BUTTON_N (1)
+#define H5000_GPIO_OPT_INT        (2)
+#define H5000_GPIO_BACKUP_POWER   (3)
+#define H5000_GPIO_ACTION_BUTTON  (4)
+#define H5000_GPIO_COM_DCD_SOMETHING  (5) /* what is this really ? */
+/* 6 not connected */
+#define H5000_GPIO_RESET_BUTTON_AGAIN_N (7) /* connected to gpio 1 as well */
+/* 8 not connected */
+#define H5000_GPIO_RSO_N          (9)       /* reset output from max1702 which regulates 3.3 and 2.5 */
+#define H5000_GPIO_ASIC_INT_N   (10)       /* from companion asic */
+#define H5000_GPIO_BT_ENV_0     (11)       /* to LMX9814, set to 1 according to regdump */
+/*(12) not connected */
+#define H5000_GPIO_BT_ENV_1     (13)       /* to LMX9814, set to 1 according to regdump */
+#define H5000_GPIO_BT_WU        (14)       /* from LMX9814, Defined as HOST_WAKEUP in the LMX9820 data sheet */
+/*(15) is CS1# */
+/*(16) not connected */
+/*(17) not connected */
+/*(18) is pcmcia ready */
+/*(19) is dreq1 */
+/*(20) is dreq0 */
+#define H5000_GPIO_OE_RD_NWR   (21)       /* output enable on rd/nwr signal to companion asic */
+/*(22) is not connected */
+#define H5000_GPIO_OPT_SPI_CLK  (23)       /* to extension pack */
+#define H5000_GPIO_OPT_SPI_CS_N (24)       /* to extension pack */
+#define H5000_GPIO_OPT_SPI_DOUT (25)       /* to extension pack */
+#define H5000_GPIO_OPT_SPI_DIN  (26)       /* to extension pack */
+/*(27) not connected */
+#define H5000_GPIO_I2S_BITCLK   (28)       /* connected to AC97 codec */
+#define H5000_GPIO_I2S_DATAOUT  (29)       /* connected to AC97 codec */
+#define H5000_GPIO_I2S_DATAIN   (30)       /* connected to AC97 codec */
+#define H5000_GPIO_I2S_LRCLK    (31)       /* connected to AC97 codec */
+#define H5000_GPIO_I2S_SYSCLK   (32)       /* connected to AC97 codec */
+/*(33) is CS5# */
+#define H5000_GPIO_COM_RXD      (34)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_CTS      (35)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_DCD      (36)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_DSR      (37)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_RI       (38)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_TXD      (39)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_DTR      (40)       /* connected to cradle/cable connector */
+#define H5000_GPIO_COM_RTS      (41)       /* connected to cradle/cable connector */
+
+#define H5000_GPIO_BT_RXD       (42)       /* connected to BT (LMX9814) */
+#define H5000_GPIO_BT_TXD       (43)       /* connected to BT (LMX9814) */
+#define H5000_GPIO_BT_CTS       (44)       /* connected to BT (LMX9814) */
+#define H5000_GPIO_BT_RTS       (45)       /* connected to BT (LMX9814) */
+
+#define H5000_GPIO_IRDA_RXD     (46)
+#define H5000_GPIO_IRDA_TXD     (47)
+
+#define H5000_GPIO_POE_N        (48)       /* used for pcmcia */
+#define H5000_GPIO_PWE_N        (49)       /* used for pcmcia */
+#define H5000_GPIO_PIOR_N       (50)       /* used for pcmcia */
+#define H5000_GPIO_PIOW_N       (51)       /* used for pcmcia */
+#define H5000_GPIO_PCE1_N       (52)       /* used for pcmcia */
+#define H5000_GPIO_PCE2_N       (53)       /* used for pcmcia */
+#define H5000_GPIO_PSKTSEL      (54)       /* used for pcmcia */
+#define H5000_GPIO_PREG_N       (55)       /* used for pcmcia */
+#define H5000_GPIO_PWAIT_N      (56)       /* used for pcmcia */
+#define H5000_GPIO_IOIS16_N     (57)       /* used for pcmcia */
+
+#define H5000_GPIO_IRDA_SD      (58)       /* to hsdl3002 sd */
+/*(59) not connected */
+#define H5000_GPIO_POWER_SD_N   (60)       /* controls power to SD */
+#define H5000_GPIO_POWER_RS232_N       (61)       /* inverted FORCEON to rs232 transceiver */
+#define H5000_GPIO_POWER_ACCEL_N       (62)       /* controls power to accel */
+/*(63) is not connected */
+#define H5000_GPIO_OPT_NVRAM    (64)       /* controls power to expansion pack */
+#define H5000_GPIO_CHG_EN       (65)       /* to sc801 en */
+#define H5000_GPIO_USB_PULLUP   (66)       /* USB d+ pullup via 1.5K resistor */
+#define H5000_GPIO_BT_2V8_N     (67)       /* 2.8V used by bluetooth */
+#define H5000_GPIO_EXT_CHG_RATE (68)       /* enables external charging rate */
+/*(69) is not connected */
+#define H5000_GPIO_CIR_RESET    (70)       /* consumer IR reset */
+#define H5000_GPIO_POWER_LIGHT_SENSOR_N        (71)
+#define H5000_GPIO_BT_M_RESET   (72)
+#define H5000_GPIO_STD_CHG_RATE (73)
+#define H5000_GPIO_SD_WP_N      (74)
+#define H5000_GPIO_MOTOR_ON_N   (75)       /* external pullup on this */
+#define H5000_GPIO_HEADPHONE_DETECT    (76)
+#define H5000_GPIO_USB_CHG_RATE (77)       /* select rate for charging via usb */
+/*(78) is CS2# */
+/*(79) is CS3# */
+/*(80) is CS4# */
+
+#endif /* __ASM_ARCH_H5000_H */
index a582a6d9b92b10c93d6ecae6d95128472b4ae9a3..16ab79547daee4fc7763cf6515e7fedd9a09674c 100644 (file)
  *  PXA930     B0      0x69056835      0x5E643013
  *  PXA930     B1      0x69056837      0x7E643013
  *  PXA930     B2      0x69056838      0x8E643013
+ *
+ *  PXA935     A0      0x56056931      0x1E653013
+ *  PXA935     B0      0x56056936      0x6E653013
  */
 #ifdef CONFIG_PXA25x
 #define __cpu_is_pxa210(id)                            \
 #define __cpu_is_pxa930(id)                            \
        ({                                              \
                unsigned int _id = (id) >> 4 & 0xfff;   \
-               _id == 0x683;           \
+               _id == 0x683;                           \
         })
 #else
 #define __cpu_is_pxa930(id)    (0)
 #endif
 
+#ifdef CONFIG_CPU_PXA935
+#define __cpu_is_pxa935(id)                            \
+       ({                                              \
+               unsigned int _id = (id) >> 4 & 0xfff;   \
+               _id == 0x693;                           \
+        })
+#else
+#define __cpu_is_pxa935(id)    (0)
+#endif
+
 #define cpu_is_pxa210()                                        \
        ({                                              \
                __cpu_is_pxa210(read_cpuid_id());       \
                __cpu_is_pxa25x(read_cpuid_id());       \
        })
 
-extern int cpu_is_pxa26x(void);
-
 #define cpu_is_pxa27x()                                        \
        ({                                              \
                __cpu_is_pxa27x(read_cpuid_id());       \
@@ -232,6 +243,12 @@ extern int cpu_is_pxa26x(void);
                __cpu_is_pxa930(id);                    \
         })
 
+#define cpu_is_pxa935()                                        \
+       ({                                              \
+               unsigned int id = read_cpuid(CPUID_ID); \
+               __cpu_is_pxa935(id);                    \
+        })
+
 /*
  * CPUID Core Generation Bit
  * <= 0x2 for pxa21x/pxa25x/pxa26x/pxa27x
@@ -249,6 +266,12 @@ extern int cpu_is_pxa26x(void);
                _id == 0x3;                             \
         })
 
+#define __cpu_is_pxa9xx(id)                            \
+       ({                                              \
+               unsigned int _id = (id) >> 4 & 0xfff;   \
+               _id == 0x683 || _id == 0x693;           \
+        })
+
 #define cpu_is_pxa2xx()                                        \
        ({                                              \
                __cpu_is_pxa2xx(read_cpuid_id());       \
@@ -259,32 +282,25 @@ extern int cpu_is_pxa26x(void);
                __cpu_is_pxa3xx(read_cpuid_id());       \
         })
 
-/*
- * Handy routine to set GPIO alternate functions
- */
-extern int pxa_gpio_mode( int gpio_mode );
-
-/*
- * Return GPIO level, nonzero means high, zero is low
- */
-extern int pxa_gpio_get_value(unsigned gpio);
-
-/*
- * Set output GPIO level
- */
-extern void pxa_gpio_set_value(unsigned gpio, int value);
-
+#define cpu_is_pxa9xx()                                        \
+       ({                                              \
+               __cpu_is_pxa9xx(read_cpuid_id());       \
+        })
 /*
  * return current memory and LCD clock frequency in units of 10kHz
  */
 extern unsigned int get_memclk_frequency_10khz(void);
 
+/* return the clock tick rate of the OS timer */
+extern unsigned long get_clock_tick_rate(void);
 #endif
 
 #if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
 #define PCIBIOS_MIN_IO         0
 #define PCIBIOS_MIN_MEM                0
 #define pcibios_assign_all_busses()    1
+#define HAVE_ARCH_PCI_SET_DMA_MASK     1
 #endif
 
+
 #endif  /* _ASM_ARCH_HARDWARE_H */
index 600fd4f76603a51c6145839d74f0e5832ed790e8..262691fb97d86c2ce36de96d7e180a35b4906298 100644 (file)
@@ -6,15 +6,13 @@
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
-
 #define IO_SPACE_LIMIT 0xffffffff
 
 /*
  * We don't actually have real ISA nor PCI buses, but there is so many
  * drivers out there that might just work if we fake them...
  */
-#define __io(a)                        ((void __iomem *)(a))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 5c4e320c1437f4e57d7fa2409183dd48be103692..6c9b21c5132254dad261aa1dba4097293248684d 100644 (file)
@@ -1,8 +1,13 @@
-#ifndef __ASM_ARCH_ZYLONITE_H
-#define __ASM_ARCH_ZYLONITE_H
+#ifndef __ASM_ARCH_LITTLETON_H
+#define __ASM_ARCH_LITTLETON_H
+
+#include <mach/gpio.h>
 
 #define LITTLETON_ETH_PHYS     0x30000000
 
 #define LITTLETON_GPIO_LCD_CS  (17)
 
-#endif /* __ASM_ARCH_ZYLONITE_H */
+#define EXT0_GPIO_BASE (NR_BUILTIN_GPIO)
+#define EXT0_GPIO(x)   (EXT0_GPIO_BASE + (x))
+
+#endif /* __ASM_ARCH_LITTLETON_H */
index 59aef89808d6609cb371c4bf1d15b78fcd52dd19..f626730ee42e11a8071149677b43f55fb85666a7 100644 (file)
  */
 #define PHYS_OFFSET    UL(0xa0000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- */
-#define __virt_to_bus(x)        __virt_to_phys(x)
-#define __bus_to_virt(x)        __phys_to_virt(x)
-
 /*
  * The nodes are matched with the physical SDRAM banks as follows:
  *
@@ -47,6 +37,7 @@ void cmx2xx_pci_adjust_zones(int node, unsigned long *size,
        cmx2xx_pci_adjust_zones(node, size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_64M - 1)
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_64M)
 #endif
 
 #endif
index 617cab2cc8d0fcd7edb682134d3c10b6b1ca6389..a72869b73ee3a44d638cdd1fe5031d32913787cd 100644 (file)
 #define GPIO76_LCD_PCLK                MFP_CFG_OUT(GPIO76, AF2, DRIVE_LOW)
 #define GPIO77_LCD_BIAS                MFP_CFG_OUT(GPIO77, AF2, DRIVE_LOW)
 
+#ifdef CONFIG_CPU_PXA26x
+/* GPIO */
+#define GPIO85_GPIO            MFP_CFG_IN(GPIO85, AF0)
+#define GPIO86_GPIO            MFP_CFG_IN(GPIO86, AF1)
+#define GPIO87_GPIO            MFP_CFG_IN(GPIO87, AF1)
+#define GPIO88_GPIO            MFP_CFG_IN(GPIO88, AF1)
+#define GPIO89_GPIO            MFP_CFG_IN(GPIO89, AF1)
+
+/* SDRAM */
+#define GPIO86_nSDCS2          MFP_CFG_OUT(GPIO86, AF0, DRIVE_HIGH)
+#define GPIO87_nSDCS3          MFP_CFG_OUT(GPIO87, AF0, DRIVE_HIGH)
+#define GPIO88_RDnWR           MFP_CFG_OUT(GPIO88, AF0, DRIVE_HIGH)
+#define GPIO89_nACRESET                MFP_CFG_OUT(GPIO89, AF0, DRIVE_HIGH)
+
+/* USB */
+#define GPIO9_USB_RCV          MFP_CFG_IN(GPIO9, AF1)
+#define GPIO32_USB_VP          MFP_CFG_IN(GPIO32, AF2)
+#define GPIO34_USB_VM          MFP_CFG_IN(GPIO34, AF2)
+#define GPIO39_USB_VPO         MFP_CFG_OUT(GPIO39, AF3, DRIVE_LOW)
+#define GPIO56_USB_VMO         MFP_CFG_OUT(GPIO56, AF1, DRIVE_LOW)
+#define GPIO57_USB_nOE         MFP_CFG_OUT(GPIO57, AF1, DRIVE_HIGH)
+
+/* ASSP */
+#define GPIO28_ASSP_BITCLK_IN  MFP_CFG_IN(GPIO28, AF3)
+#define GPIO28_ASSP_BITCLK_OUT MFP_CFG_OUT(GPIO28, AF3, DRIVE_LOW)
+#define GPIO29_ASSP_RXD                MFP_CFG_IN(GPIO29, AF3)
+#define GPIO30_ASSP_TXD                MFP_CFG_OUT(GPIO30, AF3, DRIVE_LOW)
+#define GPIO31_ASSP_SFRM_IN    MFP_CFG_IN(GPIO31, AF1)
+#define GPIO31_ASSP_SFRM_OUT   MFP_CFG_OUT(GPIO31, AF3, DRIVE_LOW)
+#endif
+
 #endif /* __ASM_ARCH_MFP_PXA25X_H */
index 122bdbd5318222bddbc2b5469784d41e69704b64..da4f85a4f99010569794108c23e69bfb8e4ea59c 100644 (file)
 #include <mach/mfp.h>
 #include <mach/mfp-pxa2xx.h>
 
+/* Note: GPIO3/GPIO4 will be driven by Power I2C when PCFR/PI2C_EN
+ * bit is set, regardless of the GPIO configuration
+ */
+#define GPIO3_GPIO             MFP_CFG_IN(GPIO3, AF0)
+#define GPIO4_GPIO             MFP_CFG_IN(GPIO4, AF0)
+
 /* GPIO */
 #define GPIO85_GPIO            MFP_CFG_IN(GPIO85, AF0)
 #define GPIO86_GPIO            MFP_CFG_IN(GPIO86, AF0)
index fabd9b4df827075f2d30a16f170971bb9706f3b9..fa73f56a137241fe905bc3dc4cbed9b1d2eb435e 100644 (file)
 #define GPIO20_PWM0            MFP_CFG_LPM(GPIO20, AF2, PULL_LOW)
 #define GPIO21_PWM2            MFP_CFG_LPM(GPIO21, AF3, PULL_LOW)
 #define GPIO22_PWM3            MFP_CFG_LPM(GPIO22, AF3, PULL_LOW)
+#define GPIO32_PWM0            MFP_CFG_LPM(GPIO32, AF4, PULL_LOW)
 
 /* CIR */
 #define GPIO46_CIR_OUT         MFP_CFG(GPIO46, AF1)
index 8483cb511831f47659c744000349905fddce9491..02868447b0b135d56b4e9c687233358280da77b3 100644 (file)
         (MFP_PIN(pin) | MFP_##af | MFP_DIR_OUT | MFP_LPM_##state))
 
 /* Global GPIOs */
-#define GPIO9_CHARGE_nEN                       9
+#define GPIO9_CHARGE_EN                                9
 #define GPIO18_POWEROFF                                18
 #define GPIO87_LCD_POWER                       87
+#define GPIO96_AC_DETECT                       96
+#define GPIO80_MAYBE_CHARGE_VDROP              80      /* Drop of 88mV */
 
 /* USB */
-#define GPIO13_USB_DETECT                      13
+#define GPIO13_nUSB_DETECT                     13
 #define GPIO22_USB_ENABLE                      22
 
 /* SDIO bits */
 #define GPIO91_SDIO_EN                         91
 
 /* Bluetooth */
+#define GPIO14_BT_nACTIVITY                    14
 #define GPIO83_BT_ON                           83
+#define GPIO77_BT_UNKNOWN1                     77
+#define GPIO86_BT_MAYBE_nRESET                 86
 
 /* GPS */
 #define GPIO23_GPS_UNKNOWN1                    23
index 4d452fcb15086317ea5f1639aee75ec4981624fa..cfca8155be7232b294e72c3cf407e1c349f8c723 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __ARCH_PXA_MTD_XIP_H__
 #define __ARCH_PXA_MTD_XIP_H__
 
+#include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 
 #define xip_irqpending()       (ICIP & ICMR)
index 15295d96000025e4bb4bf0fadbd393dafcee3347..31d615aa7723af3ca217fd59a142e2ae03bc034f 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __PXA_REGS_H
 #define __PXA_REGS_H
 
+#include <mach/hardware.h>
 
 /*
  * PXA Chip selects
 #define DCMD_WIDTH4    (3 << 14)       /* 4 byte width (Word) */
 #define DCMD_LENGTH    0x01fff         /* length mask (max = 8K - 1) */
 
-
-/*
- * UARTs
- */
-
-/* Full Function UART (FFUART) */
-#define FFUART         FFRBR
-#define FFRBR          __REG(0x40100000)  /* Receive Buffer Register (read only) */
-#define FFTHR          __REG(0x40100000)  /* Transmit Holding Register (write only) */
-#define FFIER          __REG(0x40100004)  /* Interrupt Enable Register (read/write) */
-#define FFIIR          __REG(0x40100008)  /* Interrupt ID Register (read only) */
-#define FFFCR          __REG(0x40100008)  /* FIFO Control Register (write only) */
-#define FFLCR          __REG(0x4010000C)  /* Line Control Register (read/write) */
-#define FFMCR          __REG(0x40100010)  /* Modem Control Register (read/write) */
-#define FFLSR          __REG(0x40100014)  /* Line Status Register (read only) */
-#define FFMSR          __REG(0x40100018)  /* Modem Status Register (read only) */
-#define FFSPR          __REG(0x4010001C)  /* Scratch Pad Register (read/write) */
-#define FFISR          __REG(0x40100020)  /* Infrared Selection Register (read/write) */
-#define FFDLL          __REG(0x40100000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
-#define FFDLH          __REG(0x40100004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
-
-/* Bluetooth UART (BTUART) */
-#define BTUART         BTRBR
-#define BTRBR          __REG(0x40200000)  /* Receive Buffer Register (read only) */
-#define BTTHR          __REG(0x40200000)  /* Transmit Holding Register (write only) */
-#define BTIER          __REG(0x40200004)  /* Interrupt Enable Register (read/write) */
-#define BTIIR          __REG(0x40200008)  /* Interrupt ID Register (read only) */
-#define BTFCR          __REG(0x40200008)  /* FIFO Control Register (write only) */
-#define BTLCR          __REG(0x4020000C)  /* Line Control Register (read/write) */
-#define BTMCR          __REG(0x40200010)  /* Modem Control Register (read/write) */
-#define BTLSR          __REG(0x40200014)  /* Line Status Register (read only) */
-#define BTMSR          __REG(0x40200018)  /* Modem Status Register (read only) */
-#define BTSPR          __REG(0x4020001C)  /* Scratch Pad Register (read/write) */
-#define BTISR          __REG(0x40200020)  /* Infrared Selection Register (read/write) */
-#define BTDLL          __REG(0x40200000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
-#define BTDLH          __REG(0x40200004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
-
-/* Standard UART (STUART) */
-#define STUART         STRBR
-#define STRBR          __REG(0x40700000)  /* Receive Buffer Register (read only) */
-#define STTHR          __REG(0x40700000)  /* Transmit Holding Register (write only) */
-#define STIER          __REG(0x40700004)  /* Interrupt Enable Register (read/write) */
-#define STIIR          __REG(0x40700008)  /* Interrupt ID Register (read only) */
-#define STFCR          __REG(0x40700008)  /* FIFO Control Register (write only) */
-#define STLCR          __REG(0x4070000C)  /* Line Control Register (read/write) */
-#define STMCR          __REG(0x40700010)  /* Modem Control Register (read/write) */
-#define STLSR          __REG(0x40700014)  /* Line Status Register (read only) */
-#define STMSR          __REG(0x40700018)  /* Reserved */
-#define STSPR          __REG(0x4070001C)  /* Scratch Pad Register (read/write) */
-#define STISR          __REG(0x40700020)  /* Infrared Selection Register (read/write) */
-#define STDLL          __REG(0x40700000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
-#define STDLH          __REG(0x40700004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
-
-/* Hardware UART (HWUART) */
-#define HWUART         HWRBR
-#define HWRBR          __REG(0x41600000)  /* Receive Buffer Register (read only) */
-#define HWTHR          __REG(0x41600000)  /* Transmit Holding Register (write only) */
-#define HWIER          __REG(0x41600004)  /* Interrupt Enable Register (read/write) */
-#define HWIIR          __REG(0x41600008)  /* Interrupt ID Register (read only) */
-#define HWFCR          __REG(0x41600008)  /* FIFO Control Register (write only) */
-#define HWLCR          __REG(0x4160000C)  /* Line Control Register (read/write) */
-#define HWMCR          __REG(0x41600010)  /* Modem Control Register (read/write) */
-#define HWLSR          __REG(0x41600014)  /* Line Status Register (read only) */
-#define HWMSR          __REG(0x41600018)  /* Modem Status Register (read only) */
-#define HWSPR          __REG(0x4160001C)  /* Scratch Pad Register (read/write) */
-#define HWISR          __REG(0x41600020)  /* Infrared Selection Register (read/write) */
-#define HWFOR          __REG(0x41600024)  /* Receive FIFO Occupancy Register (read only) */
-#define HWABR          __REG(0x41600028)  /* Auto-Baud Control Register (read/write) */
-#define HWACR          __REG(0x4160002C)  /* Auto-Baud Count Register (read only) */
-#define HWDLL          __REG(0x41600000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
-#define HWDLH          __REG(0x41600004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
-
-#define IER_DMAE       (1 << 7)        /* DMA Requests Enable */
-#define IER_UUE                (1 << 6)        /* UART Unit Enable */
-#define IER_NRZE       (1 << 5)        /* NRZ coding Enable */
-#define IER_RTIOE      (1 << 4)        /* Receiver Time Out Interrupt Enable */
-#define IER_MIE                (1 << 3)        /* Modem Interrupt Enable */
-#define IER_RLSE       (1 << 2)        /* Receiver Line Status Interrupt Enable */
-#define IER_TIE                (1 << 1)        /* Transmit Data request Interrupt Enable */
-#define IER_RAVIE      (1 << 0)        /* Receiver Data Available Interrupt Enable */
-
-#define IIR_FIFOES1    (1 << 7)        /* FIFO Mode Enable Status */
-#define IIR_FIFOES0    (1 << 6)        /* FIFO Mode Enable Status */
-#define IIR_TOD                (1 << 3)        /* Time Out Detected */
-#define IIR_IID2       (1 << 2)        /* Interrupt Source Encoded */
-#define IIR_IID1       (1 << 1)        /* Interrupt Source Encoded */
-#define IIR_IP         (1 << 0)        /* Interrupt Pending (active low) */
-
-#define FCR_ITL2       (1 << 7)        /* Interrupt Trigger Level */
-#define FCR_ITL1       (1 << 6)        /* Interrupt Trigger Level */
-#define FCR_RESETTF    (1 << 2)        /* Reset Transmitter FIFO */
-#define FCR_RESETRF    (1 << 1)        /* Reset Receiver FIFO */
-#define FCR_TRFIFOE    (1 << 0)        /* Transmit and Receive FIFO Enable */
-#define FCR_ITL_1      (0)
-#define FCR_ITL_8      (FCR_ITL1)
-#define FCR_ITL_16     (FCR_ITL2)
-#define FCR_ITL_32     (FCR_ITL2|FCR_ITL1)
-
-#define LCR_DLAB       (1 << 7)        /* Divisor Latch Access Bit */
-#define LCR_SB         (1 << 6)        /* Set Break */
-#define LCR_STKYP      (1 << 5)        /* Sticky Parity */
-#define LCR_EPS                (1 << 4)        /* Even Parity Select */
-#define LCR_PEN                (1 << 3)        /* Parity Enable */
-#define LCR_STB                (1 << 2)        /* Stop Bit */
-#define LCR_WLS1       (1 << 1)        /* Word Length Select */
-#define LCR_WLS0       (1 << 0)        /* Word Length Select */
-
-#define LSR_FIFOE      (1 << 7)        /* FIFO Error Status */
-#define LSR_TEMT       (1 << 6)        /* Transmitter Empty */
-#define LSR_TDRQ       (1 << 5)        /* Transmit Data Request */
-#define LSR_BI         (1 << 4)        /* Break Interrupt */
-#define LSR_FE         (1 << 3)        /* Framing Error */
-#define LSR_PE         (1 << 2)        /* Parity Error */
-#define LSR_OE         (1 << 1)        /* Overrun Error */
-#define LSR_DR         (1 << 0)        /* Data Ready */
-
-#define MCR_LOOP       (1 << 4)
-#define MCR_OUT2       (1 << 3)        /* force MSR_DCD in loopback mode */
-#define MCR_OUT1       (1 << 2)        /* force MSR_RI in loopback mode */
-#define MCR_RTS                (1 << 1)        /* Request to Send */
-#define MCR_DTR                (1 << 0)        /* Data Terminal Ready */
-
-#define MSR_DCD                (1 << 7)        /* Data Carrier Detect */
-#define MSR_RI         (1 << 6)        /* Ring Indicator */
-#define MSR_DSR                (1 << 5)        /* Data Set Ready */
-#define MSR_CTS                (1 << 4)        /* Clear To Send */
-#define MSR_DDCD       (1 << 3)        /* Delta Data Carrier Detect */
-#define MSR_TERI       (1 << 2)        /* Trailing Edge Ring Indicator */
-#define MSR_DDSR       (1 << 1)        /* Delta Data Set Ready */
-#define MSR_DCTS       (1 << 0)        /* Delta Clear To Send */
-
-/*
- * IrSR (Infrared Selection Register)
- */
-#define STISR_RXPL      (1 << 4)        /* Receive Data Polarity */
-#define STISR_TXPL      (1 << 3)        /* Transmit Data Polarity */
-#define STISR_XMODE     (1 << 2)        /* Transmit Pulse Width Select */
-#define STISR_RCVEIR    (1 << 1)        /* Receiver SIR Enable */
-#define STISR_XMITIR    (1 << 0)        /* Transmitter SIR Enable */
-
-
-/*
- * I2C registers - moved into drivers/i2c/busses/i2c-pxa.c
- */
-
-/*
- * Serial Audio Controller - moved into sound/soc/pxa/pxa2xx-i2s.c
- */
-
-/*
- * AC97 Controller registers
- */
-
-#define POCR           __REG(0x40500000)  /* PCM Out Control Register */
-#define POCR_FEIE      (1 << 3)        /* FIFO Error Interrupt Enable */
-#define POCR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
-
-#define PICR           __REG(0x40500004)  /* PCM In Control Register */
-#define PICR_FEIE      (1 << 3)        /* FIFO Error Interrupt Enable */
-#define PICR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
-
-#define MCCR           __REG(0x40500008)  /* Mic In Control Register */
-#define MCCR_FEIE      (1 << 3)        /* FIFO Error Interrupt Enable */
-#define MCCR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
-
-#define GCR            __REG(0x4050000C)  /* Global Control Register */
-#ifdef CONFIG_PXA3xx
-#define GCR_CLKBPB     (1 << 31)       /* Internal clock enable */
-#endif
-#define GCR_nDMAEN     (1 << 24)       /* non DMA Enable */
-#define GCR_CDONE_IE   (1 << 19)       /* Command Done Interrupt Enable */
-#define GCR_SDONE_IE   (1 << 18)       /* Status Done Interrupt Enable */
-#define GCR_SECRDY_IEN (1 << 9)        /* Secondary Ready Interrupt Enable */
-#define GCR_PRIRDY_IEN (1 << 8)        /* Primary Ready Interrupt Enable */
-#define GCR_SECRES_IEN (1 << 5)        /* Secondary Resume Interrupt Enable */
-#define GCR_PRIRES_IEN (1 << 4)        /* Primary Resume Interrupt Enable */
-#define GCR_ACLINK_OFF (1 << 3)        /* AC-link Shut Off */
-#define GCR_WARM_RST   (1 << 2)        /* AC97 Warm Reset */
-#define GCR_COLD_RST   (1 << 1)        /* AC'97 Cold Reset (0 = active) */
-#define GCR_GIE                (1 << 0)        /* Codec GPI Interrupt Enable */
-
-#define POSR           __REG(0x40500010)  /* PCM Out Status Register */
-#define POSR_FIFOE     (1 << 4)        /* FIFO error */
-#define POSR_FSR       (1 << 2)        /* FIFO Service Request */
-
-#define PISR           __REG(0x40500014)  /* PCM In Status Register */
-#define PISR_FIFOE     (1 << 4)        /* FIFO error */
-#define PISR_EOC       (1 << 3)        /* DMA End-of-Chain (exclusive clear) */
-#define PISR_FSR       (1 << 2)        /* FIFO Service Request */
-
-#define MCSR           __REG(0x40500018)  /* Mic In Status Register */
-#define MCSR_FIFOE     (1 << 4)        /* FIFO error */
-#define MCSR_EOC       (1 << 3)        /* DMA End-of-Chain (exclusive clear) */
-#define MCSR_FSR       (1 << 2)        /* FIFO Service Request */
-
-#define GSR            __REG(0x4050001C)  /* Global Status Register */
-#define GSR_CDONE      (1 << 19)       /* Command Done */
-#define GSR_SDONE      (1 << 18)       /* Status Done */
-#define GSR_RDCS       (1 << 15)       /* Read Completion Status */
-#define GSR_BIT3SLT12  (1 << 14)       /* Bit 3 of slot 12 */
-#define GSR_BIT2SLT12  (1 << 13)       /* Bit 2 of slot 12 */
-#define GSR_BIT1SLT12  (1 << 12)       /* Bit 1 of slot 12 */
-#define GSR_SECRES     (1 << 11)       /* Secondary Resume Interrupt */
-#define GSR_PRIRES     (1 << 10)       /* Primary Resume Interrupt */
-#define GSR_SCR                (1 << 9)        /* Secondary Codec Ready */
-#define GSR_PCR                (1 << 8)        /*  Primary Codec Ready */
-#define GSR_MCINT      (1 << 7)        /* Mic In Interrupt */
-#define GSR_POINT      (1 << 6)        /* PCM Out Interrupt */
-#define GSR_PIINT      (1 << 5)        /* PCM In Interrupt */
-#define GSR_ACOFFD     (1 << 3)        /* AC-link Shut Off Done */
-#define GSR_MOINT      (1 << 2)        /* Modem Out Interrupt */
-#define GSR_MIINT      (1 << 1)        /* Modem In Interrupt */
-#define GSR_GSCI       (1 << 0)        /* Codec GPI Status Change Interrupt */
-
-#define CAR            __REG(0x40500020)  /* CODEC Access Register */
-#define CAR_CAIP       (1 << 0)        /* Codec Access In Progress */
-
-#define PCDR           __REG(0x40500040)  /* PCM FIFO Data Register */
-#define MCDR           __REG(0x40500060)  /* Mic-in FIFO Data Register */
-
-#define MOCR           __REG(0x40500100)  /* Modem Out Control Register */
-#define MOCR_FEIE      (1 << 3)        /* FIFO Error */
-#define MOCR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
-
-#define MICR           __REG(0x40500108)  /* Modem In Control Register */
-#define MICR_FEIE      (1 << 3)        /* FIFO Error */
-#define MICR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
-
-#define MOSR           __REG(0x40500110)  /* Modem Out Status Register */
-#define MOSR_FIFOE     (1 << 4)        /* FIFO error */
-#define MOSR_FSR       (1 << 2)        /* FIFO Service Request */
-
-#define MISR           __REG(0x40500118)  /* Modem In Status Register */
-#define MISR_FIFOE     (1 << 4)        /* FIFO error */
-#define MISR_EOC       (1 << 3)        /* DMA End-of-Chain (exclusive clear) */
-#define MISR_FSR       (1 << 2)        /* FIFO Service Request */
-
-#define MODR           __REG(0x40500140)  /* Modem FIFO Data Register */
-
-#define PAC_REG_BASE   __REG(0x40500200)  /* Primary Audio Codec */
-#define SAC_REG_BASE   __REG(0x40500300)  /* Secondary Audio Codec */
-#define PMC_REG_BASE   __REG(0x40500400)  /* Primary Modem Codec */
-#define SMC_REG_BASE   __REG(0x40500500)  /* Secondary Modem Codec */
-
-
-/*
- * Fast Infrared Communication Port
- */
-
-#define FICP           __REG(0x40800000)  /* Start of FICP area */
-#define ICCR0          __REG(0x40800000)  /* ICP Control Register 0 */
-#define ICCR1          __REG(0x40800004)  /* ICP Control Register 1 */
-#define ICCR2          __REG(0x40800008)  /* ICP Control Register 2 */
-#define ICDR           __REG(0x4080000c)  /* ICP Data Register */
-#define ICSR0          __REG(0x40800014)  /* ICP Status Register 0 */
-#define ICSR1          __REG(0x40800018)  /* ICP Status Register 1 */
-
-#define ICCR0_AME      (1 << 7)        /* Address match enable */
-#define ICCR0_TIE      (1 << 6)        /* Transmit FIFO interrupt enable */
-#define ICCR0_RIE      (1 << 5)        /* Recieve FIFO interrupt enable */
-#define ICCR0_RXE      (1 << 4)        /* Receive enable */
-#define ICCR0_TXE      (1 << 3)        /* Transmit enable */
-#define ICCR0_TUS      (1 << 2)        /* Transmit FIFO underrun select */
-#define ICCR0_LBM      (1 << 1)        /* Loopback mode */
-#define ICCR0_ITR      (1 << 0)        /* IrDA transmission */
-
-#define ICCR2_RXP       (1 << 3)       /* Receive Pin Polarity select */
-#define ICCR2_TXP       (1 << 2)       /* Transmit Pin Polarity select */
-#define ICCR2_TRIG     (3 << 0)        /* Receive FIFO Trigger threshold */
-#define ICCR2_TRIG_8    (0 << 0)       /*      >= 8 bytes */
-#define ICCR2_TRIG_16   (1 << 0)       /*      >= 16 bytes */
-#define ICCR2_TRIG_32   (2 << 0)       /*      >= 32 bytes */
-
-#ifdef CONFIG_PXA27x
-#define ICSR0_EOC      (1 << 6)        /* DMA End of Descriptor Chain */
-#endif
-#define ICSR0_FRE      (1 << 5)        /* Framing error */
-#define ICSR0_RFS      (1 << 4)        /* Receive FIFO service request */
-#define ICSR0_TFS      (1 << 3)        /* Transnit FIFO service request */
-#define ICSR0_RAB      (1 << 2)        /* Receiver abort */
-#define ICSR0_TUR      (1 << 1)        /* Trunsmit FIFO underun */
-#define ICSR0_EIF      (1 << 0)        /* End/Error in FIFO */
-
-#define ICSR1_ROR      (1 << 6)        /* Receiver FIFO underrun  */
-#define ICSR1_CRE      (1 << 5)        /* CRC error */
-#define ICSR1_EOF      (1 << 4)        /* End of frame */
-#define ICSR1_TNF      (1 << 3)        /* Transmit FIFO not full */
-#define ICSR1_RNE      (1 << 2)        /* Receive FIFO not empty */
-#define ICSR1_TBY      (1 << 1)        /* Tramsmiter busy flag */
-#define ICSR1_RSY      (1 << 0)        /* Recevier synchronized flag */
-
-
 /*
  * Real Time Clock
  */
 #define OIER_E0                (1 << 0)        /* Interrupt enable channel 0 */
 
 
-/*
- * Pulse Width Modulator
- */
-
-#define PWM_CTRL0      __REG(0x40B00000)  /* PWM 0 Control Register */
-#define PWM_PWDUTY0    __REG(0x40B00004)  /* PWM 0 Duty Cycle Register */
-#define PWM_PERVAL0    __REG(0x40B00008)  /* PWM 0 Period Control Register */
-
-#define PWM_CTRL1      __REG(0x40C00000)  /* PWM 1Control Register */
-#define PWM_PWDUTY1    __REG(0x40C00004)  /* PWM 1 Duty Cycle Register */
-#define PWM_PERVAL1    __REG(0x40C00008)  /* PWM 1 Period Control Register */
-
-
 /*
  * Interrupt Controller
  */
  * General Purpose I/O
  */
 
-#define GPIO0_BASE     ((void __iomem *)io_p2v(0x40E00000))
-#define GPIO1_BASE     ((void __iomem *)io_p2v(0x40E00004))
-#define GPIO2_BASE     ((void __iomem *)io_p2v(0x40E00008))
-#define GPIO3_BASE     ((void __iomem *)io_p2v(0x40E00100))
-
-#define GPLR_OFFSET    0x00
-#define GPDR_OFFSET    0x0C
-#define GPSR_OFFSET    0x18
-#define GPCR_OFFSET    0x24
-#define GRER_OFFSET    0x30
-#define GFER_OFFSET    0x3C
-#define GEDR_OFFSET    0x48
-
 #define GPLR0          __REG(0x40E00000)  /* GPIO Pin-Level Register GPIO<31:0> */
 #define GPLR1          __REG(0x40E00004)  /* GPIO Pin-Level Register GPIO<63:32> */
 #define GPLR2          __REG(0x40E00008)  /* GPIO Pin-Level Register GPIO<80:64> */
 
 #define GPIO_bit(x)    (1 << ((x) & 0x1f))
 
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-
-/* Interrupt Controller */
-
 #define _GPLR(x)       __REG2(0x40E00000, ((x) & 0x60) >> 3)
 #define _GPDR(x)       __REG2(0x40E0000C, ((x) & 0x60) >> 3)
 #define _GPSR(x)       __REG2(0x40E00018, ((x) & 0x60) >> 3)
 #define GEDR(x)                (*((((x) & 0x7f) < 96) ? &_GEDR(x) : &GEDR3))
 #define GAFR(x)                (*((((x) & 0x7f) < 96) ? &_GAFR(x) : \
                         ((((x) & 0x7f) < 112) ? &GAFR3_L : &GAFR3_U)))
-#else
-
-#define GPLR(x)                __REG2(0x40E00000, ((x) & 0x60) >> 3)
-#define GPDR(x)                __REG2(0x40E0000C, ((x) & 0x60) >> 3)
-#define GPSR(x)                __REG2(0x40E00018, ((x) & 0x60) >> 3)
-#define GPCR(x)                __REG2(0x40E00024, ((x) & 0x60) >> 3)
-#define GRER(x)                __REG2(0x40E00030, ((x) & 0x60) >> 3)
-#define GFER(x)                __REG2(0x40E0003C, ((x) & 0x60) >> 3)
-#define GEDR(x)                __REG2(0x40E00048, ((x) & 0x60) >> 3)
-#define GAFR(x)                __REG2(0x40E00054, ((x) & 0x70) >> 2)
-
-#endif
-
-/*
- * Power Manager - see pxa2xx-regs.h
- */
-
-/*
- * SSP Serial Port Registers - see arch/arm/mach-pxa/include/mach/regs-ssp.h
- */
-
-/*
- * MultiMediaCard (MMC) controller - see drivers/mmc/host/pxamci.h
- */
-
-/*
- * Core Clock - see arch/arm/mach-pxa/include/mach/pxa2xx-regs.h
- */
-
-#ifdef CONFIG_PXA27x
-
-/* Camera Interface */
-#define CICR0          __REG(0x50000000)
-#define CICR1          __REG(0x50000004)
-#define CICR2          __REG(0x50000008)
-#define CICR3          __REG(0x5000000C)
-#define CICR4          __REG(0x50000010)
-#define CISR           __REG(0x50000014)
-#define CIFR           __REG(0x50000018)
-#define CITOR          __REG(0x5000001C)
-#define CIBR0          __REG(0x50000028)
-#define CIBR1          __REG(0x50000030)
-#define CIBR2          __REG(0x50000038)
-
-#define CICR0_DMAEN    (1 << 31)       /* DMA request enable */
-#define CICR0_PAR_EN   (1 << 30)       /* Parity enable */
-#define CICR0_SL_CAP_EN        (1 << 29)       /* Capture enable for slave mode */
-#define CICR0_ENB      (1 << 28)       /* Camera interface enable */
-#define CICR0_DIS      (1 << 27)       /* Camera interface disable */
-#define CICR0_SIM      (0x7 << 24)     /* Sensor interface mode mask */
-#define CICR0_TOM      (1 << 9)        /* Time-out mask */
-#define CICR0_RDAVM    (1 << 8)        /* Receive-data-available mask */
-#define CICR0_FEM      (1 << 7)        /* FIFO-empty mask */
-#define CICR0_EOLM     (1 << 6)        /* End-of-line mask */
-#define CICR0_PERRM    (1 << 5)        /* Parity-error mask */
-#define CICR0_QDM      (1 << 4)        /* Quick-disable mask */
-#define CICR0_CDM      (1 << 3)        /* Disable-done mask */
-#define CICR0_SOFM     (1 << 2)        /* Start-of-frame mask */
-#define CICR0_EOFM     (1 << 1)        /* End-of-frame mask */
-#define CICR0_FOM      (1 << 0)        /* FIFO-overrun mask */
-
-#define CICR1_TBIT     (1 << 31)       /* Transparency bit */
-#define CICR1_RGBT_CONV        (0x3 << 29)     /* RGBT conversion mask */
-#define CICR1_PPL      (0x7ff << 15)   /* Pixels per line mask */
-#define CICR1_RGB_CONV (0x7 << 12)     /* RGB conversion mask */
-#define CICR1_RGB_F    (1 << 11)       /* RGB format */
-#define CICR1_YCBCR_F  (1 << 10)       /* YCbCr format */
-#define CICR1_RGB_BPP  (0x7 << 7)      /* RGB bis per pixel mask */
-#define CICR1_RAW_BPP  (0x3 << 5)      /* Raw bis per pixel mask */
-#define CICR1_COLOR_SP (0x3 << 3)      /* Color space mask */
-#define CICR1_DW       (0x7 << 0)      /* Data width mask */
-
-#define CICR2_BLW      (0xff << 24)    /* Beginning-of-line pixel clock
-                                          wait count mask */
-#define CICR2_ELW      (0xff << 16)    /* End-of-line pixel clock
-                                          wait count mask */
-#define CICR2_HSW      (0x3f << 10)    /* Horizontal sync pulse width mask */
-#define CICR2_BFPW     (0x3f << 3)     /* Beginning-of-frame pixel clock
-                                          wait count mask */
-#define CICR2_FSW      (0x7 << 0)      /* Frame stabilization
-                                          wait count mask */
-
-#define CICR3_BFW      (0xff << 24)    /* Beginning-of-frame line clock
-                                          wait count mask */
-#define CICR3_EFW      (0xff << 16)    /* End-of-frame line clock
-                                          wait count mask */
-#define CICR3_VSW      (0x3f << 10)    /* Vertical sync pulse width mask */
-#define CICR3_BFPW     (0x3f << 3)     /* Beginning-of-frame pixel clock
-                                          wait count mask */
-#define CICR3_LPF      (0x7ff << 0)    /* Lines per frame mask */
-
-#define CICR4_MCLK_DLY (0x3 << 24)     /* MCLK Data Capture Delay mask */
-#define CICR4_PCLK_EN  (1 << 23)       /* Pixel clock enable */
-#define CICR4_PCP      (1 << 22)       /* Pixel clock polarity */
-#define CICR4_HSP      (1 << 21)       /* Horizontal sync polarity */
-#define CICR4_VSP      (1 << 20)       /* Vertical sync polarity */
-#define CICR4_MCLK_EN  (1 << 19)       /* MCLK enable */
-#define CICR4_FR_RATE  (0x7 << 8)      /* Frame rate mask */
-#define CICR4_DIV      (0xff << 0)     /* Clock divisor mask */
-
-#define CISR_FTO       (1 << 15)       /* FIFO time-out */
-#define CISR_RDAV_2    (1 << 14)       /* Channel 2 receive data available */
-#define CISR_RDAV_1    (1 << 13)       /* Channel 1 receive data available */
-#define CISR_RDAV_0    (1 << 12)       /* Channel 0 receive data available */
-#define CISR_FEMPTY_2  (1 << 11)       /* Channel 2 FIFO empty */
-#define CISR_FEMPTY_1  (1 << 10)       /* Channel 1 FIFO empty */
-#define CISR_FEMPTY_0  (1 << 9)        /* Channel 0 FIFO empty */
-#define CISR_EOL       (1 << 8)        /* End of line */
-#define CISR_PAR_ERR   (1 << 7)        /* Parity error */
-#define CISR_CQD       (1 << 6)        /* Camera interface quick disable */
-#define CISR_CDD       (1 << 5)        /* Camera interface disable done */
-#define CISR_SOF       (1 << 4)        /* Start of frame */
-#define CISR_EOF       (1 << 3)        /* End of frame */
-#define CISR_IFO_2     (1 << 2)        /* FIFO overrun for Channel 2 */
-#define CISR_IFO_1     (1 << 1)        /* FIFO overrun for Channel 1 */
-#define CISR_IFO_0     (1 << 0)        /* FIFO overrun for Channel 0 */
-
-#define CIFR_FLVL2     (0x7f << 23)    /* FIFO 2 level mask */
-#define CIFR_FLVL1     (0x7f << 16)    /* FIFO 1 level mask */
-#define CIFR_FLVL0     (0xff << 8)     /* FIFO 0 level mask */
-#define CIFR_THL_0     (0x3 << 4)      /* Threshold Level for Channel 0 FIFO */
-#define CIFR_RESET_F   (1 << 3)        /* Reset input FIFOs */
-#define CIFR_FEN2      (1 << 2)        /* FIFO enable for channel 2 */
-#define CIFR_FEN1      (1 << 1)        /* FIFO enable for channel 1 */
-#define CIFR_FEN0      (1 << 0)        /* FIFO enable for channel 0 */
-
-#define SRAM_SIZE              0x40000 /* 4x64K  */
-
-#define SRAM_MEM_PHYS          0x5C000000
-
-#define IMPMCR         __REG(0x58000000) /* IM Power Management Control Reg */
-#define IMPMSR         __REG(0x58000008) /* IM Power Management Status Reg */
-
-#define IMPMCR_PC3             (0x3 << 22) /* Bank 3 Power Control */
-#define IMPMCR_PC3_RUN_MODE    (0x0 << 22) /*   Run mode */
-#define IMPMCR_PC3_STANDBY_MODE        (0x1 << 22) /*   Standby mode */
-#define IMPMCR_PC3_AUTO_MODE   (0x3 << 22) /*   Automatically controlled */
-
-#define IMPMCR_PC2             (0x3 << 20) /* Bank 2 Power Control */
-#define IMPMCR_PC2_RUN_MODE    (0x0 << 20) /*   Run mode */
-#define IMPMCR_PC2_STANDBY_MODE        (0x1 << 20) /*   Standby mode */
-#define IMPMCR_PC2_AUTO_MODE   (0x3 << 20) /*   Automatically controlled */
-
-#define IMPMCR_PC1             (0x3 << 18) /* Bank 1 Power Control */
-#define IMPMCR_PC1_RUN_MODE    (0x0 << 18) /*   Run mode */
-#define IMPMCR_PC1_STANDBY_MODE        (0x1 << 18) /*   Standby mode */
-#define IMPMCR_PC1_AUTO_MODE   (0x3 << 18) /*   Automatically controlled */
-
-#define IMPMCR_PC0             (0x3 << 16) /* Bank 0 Power Control */
-#define IMPMCR_PC0_RUN_MODE    (0x0 << 16) /*   Run mode */
-#define IMPMCR_PC0_STANDBY_MODE        (0x1 << 16) /*   Standby mode */
-#define IMPMCR_PC0_AUTO_MODE   (0x3 << 16) /*   Automatically controlled */
-
-#define IMPMCR_AW3             (1 << 11) /* Bank 3 Automatic Wake-up enable */
-#define IMPMCR_AW2             (1 << 10) /* Bank 2 Automatic Wake-up enable */
-#define IMPMCR_AW1             (1 << 9)  /* Bank 1 Automatic Wake-up enable */
-#define IMPMCR_AW0             (1 << 8)  /* Bank 0 Automatic Wake-up enable */
-
-#define IMPMCR_DST             (0xFF << 0) /* Delay Standby Time, ms */
-
-#define IMPMSR_PS3             (0x3 << 6) /* Bank 3 Power Status: */
-#define IMPMSR_PS3_RUN_MODE    (0x0 << 6) /*    Run mode */
-#define IMPMSR_PS3_STANDBY_MODE        (0x1 << 6) /*    Standby mode */
-
-#define IMPMSR_PS2             (0x3 << 4) /* Bank 2 Power Status: */
-#define IMPMSR_PS2_RUN_MODE    (0x0 << 4) /*    Run mode */
-#define IMPMSR_PS2_STANDBY_MODE        (0x1 << 4) /*    Standby mode */
-
-#define IMPMSR_PS1             (0x3 << 2) /* Bank 1 Power Status: */
-#define IMPMSR_PS1_RUN_MODE    (0x0 << 2) /*    Run mode */
-#define IMPMSR_PS1_STANDBY_MODE        (0x1 << 2) /*    Standby mode */
-
-#define IMPMSR_PS0             (0x3 << 0) /* Bank 0 Power Status: */
-#define IMPMSR_PS0_RUN_MODE    (0x0 << 0) /*    Run mode */
-#define IMPMSR_PS0_STANDBY_MODE        (0x1 << 0) /*    Standby mode */
-
-#endif
-
-/* PWRMODE register M field values */
-
-#define PWRMODE_IDLE           0x1
-#define PWRMODE_STANDBY                0x2
-#define PWRMODE_SLEEP          0x3
-#define PWRMODE_DEEPSLEEP      0x7
 
 #endif
index 6ef1dd09970b47240ddc5c1ce0447a8e2088a699..d83393e252734398462bf140a9f8086bf09a5c95 100644 (file)
 #define GPIO117_I2CSCL_MD      (117 | GPIO_ALT_FN_1_IN)
 #define GPIO118_I2CSDA_MD      (118 | GPIO_ALT_FN_1_IN)
 
+/*
+ * Handy routine to set GPIO alternate functions
+ */
+extern int pxa_gpio_mode( int gpio_mode );
+
 #endif /* __ASM_ARCH_PXA2XX_GPIO_H */
index 806ecfea44bfb87c18f09ac8c5c49ccdc29838ab..77102d695cc7c58dd0b65f974f956069f777146b 100644 (file)
 #define MECR_NOS       (1 << 0)        /* Number Of Sockets: 0 -> 1 sock, 1 -> 2 sock */
 #define MECR_CIT       (1 << 1)        /* Card Is There: 0 -> no card, 1 -> card inserted */
 
+#define MDCNFG_DE0     (1 << 0)        /* SDRAM Bank 0 Enable */
+#define MDCNFG_DE1     (1 << 1)        /* SDRAM Bank 1 Enable */
+#define MDCNFG_DE2     (1 << 16)       /* SDRAM Bank 2 Enable */
+#define MDCNFG_DE3     (1 << 17)       /* SDRAM Bank 3 Enable */
+
 #define MDREFR_K0DB4   (1 << 29)       /* SDCLK0 Divide by 4 Control/Status */
 #define MDREFR_K2FREE  (1 << 25)       /* SDRAM Free-Running Control */
 #define MDREFR_K1FREE  (1 << 24)       /* SDRAM Free-Running Control */
 #define OSCC_OON       (1 << 1)        /* 32.768kHz OON (write-once only bit) */
 #define OSCC_OOK       (1 << 0)        /* 32.768kHz OOK (read-only bit) */
 
+/* PWRMODE register M field values */
+
+#define PWRMODE_IDLE           0x1
+#define PWRMODE_STANDBY                0x2
+#define PWRMODE_SLEEP          0x3
+#define PWRMODE_DEEPSLEEP      0x7
+
 #endif
index cbda4d35c42130d44eca008fce11cc03ac9f9ba2..6932720ba04e39deea7c7f25fdea94316b2feb68 100644 (file)
@@ -48,6 +48,7 @@
 #define LCD_MONO_DSTN_8BPP     ((8  << 4) | LCD_TYPE_MONO_DSTN)
 #define LCD_COLOR_STN_8BPP     ((8  << 4) | LCD_TYPE_COLOR_STN)
 #define LCD_COLOR_DSTN_16BPP   ((16 << 4) | LCD_TYPE_COLOR_DSTN)
+#define LCD_COLOR_TFT_8BPP     ((8  << 4) | LCD_TYPE_COLOR_TFT)
 #define LCD_COLOR_TFT_16BPP    ((16 << 4) | LCD_TYPE_COLOR_TFT)
 #define LCD_COLOR_TFT_18BPP    ((18 << 4) | LCD_TYPE_COLOR_TFT)
 #define LCD_SMART_PANEL_8BPP   ((8  << 4) | LCD_TYPE_SMART_PANEL)
@@ -94,6 +95,10 @@ struct pxafb_mode_info {
         *    in pxa27x and pxa3xx, initialize them to the same value or
         *    the larger one will be used
         * 3. same to {rd,wr}_pulse_width
+        *
+        * 4. LCD_PCLK_EDGE_{RISE,FALL} controls the L_PCLK_WR polarity
+        * 5. sync & FB_SYNC_HOR_HIGH_ACT controls the L_LCLK_A0
+        * 6. sync & FB_SYNC_VERT_HIGH_ACT controls the L_LCLK_RD
         */
        unsigned        a0csrd_set_hld; /* A0 and CS Setup/Hold Time before/after L_FCLK_RD */
        unsigned        a0cswr_set_hld; /* A0 and CS Setup/Hold Time before/after L_PCLK_WR */
@@ -108,6 +113,7 @@ struct pxafb_mach_info {
        unsigned int num_modes;
 
        unsigned int    lcd_conn;
+       unsigned long   video_mem_size;
 
        u_int           fixed_modes:1,
                        cmap_inverse:1,
diff --git a/arch/arm/mach-pxa/include/mach/regs-ac97.h b/arch/arm/mach-pxa/include/mach/regs-ac97.h
new file mode 100644 (file)
index 0000000..e41b9d2
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef __ASM_ARCH_REGS_AC97_H
+#define __ASM_ARCH_REGS_AC97_H
+
+/*
+ * AC97 Controller registers
+ */
+
+#define POCR           __REG(0x40500000)  /* PCM Out Control Register */
+#define POCR_FEIE      (1 << 3)        /* FIFO Error Interrupt Enable */
+#define POCR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
+
+#define PICR           __REG(0x40500004)  /* PCM In Control Register */
+#define PICR_FEIE      (1 << 3)        /* FIFO Error Interrupt Enable */
+#define PICR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
+
+#define MCCR           __REG(0x40500008)  /* Mic In Control Register */
+#define MCCR_FEIE      (1 << 3)        /* FIFO Error Interrupt Enable */
+#define MCCR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
+
+#define GCR            __REG(0x4050000C)  /* Global Control Register */
+#ifdef CONFIG_PXA3xx
+#define GCR_CLKBPB     (1 << 31)       /* Internal clock enable */
+#endif
+#define GCR_nDMAEN     (1 << 24)       /* non DMA Enable */
+#define GCR_CDONE_IE   (1 << 19)       /* Command Done Interrupt Enable */
+#define GCR_SDONE_IE   (1 << 18)       /* Status Done Interrupt Enable */
+#define GCR_SECRDY_IEN (1 << 9)        /* Secondary Ready Interrupt Enable */
+#define GCR_PRIRDY_IEN (1 << 8)        /* Primary Ready Interrupt Enable */
+#define GCR_SECRES_IEN (1 << 5)        /* Secondary Resume Interrupt Enable */
+#define GCR_PRIRES_IEN (1 << 4)        /* Primary Resume Interrupt Enable */
+#define GCR_ACLINK_OFF (1 << 3)        /* AC-link Shut Off */
+#define GCR_WARM_RST   (1 << 2)        /* AC97 Warm Reset */
+#define GCR_COLD_RST   (1 << 1)        /* AC'97 Cold Reset (0 = active) */
+#define GCR_GIE                (1 << 0)        /* Codec GPI Interrupt Enable */
+
+#define POSR           __REG(0x40500010)  /* PCM Out Status Register */
+#define POSR_FIFOE     (1 << 4)        /* FIFO error */
+#define POSR_FSR       (1 << 2)        /* FIFO Service Request */
+
+#define PISR           __REG(0x40500014)  /* PCM In Status Register */
+#define PISR_FIFOE     (1 << 4)        /* FIFO error */
+#define PISR_EOC       (1 << 3)        /* DMA End-of-Chain (exclusive clear) */
+#define PISR_FSR       (1 << 2)        /* FIFO Service Request */
+
+#define MCSR           __REG(0x40500018)  /* Mic In Status Register */
+#define MCSR_FIFOE     (1 << 4)        /* FIFO error */
+#define MCSR_EOC       (1 << 3)        /* DMA End-of-Chain (exclusive clear) */
+#define MCSR_FSR       (1 << 2)        /* FIFO Service Request */
+
+#define GSR            __REG(0x4050001C)  /* Global Status Register */
+#define GSR_CDONE      (1 << 19)       /* Command Done */
+#define GSR_SDONE      (1 << 18)       /* Status Done */
+#define GSR_RDCS       (1 << 15)       /* Read Completion Status */
+#define GSR_BIT3SLT12  (1 << 14)       /* Bit 3 of slot 12 */
+#define GSR_BIT2SLT12  (1 << 13)       /* Bit 2 of slot 12 */
+#define GSR_BIT1SLT12  (1 << 12)       /* Bit 1 of slot 12 */
+#define GSR_SECRES     (1 << 11)       /* Secondary Resume Interrupt */
+#define GSR_PRIRES     (1 << 10)       /* Primary Resume Interrupt */
+#define GSR_SCR                (1 << 9)        /* Secondary Codec Ready */
+#define GSR_PCR                (1 << 8)        /*  Primary Codec Ready */
+#define GSR_MCINT      (1 << 7)        /* Mic In Interrupt */
+#define GSR_POINT      (1 << 6)        /* PCM Out Interrupt */
+#define GSR_PIINT      (1 << 5)        /* PCM In Interrupt */
+#define GSR_ACOFFD     (1 << 3)        /* AC-link Shut Off Done */
+#define GSR_MOINT      (1 << 2)        /* Modem Out Interrupt */
+#define GSR_MIINT      (1 << 1)        /* Modem In Interrupt */
+#define GSR_GSCI       (1 << 0)        /* Codec GPI Status Change Interrupt */
+
+#define CAR            __REG(0x40500020)  /* CODEC Access Register */
+#define CAR_CAIP       (1 << 0)        /* Codec Access In Progress */
+
+#define PCDR           __REG(0x40500040)  /* PCM FIFO Data Register */
+#define MCDR           __REG(0x40500060)  /* Mic-in FIFO Data Register */
+
+#define MOCR           __REG(0x40500100)  /* Modem Out Control Register */
+#define MOCR_FEIE      (1 << 3)        /* FIFO Error */
+#define MOCR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
+
+#define MICR           __REG(0x40500108)  /* Modem In Control Register */
+#define MICR_FEIE      (1 << 3)        /* FIFO Error */
+#define MICR_FSRIE     (1 << 1)        /* FIFO Service Request Interrupt Enable */
+
+#define MOSR           __REG(0x40500110)  /* Modem Out Status Register */
+#define MOSR_FIFOE     (1 << 4)        /* FIFO error */
+#define MOSR_FSR       (1 << 2)        /* FIFO Service Request */
+
+#define MISR           __REG(0x40500118)  /* Modem In Status Register */
+#define MISR_FIFOE     (1 << 4)        /* FIFO error */
+#define MISR_EOC       (1 << 3)        /* DMA End-of-Chain (exclusive clear) */
+#define MISR_FSR       (1 << 2)        /* FIFO Service Request */
+
+#define MODR           __REG(0x40500140)  /* Modem FIFO Data Register */
+
+#define PAC_REG_BASE   __REG(0x40500200)  /* Primary Audio Codec */
+#define SAC_REG_BASE   __REG(0x40500300)  /* Secondary Audio Codec */
+#define PMC_REG_BASE   __REG(0x40500400)  /* Primary Modem Codec */
+#define SMC_REG_BASE   __REG(0x40500500)  /* Secondary Modem Codec */
+
+#endif /* __ASM_ARCH_REGS_AC97_H */
index c689c4ea769cbf3892bac3d44134b4324052af8f..f82dcea792d9523f7b25b149a900f6567de43cd5 100644 (file)
 #define LCCR3          (0x00C) /* LCD Controller Control Register 3 */
 #define LCCR4          (0x010) /* LCD Controller Control Register 4 */
 #define LCCR5          (0x014) /* LCD Controller Control Register 5 */
-#define DFBR0          (0x020) /* DMA Channel 0 Frame Branch Register */
-#define DFBR1          (0x024) /* DMA Channel 1 Frame Branch Register */
-#define LCSR           (0x038) /* LCD Controller Status Register */
+#define LCSR           (0x038) /* LCD Controller Status Register 0 */
+#define LCSR1          (0x034) /* LCD Controller Status Register 1 */
 #define LIIDR          (0x03C) /* LCD Controller Interrupt ID Register */
 #define TMEDRGBR       (0x040) /* TMED RGB Seed Register */
 #define TMEDCR         (0x044) /* TMED Control Register */
 
+#define FBR0           (0x020) /* DMA Channel 0 Frame Branch Register */
+#define FBR1           (0x024) /* DMA Channel 1 Frame Branch Register */
+#define FBR2           (0x028) /* DMA Channel 2 Frame Branch Register */
+#define FBR3           (0x02C) /* DMA Channel 2 Frame Branch Register */
+#define FBR4           (0x030) /* DMA Channel 2 Frame Branch Register */
+#define FBR5           (0x110) /* DMA Channel 2 Frame Branch Register */
+#define FBR6           (0x114) /* DMA Channel 2 Frame Branch Register */
+
+#define OVL1C1         (0x050) /* Overlay 1 Control Register 1 */
+#define OVL1C2         (0x060) /* Overlay 1 Control Register 2 */
+#define OVL2C1         (0x070) /* Overlay 2 Control Register 1 */
+#define OVL2C2         (0x080) /* Overlay 2 Control Register 2 */
+
 #define CMDCR          (0x100) /* Command Control Register */
 #define PRSR           (0x104) /* Panel Read Status Register */
 
-#define LCCR3_1BPP     (0 << 24)
-#define LCCR3_2BPP     (1 << 24)
-#define LCCR3_4BPP     (2 << 24)
-#define LCCR3_8BPP     (3 << 24)
-#define LCCR3_16BPP    (4 << 24)
-#define LCCR3_18BPP    (5 << 24)
-#define LCCR3_18BPP_P  (6 << 24)
-#define LCCR3_19BPP    (7 << 24)
-#define LCCR3_19BPP_P  (1 << 29)
-#define LCCR3_24BPP    ((1 << 29) | (1 << 24))
-#define LCCR3_25BPP    ((1 << 29) | (2 << 24))
+#define LCCR3_BPP(x)   ((((x) & 0x7) << 24) | (((x) & 0x8) ? (1 << 29) : 0))
 
 #define LCCR3_PDFOR_0  (0 << 30)
 #define LCCR3_PDFOR_1  (1 << 30)
 #define LCCR4_PAL_FOR_0        (0 << 15)
 #define LCCR4_PAL_FOR_1        (1 << 15)
 #define LCCR4_PAL_FOR_2        (2 << 15)
+#define LCCR4_PAL_FOR_3        (3 << 15)
 #define LCCR4_PAL_FOR_MASK     (3 << 15)
 
 #define FDADR0         (0x200) /* DMA Channel 0 Frame Descriptor Address Register */
-#define FSADR0         (0x204) /* DMA Channel 0 Frame Source Address Register */
-#define FIDR0          (0x208) /* DMA Channel 0 Frame ID Register */
-#define LDCMD0         (0x20C) /* DMA Channel 0 Command Register */
 #define FDADR1         (0x210) /* DMA Channel 1 Frame Descriptor Address Register */
-#define FSADR1         (0x214) /* DMA Channel 1 Frame Source Address Register */
-#define FIDR1          (0x218) /* DMA Channel 1 Frame ID Register */
-#define LDCMD1         (0x21C) /* DMA Channel 1 Command Register */
+#define FDADR2         (0x220) /* DMA Channel 2 Frame Descriptor Address Register */
+#define FDADR3         (0x230) /* DMA Channel 3 Frame Descriptor Address Register */
+#define FDADR4         (0x240) /* DMA Channel 4 Frame Descriptor Address Register */
+#define FDADR5         (0x250) /* DMA Channel 5 Frame Descriptor Address Register */
 #define FDADR6         (0x260) /* DMA Channel 6 Frame Descriptor Address Register */
-#define FSADR6         (0x264) /* DMA Channel 6 Frame Source Address Register */
-#define FIDR6          (0x268) /* DMA Channel 6 Frame ID Register */
 
 #define LCCR0_ENB      (1 << 0)        /* LCD Controller enable */
 #define LCCR0_CMS      (1 << 1)        /* Color/Monochrome Display Select */
 #define LCCR3_PCD      Fld (8, 0)      /* Pixel Clock Divisor */
 #define LCCR3_PixClkDiv(Div)   (((Div) << FShft (LCCR3_PCD)))
 
-#define LCCR3_BPP      Fld (3, 24)     /* Bit Per Pixel */
-#define LCCR3_Bpp(Bpp) (((Bpp) << FShft (LCCR3_BPP)))
-
 #define LCCR3_ACB      Fld (8, 8)      /* AC Bias */
 #define LCCR3_Acb(Acb) (((Acb) << FShft (LCCR3_ACB)))
 
 #define LCSR_RD_ST     (1 << 11)       /* read status */
 #define LCSR_CMD_INT   (1 << 12)       /* command interrupt */
 
+#define LCSR1_IU(x)    (1 << ((x) + 23)) /* Input FIFO underrun */
+#define LCSR1_BS(x)    (1 << ((x) + 15)) /* Branch Status */
+#define LCSR1_EOF(x)   (1 << ((x) + 7))  /* End of Frame Status */
+#define LCSR1_SOF(x)   (1 << ((x) - 1))  /* Start of Frame Status */
+
 #define LDCMD_PAL      (1 << 26)       /* instructs DMA to load palette buffer */
 
+/* overlay control registers */
+#define OVLxC1_PPL(x)  ((((x) - 1) & 0x3ff) << 0)      /* Pixels Per Line */
+#define OVLxC1_LPO(x)  ((((x) - 1) & 0x3ff) << 10)     /* Number of Lines */
+#define OVLxC1_BPP(x)  (((x) & 0xf) << 20)     /* Bits Per Pixel */
+#define OVLxC1_OEN     (1 << 31)               /* Enable bit for Overlay */
+#define OVLxC2_XPOS(x) (((x) & 0x3ff) << 0)    /* Horizontal Position */
+#define OVLxC2_YPOS(x) (((x) & 0x3ff) << 10)   /* Vertical Position */
+#define OVL2C2_PFOR(x) (((x) & 0x7) << 20)     /* Pixel Format */
+
 /* smartpanel related */
 #define PRSR_DATA(x)   ((x) & 0xff)    /* Panel Data */
 #define PRSR_A0                (1 << 8)        /* Read Data Source */
 
 #define SMART_CMD(x)   (SMART_CMD_WRITE_COMMAND | ((x) & 0xff))
 #define SMART_DAT(x)   (SMART_CMD_WRITE_DATA | ((x) & 0xff))
+
+/* SMART_DELAY() is introduced for software controlled delay primitive which
+ * can be inserted between command sequences, unused command 0x6 is used here
+ * and delay ranges from 0ms ~ 255ms
+ */
+#define SMART_CMD_DELAY                (0x6 << 9)
+#define SMART_DELAY(ms)                (SMART_CMD_DELAY | ((ms) & 0xff))
 #endif /* __ASM_ARCH_REGS_LCD_H */
diff --git a/arch/arm/mach-pxa/include/mach/regs-uart.h b/arch/arm/mach-pxa/include/mach/regs-uart.h
new file mode 100644 (file)
index 0000000..55aeb7f
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef __ASM_ARCH_REGS_UART_H
+#define __ASM_ARCH_REGS_UART_H
+
+/*
+ * UARTs
+ */
+
+/* Full Function UART (FFUART) */
+#define FFUART         FFRBR
+#define FFRBR          __REG(0x40100000)  /* Receive Buffer Register (read only) */
+#define FFTHR          __REG(0x40100000)  /* Transmit Holding Register (write only) */
+#define FFIER          __REG(0x40100004)  /* Interrupt Enable Register (read/write) */
+#define FFIIR          __REG(0x40100008)  /* Interrupt ID Register (read only) */
+#define FFFCR          __REG(0x40100008)  /* FIFO Control Register (write only) */
+#define FFLCR          __REG(0x4010000C)  /* Line Control Register (read/write) */
+#define FFMCR          __REG(0x40100010)  /* Modem Control Register (read/write) */
+#define FFLSR          __REG(0x40100014)  /* Line Status Register (read only) */
+#define FFMSR          __REG(0x40100018)  /* Modem Status Register (read only) */
+#define FFSPR          __REG(0x4010001C)  /* Scratch Pad Register (read/write) */
+#define FFISR          __REG(0x40100020)  /* Infrared Selection Register (read/write) */
+#define FFDLL          __REG(0x40100000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
+#define FFDLH          __REG(0x40100004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
+
+/* Bluetooth UART (BTUART) */
+#define BTUART         BTRBR
+#define BTRBR          __REG(0x40200000)  /* Receive Buffer Register (read only) */
+#define BTTHR          __REG(0x40200000)  /* Transmit Holding Register (write only) */
+#define BTIER          __REG(0x40200004)  /* Interrupt Enable Register (read/write) */
+#define BTIIR          __REG(0x40200008)  /* Interrupt ID Register (read only) */
+#define BTFCR          __REG(0x40200008)  /* FIFO Control Register (write only) */
+#define BTLCR          __REG(0x4020000C)  /* Line Control Register (read/write) */
+#define BTMCR          __REG(0x40200010)  /* Modem Control Register (read/write) */
+#define BTLSR          __REG(0x40200014)  /* Line Status Register (read only) */
+#define BTMSR          __REG(0x40200018)  /* Modem Status Register (read only) */
+#define BTSPR          __REG(0x4020001C)  /* Scratch Pad Register (read/write) */
+#define BTISR          __REG(0x40200020)  /* Infrared Selection Register (read/write) */
+#define BTDLL          __REG(0x40200000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
+#define BTDLH          __REG(0x40200004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
+
+/* Standard UART (STUART) */
+#define STUART         STRBR
+#define STRBR          __REG(0x40700000)  /* Receive Buffer Register (read only) */
+#define STTHR          __REG(0x40700000)  /* Transmit Holding Register (write only) */
+#define STIER          __REG(0x40700004)  /* Interrupt Enable Register (read/write) */
+#define STIIR          __REG(0x40700008)  /* Interrupt ID Register (read only) */
+#define STFCR          __REG(0x40700008)  /* FIFO Control Register (write only) */
+#define STLCR          __REG(0x4070000C)  /* Line Control Register (read/write) */
+#define STMCR          __REG(0x40700010)  /* Modem Control Register (read/write) */
+#define STLSR          __REG(0x40700014)  /* Line Status Register (read only) */
+#define STMSR          __REG(0x40700018)  /* Reserved */
+#define STSPR          __REG(0x4070001C)  /* Scratch Pad Register (read/write) */
+#define STISR          __REG(0x40700020)  /* Infrared Selection Register (read/write) */
+#define STDLL          __REG(0x40700000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
+#define STDLH          __REG(0x40700004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
+
+/* Hardware UART (HWUART) */
+#define HWUART         HWRBR
+#define HWRBR          __REG(0x41600000)  /* Receive Buffer Register (read only) */
+#define HWTHR          __REG(0x41600000)  /* Transmit Holding Register (write only) */
+#define HWIER          __REG(0x41600004)  /* Interrupt Enable Register (read/write) */
+#define HWIIR          __REG(0x41600008)  /* Interrupt ID Register (read only) */
+#define HWFCR          __REG(0x41600008)  /* FIFO Control Register (write only) */
+#define HWLCR          __REG(0x4160000C)  /* Line Control Register (read/write) */
+#define HWMCR          __REG(0x41600010)  /* Modem Control Register (read/write) */
+#define HWLSR          __REG(0x41600014)  /* Line Status Register (read only) */
+#define HWMSR          __REG(0x41600018)  /* Modem Status Register (read only) */
+#define HWSPR          __REG(0x4160001C)  /* Scratch Pad Register (read/write) */
+#define HWISR          __REG(0x41600020)  /* Infrared Selection Register (read/write) */
+#define HWFOR          __REG(0x41600024)  /* Receive FIFO Occupancy Register (read only) */
+#define HWABR          __REG(0x41600028)  /* Auto-Baud Control Register (read/write) */
+#define HWACR          __REG(0x4160002C)  /* Auto-Baud Count Register (read only) */
+#define HWDLL          __REG(0x41600000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
+#define HWDLH          __REG(0x41600004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
+
+#define IER_DMAE       (1 << 7)        /* DMA Requests Enable */
+#define IER_UUE                (1 << 6)        /* UART Unit Enable */
+#define IER_NRZE       (1 << 5)        /* NRZ coding Enable */
+#define IER_RTIOE      (1 << 4)        /* Receiver Time Out Interrupt Enable */
+#define IER_MIE                (1 << 3)        /* Modem Interrupt Enable */
+#define IER_RLSE       (1 << 2)        /* Receiver Line Status Interrupt Enable */
+#define IER_TIE                (1 << 1)        /* Transmit Data request Interrupt Enable */
+#define IER_RAVIE      (1 << 0)        /* Receiver Data Available Interrupt Enable */
+
+#define IIR_FIFOES1    (1 << 7)        /* FIFO Mode Enable Status */
+#define IIR_FIFOES0    (1 << 6)        /* FIFO Mode Enable Status */
+#define IIR_TOD                (1 << 3)        /* Time Out Detected */
+#define IIR_IID2       (1 << 2)        /* Interrupt Source Encoded */
+#define IIR_IID1       (1 << 1)        /* Interrupt Source Encoded */
+#define IIR_IP         (1 << 0)        /* Interrupt Pending (active low) */
+
+#define FCR_ITL2       (1 << 7)        /* Interrupt Trigger Level */
+#define FCR_ITL1       (1 << 6)        /* Interrupt Trigger Level */
+#define FCR_RESETTF    (1 << 2)        /* Reset Transmitter FIFO */
+#define FCR_RESETRF    (1 << 1)        /* Reset Receiver FIFO */
+#define FCR_TRFIFOE    (1 << 0)        /* Transmit and Receive FIFO Enable */
+#define FCR_ITL_1      (0)
+#define FCR_ITL_8      (FCR_ITL1)
+#define FCR_ITL_16     (FCR_ITL2)
+#define FCR_ITL_32     (FCR_ITL2|FCR_ITL1)
+
+#define LCR_DLAB       (1 << 7)        /* Divisor Latch Access Bit */
+#define LCR_SB         (1 << 6)        /* Set Break */
+#define LCR_STKYP      (1 << 5)        /* Sticky Parity */
+#define LCR_EPS                (1 << 4)        /* Even Parity Select */
+#define LCR_PEN                (1 << 3)        /* Parity Enable */
+#define LCR_STB                (1 << 2)        /* Stop Bit */
+#define LCR_WLS1       (1 << 1)        /* Word Length Select */
+#define LCR_WLS0       (1 << 0)        /* Word Length Select */
+
+#define LSR_FIFOE      (1 << 7)        /* FIFO Error Status */
+#define LSR_TEMT       (1 << 6)        /* Transmitter Empty */
+#define LSR_TDRQ       (1 << 5)        /* Transmit Data Request */
+#define LSR_BI         (1 << 4)        /* Break Interrupt */
+#define LSR_FE         (1 << 3)        /* Framing Error */
+#define LSR_PE         (1 << 2)        /* Parity Error */
+#define LSR_OE         (1 << 1)        /* Overrun Error */
+#define LSR_DR         (1 << 0)        /* Data Ready */
+
+#define MCR_LOOP       (1 << 4)
+#define MCR_OUT2       (1 << 3)        /* force MSR_DCD in loopback mode */
+#define MCR_OUT1       (1 << 2)        /* force MSR_RI in loopback mode */
+#define MCR_RTS                (1 << 1)        /* Request to Send */
+#define MCR_DTR                (1 << 0)        /* Data Terminal Ready */
+
+#define MSR_DCD                (1 << 7)        /* Data Carrier Detect */
+#define MSR_RI         (1 << 6)        /* Ring Indicator */
+#define MSR_DSR                (1 << 5)        /* Data Set Ready */
+#define MSR_CTS                (1 << 4)        /* Clear To Send */
+#define MSR_DDCD       (1 << 3)        /* Delta Data Carrier Detect */
+#define MSR_TERI       (1 << 2)        /* Trailing Edge Ring Indicator */
+#define MSR_DDSR       (1 << 1)        /* Delta Data Set Ready */
+#define MSR_DCTS       (1 << 0)        /* Delta Clear To Send */
+
+/*
+ * IrSR (Infrared Selection Register)
+ */
+#define STISR_RXPL      (1 << 4)        /* Receive Data Polarity */
+#define STISR_TXPL      (1 << 3)        /* Transmit Data Polarity */
+#define STISR_XMODE     (1 << 2)        /* Transmit Pulse Width Select */
+#define STISR_RCVEIR    (1 << 1)        /* Receiver SIR Enable */
+#define STISR_XMITIR    (1 << 0)        /* Transmitter SIR Enable */
+
+#endif /* __ASM_ARCH_REGS_UART_H */
index b05fc6683c4739a3d9a6454c96f573b20347476b..af6760a50e1ab6a82996b8155bdd088cb8827eb6 100644 (file)
  * published by the Free Software Foundation.
  */
 
+/* Various drivers are still using the constant of CLOCK_TICK_RATE, for
+ * those drivers to at least work, the definition is provided here.
+ *
+ * NOTE: this is no longer accurate when multiple processors and boards
+ * are selected, newer drivers should not depend on this any more.  Use
+ * either the clocksource/clockevent or get this at run-time by calling
+ * get_clock_tick_rate() (as defined in generic.c).
+ */
 
 #if defined(CONFIG_PXA25x)
 /* PXA250/210 timer base */
index 21e3e890af984869ce3ab2346bfbb95c0beda562..f4b029c039571c622a62d9e3a017480c89ce2fc2 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/serial_reg.h>
-#include <mach/pxa-regs.h>
+#include <mach/regs-uart.h>
 #include <asm/mach-types.h>
 
 #define __REG(x)       ((volatile unsigned long *)x)
@@ -35,7 +35,7 @@ static inline void flush(void)
 
 static inline void arch_decomp_setup(void)
 {
-       if (machine_is_littleton())
+       if (machine_is_littleton() || machine_is_intelmote2())
                UART = STUART;
 }
 
index b4d00aba0e3121455f9ce3756df97022d3e6dbda..31da7f3c06f6fa331578218e4cd87306610df780 100644 (file)
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/smc91x.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mfd/da903x.h>
+#include <linux/i2c/max732x.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
 
 #include <mach/pxa-regs.h>
 #include <mach/mfp-pxa300.h>
-#include <mach/gpio.h>
 #include <mach/pxafb.h>
 #include <mach/ssp.h>
 #include <mach/pxa2xx_spi.h>
+#include <mach/i2c.h>
 #include <mach/pxa27x_keypad.h>
 #include <mach/pxa3xx_nand.h>
 #include <mach/littleton.h>
@@ -314,6 +319,73 @@ static void __init littleton_init_nand(void)
 static inline void littleton_init_nand(void) {}
 #endif /* CONFIG_MTD_NAND_PXA3xx || CONFIG_MTD_NAND_PXA3xx_MODULE */
 
+#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
+static struct led_info littleton_da9034_leds[] = {
+       [0] = {
+               .name   = "littleton:keypad1",
+               .flags  = DA9034_LED_RAMP,
+       },
+       [1] = {
+               .name   = "littleton:keypad2",
+               .flags  = DA9034_LED_RAMP,
+       },
+       [2] = {
+               .name   = "littleton:vibra",
+               .flags  = 0,
+       },
+};
+
+static struct da903x_subdev_info littleton_da9034_subdevs[] = {
+       {
+               .name           = "da903x-led",
+               .id             = DA9034_ID_LED_1,
+               .platform_data  = &littleton_da9034_leds[0],
+       }, {
+               .name           = "da903x-led",
+               .id             = DA9034_ID_LED_2,
+               .platform_data  = &littleton_da9034_leds[1],
+       }, {
+               .name           = "da903x-led",
+               .id             = DA9034_ID_VIBRA,
+               .platform_data  = &littleton_da9034_leds[2],
+       }, {
+               .name           = "da903x-backlight",
+               .id             = DA9034_ID_WLED,
+       },
+};
+
+static struct da903x_platform_data littleton_da9034_info = {
+       .num_subdevs    = ARRAY_SIZE(littleton_da9034_subdevs),
+       .subdevs        = littleton_da9034_subdevs,
+};
+
+static struct max732x_platform_data littleton_max7320_info = {
+       .gpio_base      = EXT0_GPIO_BASE,
+};
+
+static struct i2c_board_info littleton_i2c_info[] = {
+       [0] = {
+               .type           = "da9034",
+               .addr           = 0x34,
+               .platform_data  = &littleton_da9034_info,
+               .irq            = gpio_to_irq(mfp_to_gpio(MFP_PIN_GPIO18)),
+       },
+       [1] = {
+               .type           = "max7320",
+               .addr           = 0x50,
+               .platform_data  = &littleton_max7320_info,
+       },
+};
+
+static void __init littleton_init_i2c(void)
+{
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(littleton_i2c_info));
+}
+#else
+static inline void littleton_init_i2c(void) {}
+#endif /* CONFIG_I2C_PXA || CONFIG_I2C_PXA_MODULE */
+
 static void __init littleton_init(void)
 {
        /* initialize MFP configurations */
@@ -326,6 +398,7 @@ static void __init littleton_init(void)
        platform_device_register(&smc91x_device);
 
        littleton_init_spi();
+       littleton_init_i2c();
        littleton_init_lcd();
        littleton_init_keypad();
        littleton_init_nand();
index 519138bc5f85ee6cff05318749f9a0437e79aa22..21b821e1a60d82bc3b2811523e5b164b1af7728d 100644 (file)
@@ -123,6 +123,10 @@ static unsigned long magician_pin_config[] __initdata = {
        GPIO107_GPIO,   /* DS1WM_IRQ */
        GPIO108_GPIO,   /* GSM_READY */
        GPIO115_GPIO,   /* nPEN_IRQ */
+
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
 };
 
 /*
@@ -332,8 +336,7 @@ static struct pxafb_mach_info toppoly_info = {
        .modes           = toppoly_modes,
        .num_modes       = 1,
        .fixed_modes     = 1,
-       .lccr0           = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3           = LCCR3_PixRsEdg,
+       .lcd_conn       = LCD_COLOR_TFT_16BPP,
        .pxafb_lcd_power = toppoly_lcd_power,
 };
 
@@ -341,8 +344,8 @@ static struct pxafb_mach_info samsung_info = {
        .modes           = samsung_modes,
        .num_modes       = 1,
        .fixed_modes     = 1,
-       .lccr0           = LCCR0_LDDALT | LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-       .lccr3           = LCCR3_PixFlEdg,
+       .lcd_conn        = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |\
+                          LCD_ALTERNATE_MAPPING,
        .pxafb_lcd_power = samsung_lcd_power,
 };
 
index f2c7ad8f2b6b1fff6643a0f874f9169fb703fe09..5f224968043c76f101bf63621bb1d4a421f09a12 100644 (file)
@@ -128,6 +128,10 @@ static unsigned long mainstone_pin_config[] = {
        GPIO108_KP_MKOUT_5,
        GPIO96_KP_MKOUT_6,
 
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
+
        /* GPIO */
        GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
 };
index 2061c00c8ead6afd35d276b2f64028b50577fa25..33626de8cbf65be9ce0b91780708f522941025e1 100644 (file)
@@ -38,12 +38,13 @@ struct gpio_desc {
        unsigned        valid           : 1;
        unsigned        can_wakeup      : 1;
        unsigned        keypad_gpio     : 1;
+       unsigned        dir_inverted    : 1;
        unsigned int    mask; /* bit mask in PWER or PKWR */
+       unsigned int    mux_mask; /* bit mask of muxed gpio bits, 0 if no mux */
        unsigned long   config;
 };
 
 static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1];
-static int gpio_nr;
 
 static unsigned long gpdr_lpm[4];
 
@@ -54,7 +55,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
        int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */
        int shft = (gpio & 0xf) << 1;
        int fn = MFP_AF(c);
-       int dir = c & MFP_DIR_OUT;
+       int is_out = (c & MFP_DIR_OUT) ? 1 : 0;
 
        if (fn > 3)
                return -EINVAL;
@@ -68,7 +69,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
        else
                GAFR_U(bank) = gafr;
 
-       if (dir == MFP_DIR_OUT)
+       if (is_out ^ gpio_desc[gpio].dir_inverted)
                GPDR(gpio) |= mask;
        else
                GPDR(gpio) &= ~mask;
@@ -77,11 +78,11 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
        switch (c & MFP_LPM_STATE_MASK) {
        case MFP_LPM_DRIVE_HIGH:
                PGSR(bank) |= mask;
-               dir = MFP_DIR_OUT;
+               is_out = 1;
                break;
        case MFP_LPM_DRIVE_LOW:
                PGSR(bank) &= ~mask;
-               dir = MFP_DIR_OUT;
+               is_out = 1;
                break;
        case MFP_LPM_DEFAULT:
                break;
@@ -92,7 +93,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
                break;
        }
 
-       if (dir == MFP_DIR_OUT)
+       if (is_out ^ gpio_desc[gpio].dir_inverted)
                gpdr_lpm[bank] |= mask;
        else
                gpdr_lpm[bank] &= ~mask;
@@ -106,7 +107,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
                return -EINVAL;
        }
 
-       if ((c & MFP_LPM_CAN_WAKEUP) && (dir == MFP_DIR_OUT)) {
+       if ((c & MFP_LPM_CAN_WAKEUP) && is_out) {
                pr_warning("%s: output GPIO%d unable to wakeup\n",
                                __func__, gpio);
                return -EINVAL;
@@ -169,7 +170,7 @@ void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm)
 int gpio_set_wake(unsigned int gpio, unsigned int on)
 {
        struct gpio_desc *d;
-       unsigned long c;
+       unsigned long c, mux_taken;
 
        if (gpio > mfp_to_gpio(MFP_PIN_GPIO127))
                return -EINVAL;
@@ -183,9 +184,13 @@ int gpio_set_wake(unsigned int gpio, unsigned int on)
        if (d->keypad_gpio)
                return -EINVAL;
 
+       mux_taken = (PWER & d->mux_mask) & (~d->mask);
+       if (on && mux_taken)
+               return -EBUSY;
+
        if (d->can_wakeup && (c & MFP_LPM_CAN_WAKEUP)) {
                if (on) {
-                       PWER |= d->mask;
+                       PWER = (PWER & ~d->mux_mask) | d->mask;
 
                        if (c & MFP_LPM_EDGE_RISE)
                                PRER |= d->mask;
@@ -210,7 +215,7 @@ static void __init pxa25x_mfp_init(void)
 {
        int i;
 
-       for (i = 0; i <= 84; i++)
+       for (i = 0; i <= pxa_last_gpio; i++)
                gpio_desc[i].valid = 1;
 
        for (i = 0; i <= 15; i++) {
@@ -218,7 +223,11 @@ static void __init pxa25x_mfp_init(void)
                gpio_desc[i].mask = GPIO_bit(i);
        }
 
-       gpio_nr = 85;
+       /* PXA26x has additional 4 GPIOs (86/87/88/89) which has the
+        * direction bit inverted in GPDR2. See PXA26x DM 4.1.1.
+        */
+       for (i = 86; i <= pxa_last_gpio; i++)
+               gpio_desc[i].dir_inverted = 1;
 }
 #else
 static inline void pxa25x_mfp_init(void) {}
@@ -251,11 +260,27 @@ int keypad_set_wake(unsigned int on)
        return 0;
 }
 
+#define PWER_WEMUX2_GPIO38     (1 << 16)
+#define PWER_WEMUX2_GPIO53     (2 << 16)
+#define PWER_WEMUX2_GPIO40     (3 << 16)
+#define PWER_WEMUX2_GPIO36     (4 << 16)
+#define PWER_WEMUX2_MASK       (7 << 16)
+#define PWER_WEMUX3_GPIO31     (1 << 19)
+#define PWER_WEMUX3_GPIO113    (2 << 19)
+#define PWER_WEMUX3_MASK       (3 << 19)
+
+#define INIT_GPIO_DESC_MUXED(mux, gpio)                                \
+do {                                                           \
+       gpio_desc[(gpio)].can_wakeup = 1;                       \
+       gpio_desc[(gpio)].mask = PWER_ ## mux ## _GPIO ##gpio;  \
+       gpio_desc[(gpio)].mux_mask = PWER_ ## mux ## _MASK;     \
+} while (0)
+
 static void __init pxa27x_mfp_init(void)
 {
        int i, gpio;
 
-       for (i = 0; i <= 120; i++) {
+       for (i = 0; i <= pxa_last_gpio; i++) {
                /* skip GPIO2, 5, 6, 7, 8, they are not
                 * valid pins allow configuration
                 */
@@ -286,7 +311,12 @@ static void __init pxa27x_mfp_init(void)
        gpio_desc[35].can_wakeup = 1;
        gpio_desc[35].mask = PWER_WE35;
 
-       gpio_nr = 121;
+       INIT_GPIO_DESC_MUXED(WEMUX3, 31);
+       INIT_GPIO_DESC_MUXED(WEMUX3, 113);
+       INIT_GPIO_DESC_MUXED(WEMUX2, 38);
+       INIT_GPIO_DESC_MUXED(WEMUX2, 53);
+       INIT_GPIO_DESC_MUXED(WEMUX2, 40);
+       INIT_GPIO_DESC_MUXED(WEMUX2, 36);
 }
 #else
 static inline void pxa27x_mfp_init(void) {}
@@ -300,7 +330,7 @@ static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state)
 {
        int i;
 
-       for (i = 0; i <= gpio_to_bank(gpio_nr); i++) {
+       for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) {
 
                saved_gafr[0][i] = GAFR_L(i);
                saved_gafr[1][i] = GAFR_U(i);
@@ -315,7 +345,7 @@ static int pxa2xx_mfp_resume(struct sys_device *d)
 {
        int i;
 
-       for (i = 0; i <= gpio_to_bank(gpio_nr); i++) {
+       for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) {
                GAFR_L(i) = saved_gafr[0][i];
                GAFR_U(i) = saved_gafr[1][i];
                GPDR(i * 32) = saved_gpdr[i];
@@ -348,7 +378,7 @@ static int __init pxa2xx_mfp_init(void)
                pxa27x_mfp_init();
 
        /* initialize gafr_run[], pgsr_lpm[] from existing values */
-       for (i = 0; i <= gpio_to_bank(gpio_nr); i++)
+       for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++)
                gpdr_lpm[i] = GPDR(i * 32);
 
        return sysdev_class_register(&pxa2xx_mfp_sysclass);
index 782903fe9c6c2d5900e77efdfe2bc2e664acd4bd..2b427e015b6fac9be73fc6d6b19c4279d8486914 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/irq.h>
 #include <linux/pda_power.h>
 #include <linux/power_supply.h>
-#include <linux/wm97xx.h>
+#include <linux/wm97xx_batt.h>
 #include <linux/mtd/physmap.h>
 
 #include <asm/mach-types.h>
@@ -46,6 +46,9 @@
 #include <mach/mmc.h>
 #include <mach/udc.h>
 #include <mach/pxa27x-udc.h>
+#include <mach/i2c.h>
+#include <mach/camera.h>
+#include <media/soc_camera.h>
 
 #include <mach/mioa701.h>
 
 
 static unsigned long mioa701_pin_config[] = {
        /* Mio global */
-       MIO_CFG_OUT(GPIO9_CHARGE_nEN, AF0, DRIVE_LOW),
+       MIO_CFG_OUT(GPIO9_CHARGE_EN, AF0, DRIVE_LOW),
        MIO_CFG_OUT(GPIO18_POWEROFF, AF0, DRIVE_LOW),
        MFP_CFG_OUT(GPIO3, AF0, DRIVE_HIGH),
        MFP_CFG_OUT(GPIO4, AF0, DRIVE_HIGH),
+       MIO_CFG_IN(GPIO80_MAYBE_CHARGE_VDROP, AF0),
 
        /* Backlight PWM 0 */
        GPIO16_PWM0_OUT,
@@ -74,7 +78,7 @@ static unsigned long mioa701_pin_config[] = {
        MIO_CFG_OUT(GPIO91_SDIO_EN, AF0, DRIVE_LOW),
 
        /* USB */
-       MIO_CFG_IN(GPIO13_USB_DETECT, AF0),
+       MIO_CFG_IN(GPIO13_nUSB_DETECT, AF0),
        MIO_CFG_OUT(GPIO22_USB_ENABLE, AF0, DRIVE_LOW),
 
        /* LCD */
@@ -98,12 +102,29 @@ static unsigned long mioa701_pin_config[] = {
        GPIO75_LCD_LCLK,
        GPIO76_LCD_PCLK,
 
+       /* QCI */
+       GPIO12_CIF_DD_7,
+       GPIO17_CIF_DD_6,
+       GPIO50_CIF_DD_3,
+       GPIO51_CIF_DD_2,
+       GPIO52_CIF_DD_4,
+       GPIO53_CIF_MCLK,
+       GPIO54_CIF_PCLK,
+       GPIO55_CIF_DD_1,
+       GPIO81_CIF_DD_0,
+       GPIO82_CIF_DD_5,
+       GPIO84_CIF_FV,
+       GPIO85_CIF_LV,
+
        /* Bluetooth */
+       MIO_CFG_IN(GPIO14_BT_nACTIVITY, AF0),
        GPIO44_BTUART_CTS,
        GPIO42_BTUART_RXD,
        GPIO45_BTUART_RTS,
        GPIO43_BTUART_TXD,
        MIO_CFG_OUT(GPIO83_BT_ON, AF0, DRIVE_LOW),
+       MIO_CFG_OUT(GPIO77_BT_UNKNOWN1, AF0, DRIVE_HIGH),
+       MIO_CFG_OUT(GPIO86_BT_MAYBE_nRESET, AF0, DRIVE_HIGH),
 
        /* GPS */
        MIO_CFG_OUT(GPIO23_GPS_UNKNOWN1, AF0, DRIVE_LOW),
@@ -151,16 +172,16 @@ static unsigned long mioa701_pin_config[] = {
        GPIO104_KP_MKOUT_1,
        GPIO105_KP_MKOUT_2,
 
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
+
        /* Unknown */
-       MFP_CFG_IN(GPIO14, AF0),
        MFP_CFG_IN(GPIO20, AF0),
        MFP_CFG_IN(GPIO21, AF0),
        MFP_CFG_IN(GPIO33, AF0),
        MFP_CFG_OUT(GPIO49, AF0, DRIVE_HIGH),
        MFP_CFG_OUT(GPIO57, AF0, DRIVE_HIGH),
-       MFP_CFG_OUT(GPIO77, AF0, DRIVE_HIGH),
-       MFP_CFG_IN(GPIO80, AF0),
-       MFP_CFG_OUT(GPIO86, AF0, DRIVE_HIGH),
        MFP_CFG_IN(GPIO96, AF0),
        MFP_CFG_OUT(GPIO116, AF0, DRIVE_HIGH),
 };
@@ -407,7 +428,7 @@ static void udc_power_command(int cmd)
 
 static int is_usb_connected(void)
 {
-       return !!gpio_get_value(GPIO13_USB_DETECT);
+       return !gpio_get_value(GPIO13_nUSB_DETECT);
 }
 
 static struct pxa2xx_udc_mach_info mioa701_udc_info = {
@@ -659,13 +680,19 @@ static char *supplicants[] = {
        "mioa701_battery"
 };
 
+static int is_ac_connected(void)
+{
+       return gpio_get_value(GPIO96_AC_DETECT);
+}
+
 static void mioa701_set_charge(int flags)
 {
-       gpio_set_value(GPIO9_CHARGE_nEN, !flags);
+       gpio_set_value(GPIO9_CHARGE_EN, (flags == PDA_POWER_CHARGE_USB));
 }
 
 static struct pda_power_pdata power_pdata = {
-       .is_ac_online   = is_usb_connected,
+       .is_ac_online   = is_ac_connected,
+       .is_usb_online  = is_usb_connected,
        .set_charge = mioa701_set_charge,
        .supplied_to = supplicants,
        .num_supplicants = ARRAY_SIZE(supplicants),
@@ -674,8 +701,15 @@ static struct pda_power_pdata power_pdata = {
 static struct resource power_resources[] = {
        [0] = {
                .name   = "ac",
-               .start  = gpio_to_irq(GPIO13_USB_DETECT),
-               .end    = gpio_to_irq(GPIO13_USB_DETECT),
+               .start  = gpio_to_irq(GPIO96_AC_DETECT),
+               .end    = gpio_to_irq(GPIO96_AC_DETECT),
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+               IORESOURCE_IRQ_LOWEDGE,
+       },
+       [1] = {
+               .name   = "usb",
+               .start  = gpio_to_irq(GPIO13_nUSB_DETECT),
+               .end    = gpio_to_irq(GPIO13_nUSB_DETECT),
                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
                IORESOURCE_IRQ_LOWEDGE,
        },
@@ -691,120 +725,43 @@ static struct platform_device power_dev = {
        },
 };
 
-#if defined(CONFIG_PDA_POWER) && defined(CONFIG_TOUCHSCREEN_WM97XX)
-static struct wm97xx *battery_wm;
-
-static enum power_supply_property battery_props[] = {
-       POWER_SUPPLY_PROP_STATUS,
-       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
-       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
-       POWER_SUPPLY_PROP_VOLTAGE_NOW,
-       POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,   /* Necessary for apm */
+static struct wm97xx_batt_info mioa701_battery_data = {
+       .batt_aux       = WM97XX_AUX_ID1,
+       .temp_aux       = -1,
+       .charge_gpio    = -1,
+       .min_voltage    = 0xc00,
+       .max_voltage    = 0xfc0,
+       .batt_tech      = POWER_SUPPLY_TECHNOLOGY_LION,
+       .batt_div       = 1,
+       .batt_mult      = 1,
+       .batt_name      = "mioa701_battery",
 };
 
-static int get_battery_voltage(void)
-{
-       int adc = -1;
-
-       if (battery_wm)
-               adc = wm97xx_read_aux_adc(battery_wm, WM97XX_AUX_ID1);
-       return adc;
-}
-
-static int get_battery_status(struct power_supply *b)
-{
-       int status;
-
-       if (is_usb_connected())
-               status = POWER_SUPPLY_STATUS_CHARGING;
-       else
-               status = POWER_SUPPLY_STATUS_DISCHARGING;
-
-       return status;
-}
-
-static int get_property(struct power_supply *b,
-                       enum power_supply_property psp,
-                       union power_supply_propval *val)
-{
-       int rc = 0;
-
-       switch (psp) {
-       case POWER_SUPPLY_PROP_STATUS:
-               val->intval = get_battery_status(b);
-               break;
-       case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
-               val->intval = 0xfd0;
-               break;
-       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-               val->intval = 0xc00;
-               break;
-       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-               val->intval = get_battery_voltage();
-               break;
-       case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
-               val->intval = 100;
-               break;
-       default:
-               val->intval = -1;
-               rc = -1;
-       }
-
-       return rc;
+/*
+ * Camera interface
+ */
+struct pxacamera_platform_data mioa701_pxacamera_platform_data = {
+       .flags  = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 |
+               PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN,
+       .mclk_10khz = 5000,
 };
 
-static struct power_supply battery_ps = {
-       .name = "mioa701_battery",
-       .type = POWER_SUPPLY_TYPE_BATTERY,
-       .get_property = get_property,
-       .properties = battery_props,
-       .num_properties = ARRAY_SIZE(battery_props),
+static struct soc_camera_link iclink = {
+       .bus_id = 0, /* Must match id in pxa27x_device_camera in device.c */
 };
 
-static int battery_probe(struct platform_device *pdev)
-{
-       struct wm97xx *wm = platform_get_drvdata(pdev);
-       int rc;
-
-       battery_wm = wm;
-
-       rc = power_supply_register(NULL, &battery_ps);
-       if (rc)
-               dev_err(&pdev->dev,
-               "Could not register mioa701 battery -> %d\n", rc);
-       return rc;
-}
-
-static int battery_remove(struct platform_device *pdev)
-{
-       battery_wm = NULL;
-       return 0;
-}
-
-static struct platform_driver mioa701_battery_driver = {
-       .driver = {
-               .name = "wm97xx-battery",
+/* Board I2C devices. */
+static struct i2c_board_info __initdata mioa701_i2c_devices[] = {
+       {
+               /* Must initialize before the camera(s) */
+               I2C_BOARD_INFO("mt9m111", 0x5d),
+               .platform_data = &iclink,
        },
-       .probe = battery_probe,
-       .remove = battery_remove
 };
 
-static int __init mioa701_battery_init(void)
-{
-       int rc;
-
-       rc = platform_driver_register(&mioa701_battery_driver);
-       if (rc)
-               printk(KERN_ERR "Could not register mioa701 battery driver\n");
-       return rc;
-}
-
-#else
-static int __init mioa701_battery_init(void)
-{
-       return 0;
-}
-#endif
+struct i2c_pxa_platform_data i2c_pdata = {
+       .fast_mode = 1,
+};
 
 /*
  * Mio global
@@ -851,17 +808,17 @@ static void mioa701_machine_exit(void);
 static void mioa701_poweroff(void)
 {
        mioa701_machine_exit();
-       gpio_set_value(GPIO18_POWEROFF, 1);
+       arm_machine_restart('s');
 }
 
 static void mioa701_restart(char c)
 {
        mioa701_machine_exit();
-       arm_machine_restart(c);
+       arm_machine_restart('s');
 }
 
 struct gpio_ress global_gpios[] = {
-       MIO_GPIO_OUT(GPIO9_CHARGE_nEN, 1, "Charger enable"),
+       MIO_GPIO_OUT(GPIO9_CHARGE_EN, 1, "Charger enable"),
        MIO_GPIO_OUT(GPIO18_POWEROFF, 0, "Power Off"),
        MIO_GPIO_OUT(GPIO87_LCD_POWER, 0, "LCD Power")
 };
@@ -879,12 +836,16 @@ static void __init mioa701_machine_init(void)
        set_pxa_fb_info(&mioa701_pxafb_info);
        pxa_set_mci_info(&mioa701_mci_info);
        pxa_set_keypad_info(&mioa701_keypad_info);
+       wm97xx_bat_set_pdata(&mioa701_battery_data);
        udc_init();
        pm_power_off = mioa701_poweroff;
        arm_pm_restart = mioa701_restart;
        platform_add_devices(devices, ARRAY_SIZE(devices));
        gsm_init();
-       mioa701_battery_init();
+
+       pxa_set_i2c_info(&i2c_pdata);
+       pxa_set_camera_info(&mioa701_pxacamera_platform_data);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(mioa701_i2c_devices));
 }
 
 static void mioa701_machine_exit(void)
index b36cec5c9eed528b1d595fe1b4085a5dfcd7dccc..34841c72815f6b15c2ffff1bbee04a03e32dd6bf 100644 (file)
@@ -55,6 +55,10 @@ static unsigned long pcm990_pin_config[] __initdata = {
        GPIO89_USBH1_PEN,
        /* PWM0 */
        GPIO16_PWM0_OUT,
+
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
 };
 
 /*
@@ -100,8 +104,7 @@ static struct pxafb_mode_info fb_info_sharp_lq084v1dg21 = {
 static struct pxafb_mach_info pcm990_fbinfo __initdata = {
        .modes                  = &fb_info_sharp_lq084v1dg21,
        .num_modes              = 1,
-       .lccr0                  = LCCR0_PAS,
-       .lccr3                  = LCCR3_PCP,
+       .lcd_conn               = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
        .pxafb_lcd_power        = pcm990_lcd_power,
 };
 #elif defined(CONFIG_PCM990_DISPLAY_NEC)
@@ -123,8 +126,7 @@ struct pxafb_mode_info fb_info_nec_nl6448bc20_18d = {
 static struct pxafb_mach_info pcm990_fbinfo __initdata = {
        .modes                  = &fb_info_nec_nl6448bc20_18d,
        .num_modes              = 1,
-       .lccr0                  = LCCR0_Act,
-       .lccr3                  = LCCR3_PixFlEdg,
+       .lcd_conn               = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
        .pxafb_lcd_power        = pcm990_lcd_power,
 };
 #endif
index 2e3bd8b1523b0e897acbc91b3e54cc91dd232b9c..ae88855bf97461b1851b78b0a1c64786740880f1 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/fb.h>
 #include <linux/pm.h>
 #include <linux/delay.h>
+#include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -413,9 +414,40 @@ static struct pxafb_mach_info poodle_fb_info = {
        .lcd_conn       = LCD_COLOR_TFT_16BPP,
 };
 
+static struct mtd_partition sharpsl_rom_parts[] = {
+       {
+               .name   ="Boot PROM Filesystem",
+               .offset = 0x00120000,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data sharpsl_rom_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(sharpsl_rom_parts),
+       .parts          = sharpsl_rom_parts,
+};
+
+static struct resource sharpsl_rom_resources[] = {
+       {
+               .start  = 0x00000000,
+               .end    = 0x007fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device sharpsl_rom_device = {
+       .name   = "physmap-flash",
+       .id     = -1,
+       .resource = sharpsl_rom_resources,
+       .num_resources = ARRAY_SIZE(sharpsl_rom_resources),
+       .dev.platform_data = &sharpsl_rom_data,
+};
+
 static struct platform_device *devices[] __initdata = {
        &poodle_locomo_device,
        &poodle_scoop_device,
+       &sharpsl_rom_device,
 };
 
 static void poodle_poweroff(void)
index 74e2ead8cee80fa7f52ca7d7e40b64ce8005fc00..3ca7ffc6904b04ebdb80b74b8408e0ea9f610ab4 100644 (file)
@@ -173,7 +173,7 @@ static struct pwm_device *pwm_probe(struct platform_device *pdev,
                return ERR_PTR(-ENOMEM);
        }
 
-       pwm->clk = clk_get(&pdev->dev, "PWMCLK");
+       pwm->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(pwm->clk)) {
                ret = PTR_ERR(pwm->clk);
                goto err_free;
index 25d17a1dab78bd68606224d233e6660960de0300..6c57522e24692c0b2327bf9f63a858077a172e65 100644 (file)
 #include "devices.h"
 #include "clock.h"
 
-int cpu_is_pxa26x(void)
-{
-       return cpu_is_pxa250() && ((BOOT_DEF & 0x8) == 0);
-}
-EXPORT_SYMBOL_GPL(cpu_is_pxa26x);
-
 /*
  * Various clock factors driven by the CCCR register.
  */
@@ -167,36 +161,51 @@ static const struct clkops clk_pxa25x_gpio11_ops = {
  * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
  * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
  */
-static struct clk pxa25x_hwuart_clk =
-       INIT_CKEN("UARTCLK", HWUART, 14745600, 1, &pxa_device_hwuart.dev)
-;
+static DEFINE_CKEN(pxa25x_hwuart, HWUART, 14745600, 1);
+
+static struct clk_lookup pxa25x_hwuart_clkreg =
+       INIT_CLKREG(&clk_pxa25x_hwuart, "pxa2xx-uart.3", NULL);
 
 /*
  * PXA 2xx clock declarations.
  */
-static struct clk pxa25x_clks[] = {
-       INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev),
-       INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev),
-       INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
-       INIT_CKEN("UARTCLK", STUART, 14745600, 1, NULL),
-       INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa25x_device_udc.dev),
-       INIT_CLK("GPIO11_CLK", &clk_pxa25x_gpio11_ops, 3686400, 0, NULL),
-       INIT_CLK("GPIO12_CLK", &clk_pxa25x_gpio12_ops, 32768, 0, NULL),
-       INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
-       INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev),
-
-       INIT_CKEN("SSPCLK",  SSP, 3686400, 0, &pxa25x_device_ssp.dev),
-       INIT_CKEN("SSPCLK", NSSP, 3686400, 0, &pxa25x_device_nssp.dev),
-       INIT_CKEN("SSPCLK", ASSP, 3686400, 0, &pxa25x_device_assp.dev),
-       INIT_CKEN("PWMCLK", PWM0, 3686400, 0, &pxa25x_device_pwm0.dev),
-       INIT_CKEN("PWMCLK", PWM1, 3686400, 0, &pxa25x_device_pwm1.dev),
-
-       INIT_CKEN("AC97CLK",     AC97,     24576000, 0, NULL),
-
-       /*
-       INIT_CKEN("I2SCLK",  I2S,  14745600, 0, NULL),
-       */
-       INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL),
+static DEFINE_CK(pxa25x_lcd, LCD, &clk_pxa25x_lcd_ops);
+static DEFINE_CKEN(pxa25x_ffuart, FFUART, 14745600, 1);
+static DEFINE_CKEN(pxa25x_btuart, BTUART, 14745600, 1);
+static DEFINE_CKEN(pxa25x_stuart, STUART, 14745600, 1);
+static DEFINE_CKEN(pxa25x_usb, USB, 47923000, 5);
+static DEFINE_CLK(pxa25x_gpio11, &clk_pxa25x_gpio11_ops, 3686400, 0);
+static DEFINE_CLK(pxa25x_gpio12, &clk_pxa25x_gpio12_ops, 32768, 0);
+static DEFINE_CKEN(pxa25x_mmc, MMC, 19169000, 0);
+static DEFINE_CKEN(pxa25x_i2c, I2C, 31949000, 0);
+static DEFINE_CKEN(pxa25x_ssp, SSP, 3686400, 0);
+static DEFINE_CKEN(pxa25x_nssp, NSSP, 3686400, 0);
+static DEFINE_CKEN(pxa25x_assp, ASSP, 3686400, 0);
+static DEFINE_CKEN(pxa25x_pwm0, PWM0, 3686400, 0);
+static DEFINE_CKEN(pxa25x_pwm1, PWM1, 3686400, 0);
+static DEFINE_CKEN(pxa25x_ac97, AC97, 24576000, 0);
+static DEFINE_CKEN(pxa25x_i2s, I2S, 14745600, 0);
+static DEFINE_CKEN(pxa25x_ficp, FICP, 47923000, 0);
+
+static struct clk_lookup pxa25x_clkregs[] = {
+       INIT_CLKREG(&clk_pxa25x_lcd, "pxa2xx-fb", NULL),
+       INIT_CLKREG(&clk_pxa25x_ffuart, "pxa2xx-uart.0", NULL),
+       INIT_CLKREG(&clk_pxa25x_btuart, "pxa2xx-uart.1", NULL),
+       INIT_CLKREG(&clk_pxa25x_stuart, "pxa2xx-uart.2", NULL),
+       INIT_CLKREG(&clk_pxa25x_usb, "pxa25x-udc", NULL),
+       INIT_CLKREG(&clk_pxa25x_mmc, "pxa2xx-mci.0", NULL),
+       INIT_CLKREG(&clk_pxa25x_i2c, "pxa2xx-i2c.0", NULL),
+       INIT_CLKREG(&clk_pxa25x_ssp, "pxa25x-ssp.0", NULL),
+       INIT_CLKREG(&clk_pxa25x_nssp, "pxa25x-nssp.1", NULL),
+       INIT_CLKREG(&clk_pxa25x_assp, "pxa25x-nssp.2", NULL),
+       INIT_CLKREG(&clk_pxa25x_pwm0, "pxa25x-pwm.0", NULL),
+       INIT_CLKREG(&clk_pxa25x_pwm1, "pxa25x-pwm.1", NULL),
+       INIT_CLKREG(&clk_pxa25x_i2s, "pxa2xx-i2s", NULL),
+       INIT_CLKREG(&clk_pxa25x_stuart, "pxa2xx-ir", "UARTCLK"),
+       INIT_CLKREG(&clk_pxa25x_ficp, "pxa2xx-ir", "FICPCLK"),
+       INIT_CLKREG(&clk_pxa25x_ac97, NULL, "AC97CLK"),
+       INIT_CLKREG(&clk_pxa25x_gpio11, NULL, "GPIO11_CLK"),
+       INIT_CLKREG(&clk_pxa25x_gpio12, NULL, "GPIO12_CLK"),
 };
 
 #ifdef CONFIG_PM
@@ -304,13 +313,21 @@ void __init pxa25x_init_irq(void)
        pxa_init_gpio(85, pxa25x_set_wake);
 }
 
+#ifdef CONFIG_CPU_PXA26x
+void __init pxa26x_init_irq(void)
+{
+       pxa_init_irq(32, pxa25x_set_wake);
+       pxa_init_gpio(90, pxa25x_set_wake);
+}
+#endif
+
 static struct platform_device *pxa25x_devices[] __initdata = {
        &pxa25x_device_udc,
        &pxa_device_ffuart,
        &pxa_device_btuart,
        &pxa_device_stuart,
        &pxa_device_i2s,
-       &pxa_device_rtc,
+       &sa1100_device_rtc,
        &pxa25x_device_ssp,
        &pxa25x_device_nssp,
        &pxa25x_device_assp,
@@ -336,7 +353,7 @@ static int __init pxa25x_init(void)
 
                reset_status = RCSR;
 
-               clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks));
+               clks_register(pxa25x_clkregs, ARRAY_SIZE(pxa25x_clkregs));
 
                if ((ret = pxa_init_dma(16)))
                        return ret;
@@ -356,8 +373,8 @@ static int __init pxa25x_init(void)
        }
 
        /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */
-       if (cpu_is_pxa255() || cpu_is_pxa26x()) {
-               clks_register(&pxa25x_hwuart_clk, 1);
+       if (cpu_is_pxa255()) {
+               clks_register(&pxa25x_hwuart_clkreg, 1);
                ret = platform_device_register(&pxa_device_hwuart);
        }
 
index 3e4ab2279c99b31c0a9b1c009d55543dc4a93fff..411bec54fdc4b47febc28709c8ffd13b5714b6c0 100644 (file)
@@ -144,40 +144,59 @@ static const struct clkops clk_pxa27x_lcd_ops = {
        .getrate        = clk_pxa27x_lcd_getrate,
 };
 
-static struct clk pxa27x_clks[] = {
-       INIT_CK("LCDCLK", LCD,    &clk_pxa27x_lcd_ops, &pxa_device_fb.dev),
-       INIT_CK("CAMCLK", CAMERA, &clk_pxa27x_lcd_ops, NULL),
-
-       INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
-       INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
-       INIT_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
-
-       INIT_CKEN("I2SCLK",  I2S,  14682000, 0, &pxa_device_i2s.dev),
-       INIT_CKEN("I2CCLK",  I2C,  32842000, 0, &pxa_device_i2c.dev),
-       INIT_CKEN("UDCCLK",  USB,  48000000, 5, &pxa27x_device_udc.dev),
-       INIT_CKEN("MMCCLK",  MMC,  19500000, 0, &pxa_device_mci.dev),
-       INIT_CKEN("FICPCLK", FICP, 48000000, 0, &pxa_device_ficp.dev),
-
-       INIT_CKEN("USBCLK", USBHOST, 48000000, 0, &pxa27x_device_ohci.dev),
-       INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
-       INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, &pxa27x_device_keypad.dev),
-
-       INIT_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
-       INIT_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
-       INIT_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
-       INIT_CKEN("PWMCLK", PWM0, 13000000, 0, &pxa27x_device_pwm0.dev),
-       INIT_CKEN("PWMCLK", PWM1, 13000000, 0, &pxa27x_device_pwm1.dev),
-
-       INIT_CKEN("AC97CLK",     AC97,     24576000, 0, NULL),
-       INIT_CKEN("AC97CONFCLK", AC97CONF, 24576000, 0, NULL),
-
-       /*
-       INIT_CKEN("MSLCLK",  MSL,  48000000, 0, NULL),
-       INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL),
-       INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL),
-       INIT_CKEN("IMCLK",   IM,   0, 0, NULL),
-       INIT_CKEN("MEMCLK",  MEMC, 0, 0, NULL),
-       */
+static DEFINE_CK(pxa27x_lcd, LCD, &clk_pxa27x_lcd_ops);
+static DEFINE_CK(pxa27x_camera, CAMERA, &clk_pxa27x_lcd_ops);
+static DEFINE_CKEN(pxa27x_ffuart, FFUART, 14857000, 1);
+static DEFINE_CKEN(pxa27x_btuart, BTUART, 14857000, 1);
+static DEFINE_CKEN(pxa27x_stuart, STUART, 14857000, 1);
+static DEFINE_CKEN(pxa27x_i2s, I2S, 14682000, 0);
+static DEFINE_CKEN(pxa27x_i2c, I2C, 32842000, 0);
+static DEFINE_CKEN(pxa27x_usb, USB, 48000000, 5);
+static DEFINE_CKEN(pxa27x_mmc, MMC, 19500000, 0);
+static DEFINE_CKEN(pxa27x_ficp, FICP, 48000000, 0);
+static DEFINE_CKEN(pxa27x_usbhost, USBHOST, 48000000, 0);
+static DEFINE_CKEN(pxa27x_pwri2c, PWRI2C, 13000000, 0);
+static DEFINE_CKEN(pxa27x_keypad, KEYPAD, 32768, 0);
+static DEFINE_CKEN(pxa27x_ssp1, SSP1, 13000000, 0);
+static DEFINE_CKEN(pxa27x_ssp2, SSP2, 13000000, 0);
+static DEFINE_CKEN(pxa27x_ssp3, SSP3, 13000000, 0);
+static DEFINE_CKEN(pxa27x_pwm0, PWM0, 13000000, 0);
+static DEFINE_CKEN(pxa27x_pwm1, PWM1, 13000000, 0);
+static DEFINE_CKEN(pxa27x_ac97, AC97, 24576000, 0);
+static DEFINE_CKEN(pxa27x_ac97conf, AC97CONF, 24576000, 0);
+static DEFINE_CKEN(pxa27x_msl, MSL, 48000000, 0);
+static DEFINE_CKEN(pxa27x_usim, USIM, 48000000, 0);
+static DEFINE_CKEN(pxa27x_memstk, MEMSTK, 19500000, 0);
+static DEFINE_CKEN(pxa27x_im, IM, 0, 0);
+static DEFINE_CKEN(pxa27x_memc, MEMC, 0, 0);
+
+static struct clk_lookup pxa27x_clkregs[] = {
+       INIT_CLKREG(&clk_pxa27x_lcd, "pxa2xx-fb", NULL),
+       INIT_CLKREG(&clk_pxa27x_camera, "pxa27x-camera.0", NULL),
+       INIT_CLKREG(&clk_pxa27x_ffuart, "pxa2xx-uart.0", NULL),
+       INIT_CLKREG(&clk_pxa27x_btuart, "pxa2xx-uart.1", NULL),
+       INIT_CLKREG(&clk_pxa27x_stuart, "pxa2xx-uart.2", NULL),
+       INIT_CLKREG(&clk_pxa27x_i2s, "pxa2xx-i2s", NULL),
+       INIT_CLKREG(&clk_pxa27x_i2c, "pxa2xx-i2c.0", NULL),
+       INIT_CLKREG(&clk_pxa27x_usb, "pxa27x-udc", NULL),
+       INIT_CLKREG(&clk_pxa27x_mmc, "pxa2xx-mci.0", NULL),
+       INIT_CLKREG(&clk_pxa27x_stuart, "pxa2xx-ir", "UARTCLK"),
+       INIT_CLKREG(&clk_pxa27x_ficp, "pxa2xx-ir", "FICPCLK"),
+       INIT_CLKREG(&clk_pxa27x_usbhost, "pxa27x-ohci", NULL),
+       INIT_CLKREG(&clk_pxa27x_pwri2c, "pxa2xx-i2c.1", NULL),
+       INIT_CLKREG(&clk_pxa27x_keypad, "pxa27x-keypad", NULL),
+       INIT_CLKREG(&clk_pxa27x_ssp1, "pxa27x-ssp.0", NULL),
+       INIT_CLKREG(&clk_pxa27x_ssp2, "pxa27x-ssp.1", NULL),
+       INIT_CLKREG(&clk_pxa27x_ssp3, "pxa27x-ssp.2", NULL),
+       INIT_CLKREG(&clk_pxa27x_pwm0, "pxa27x-pwm.0", NULL),
+       INIT_CLKREG(&clk_pxa27x_pwm1, "pxa27x-pwm.1", NULL),
+       INIT_CLKREG(&clk_pxa27x_ac97, NULL, "AC97CLK"),
+       INIT_CLKREG(&clk_pxa27x_ac97conf, NULL, "AC97CONFCLK"),
+       INIT_CLKREG(&clk_pxa27x_msl, NULL, "MSLCLK"),
+       INIT_CLKREG(&clk_pxa27x_usim, NULL, "USIMCLK"),
+       INIT_CLKREG(&clk_pxa27x_memstk, NULL, "MSTKCLK"),
+       INIT_CLKREG(&clk_pxa27x_im, NULL, "IMCLK"),
+       INIT_CLKREG(&clk_pxa27x_memc, NULL, "MEMCLK"),
 };
 
 #ifdef CONFIG_PM
@@ -313,38 +332,18 @@ static int pxa27x_set_wake(unsigned int irq, unsigned int on)
 void __init pxa27x_init_irq(void)
 {
        pxa_init_irq(34, pxa27x_set_wake);
-       pxa_init_gpio(128, pxa27x_set_wake);
+       pxa_init_gpio(121, pxa27x_set_wake);
 }
 
 /*
  * device registration specific to PXA27x.
  */
-
-static struct resource i2c_power_resources[] = {
-       {
-               .start  = 0x40f00180,
-               .end    = 0x40f001a3,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_PWRI2C,
-               .end    = IRQ_PWRI2C,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device pxa27x_device_i2c_power = {
-       .name           = "pxa2xx-i2c",
-       .id             = 1,
-       .resource       = i2c_power_resources,
-       .num_resources  = ARRAY_SIZE(i2c_power_resources),
-};
-
 void __init pxa27x_set_i2c_power_info(struct i2c_pxa_platform_data *info)
 {
        local_irq_disable();
        PCFR |= PCFR_PI2CEN;
        local_irq_enable();
-       pxa27x_device_i2c_power.dev.platform_data = info;
+       pxa_register_device(&pxa27x_device_i2c_power, info);
 }
 
 static struct platform_device *devices[] __initdata = {
@@ -353,8 +352,8 @@ static struct platform_device *devices[] __initdata = {
        &pxa_device_btuart,
        &pxa_device_stuart,
        &pxa_device_i2s,
+       &sa1100_device_rtc,
        &pxa_device_rtc,
-       &pxa27x_device_i2c_power,
        &pxa27x_device_ssp1,
        &pxa27x_device_ssp2,
        &pxa27x_device_ssp3,
@@ -380,7 +379,7 @@ static int __init pxa27x_init(void)
 
                reset_status = RCSR;
 
-               clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));
+               clks_register(pxa27x_clkregs, ARRAY_SIZE(pxa27x_clkregs));
 
                if ((ret = pxa_init_dma(32)))
                        return ret;
index 9adc7fc4618aacb561ca6fe9a5ab02df5c942086..f735e58e666997c7c92cd985d812ba6197ea7f76 100644 (file)
@@ -85,14 +85,16 @@ static struct pxa3xx_mfp_addr_map pxa310_mfp_addr_map[] __initdata = {
        MFP_ADDR_END,
 };
 
-static struct clk common_clks[] = {
-       PXA3xx_CKEN("NANDCLK", NAND, 156000000, 0, &pxa3xx_device_nand.dev),
+static DEFINE_PXA3_CKEN(common_nand, NAND, 156000000, 0);
+
+static struct clk_lookup common_clkregs[] = {
+       INIT_CLKREG(&clk_common_nand, "pxa3xx-nand", "NANDCLK"),
 };
 
-static struct clk pxa310_clks[] = {
-#ifdef CONFIG_CPU_PXA310
-       PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
-#endif
+static DEFINE_PXA3_CKEN(pxa310_mmc3, MMC3, 19500000, 0);
+
+static struct clk_lookup pxa310_clkregs[] = {
+       INIT_CLKREG(&clk_pxa310_mmc3, "pxa2xx-mci.2", "MMCCLK"),
 };
 
 static int __init pxa300_init(void)
@@ -100,12 +102,12 @@ static int __init pxa300_init(void)
        if (cpu_is_pxa300() || cpu_is_pxa310()) {
                pxa3xx_init_mfp();
                pxa3xx_mfp_init_addr(pxa300_mfp_addr_map);
-               clks_register(ARRAY_AND_SIZE(common_clks));
+               clks_register(ARRAY_AND_SIZE(common_clkregs));
        }
 
        if (cpu_is_pxa310()) {
                pxa3xx_mfp_init_addr(pxa310_mfp_addr_map);
-               clks_register(ARRAY_AND_SIZE(pxa310_clks));
+               clks_register(ARRAY_AND_SIZE(pxa310_clkregs));
        }
 
        return 0;
index 016eb18f01a3859dc89c1eeebe68900f568e46d5..effe408c186f24b648a02ef5114df14e91e91780 100644 (file)
@@ -80,8 +80,10 @@ static struct pxa3xx_mfp_addr_map pxa320_mfp_addr_map[] __initdata = {
        MFP_ADDR_END,
 };
 
-static struct clk pxa320_clks[] = {
-       PXA3xx_CKEN("NANDCLK", NAND, 104000000, 0, &pxa3xx_device_nand.dev),
+static DEFINE_PXA3_CKEN(pxa320_nand, NAND, 104000000, 0);
+
+static struct clk_lookup pxa320_clkregs[] = {
+       INIT_CLKREG(&clk_pxa320_nand, "pxa3xx-nand", "NANDCLK"),
 };
 
 static int __init pxa320_init(void)
@@ -89,7 +91,7 @@ static int __init pxa320_init(void)
        if (cpu_is_pxa320()) {
                pxa3xx_init_mfp();
                pxa3xx_mfp_init_addr(pxa320_mfp_addr_map);
-               clks_register(ARRAY_AND_SIZE(pxa320_clks));
+               clks_register(ARRAY_AND_SIZE(pxa320_clkregs));
        }
 
        return 0;
index b3cd5d0b0f353e970d58a9f02f49194b2c87529a..490893824e780c028243824500d378fe02c74315 100644 (file)
@@ -29,6 +29,7 @@
 #include <mach/pm.h>
 #include <mach/dma.h>
 #include <mach/ssp.h>
+#include <mach/i2c.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -216,43 +217,58 @@ static const struct clkops clk_dummy_ops = {
        .disable        = clk_dummy_disable,
 };
 
-static struct clk pxa3xx_clks[] = {
-       {
-               .name           = "CLK_POUT",
-               .ops            = &clk_pout_ops,
-               .rate           = 13000000,
-               .delay          = 70,
-       },
-
-       /* Power I2C clock is always on */
-       {
-               .name           = "I2CCLK",
-               .ops            = &clk_dummy_ops,
-               .dev            = &pxa3xx_device_i2c_power.dev,
-       },
-
-       PXA3xx_CK("LCDCLK",  LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
-       PXA3xx_CK("CAMCLK",  CAMERA, &clk_pxa3xx_hsio_ops, NULL),
-       PXA3xx_CK("AC97CLK", AC97,   &clk_pxa3xx_ac97_ops, NULL),
-
-       PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
-       PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
-       PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
-
-       PXA3xx_CKEN("I2CCLK", I2C,  32842000, 0, &pxa_device_i2c.dev),
-       PXA3xx_CKEN("UDCCLK", UDC,  48000000, 5, &pxa27x_device_udc.dev),
-       PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev),
-       PXA3xx_CKEN("KBDCLK", KEYPAD,  32768, 0, &pxa27x_device_keypad.dev),
+static struct clk clk_pxa3xx_pout = {
+       .ops            = &clk_pout_ops,
+       .rate           = 13000000,
+       .delay          = 70,
+};
 
-       PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
-       PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
-       PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
-       PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev),
-       PXA3xx_CKEN("PWMCLK", PWM0, 13000000, 0, &pxa27x_device_pwm0.dev),
-       PXA3xx_CKEN("PWMCLK", PWM1, 13000000, 0, &pxa27x_device_pwm1.dev),
+static struct clk clk_dummy = {
+       .ops            = &clk_dummy_ops,
+};
 
-       PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev),
-       PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev),
+static DEFINE_PXA3_CK(pxa3xx_lcd, LCD, &clk_pxa3xx_hsio_ops);
+static DEFINE_PXA3_CK(pxa3xx_camera, CAMERA, &clk_pxa3xx_hsio_ops);
+static DEFINE_PXA3_CK(pxa3xx_ac97, AC97, &clk_pxa3xx_ac97_ops);
+static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
+static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
+static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
+static DEFINE_PXA3_CKEN(pxa3xx_i2c, I2C, 32842000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_udc, UDC, 48000000, 5);
+static DEFINE_PXA3_CKEN(pxa3xx_usbh, USBH, 48000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_keypad, KEYPAD, 32768, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp1, SSP1, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp2, SSP2, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp3, SSP3, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_ssp4, SSP4, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_pwm0, PWM0, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_pwm1, PWM1, 13000000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_mmc1, MMC1, 19500000, 0);
+static DEFINE_PXA3_CKEN(pxa3xx_mmc2, MMC2, 19500000, 0);
+
+static struct clk_lookup pxa3xx_clkregs[] = {
+       INIT_CLKREG(&clk_pxa3xx_pout, NULL, "CLK_POUT"),
+       /* Power I2C clock is always on */
+       INIT_CLKREG(&clk_dummy, "pxa2xx-i2c.1", NULL),
+       INIT_CLKREG(&clk_pxa3xx_lcd, "pxa2xx-fb", NULL),
+       INIT_CLKREG(&clk_pxa3xx_camera, NULL, "CAMCLK"),
+       INIT_CLKREG(&clk_pxa3xx_ac97, NULL, "AC97CLK"),
+       INIT_CLKREG(&clk_pxa3xx_ffuart, "pxa2xx-uart.0", NULL),
+       INIT_CLKREG(&clk_pxa3xx_btuart, "pxa2xx-uart.1", NULL),
+       INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-uart.2", NULL),
+       INIT_CLKREG(&clk_pxa3xx_stuart, "pxa2xx-ir", "UARTCLK"),
+       INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
+       INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
+       INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
+       INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
+       INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
+       INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),
+       INIT_CLKREG(&clk_pxa3xx_ssp3, "pxa27x-ssp.2", NULL),
+       INIT_CLKREG(&clk_pxa3xx_ssp4, "pxa27x-ssp.3", NULL),
+       INIT_CLKREG(&clk_pxa3xx_pwm0, "pxa27x-pwm.0", NULL),
+       INIT_CLKREG(&clk_pxa3xx_pwm1, "pxa27x-pwm.1", NULL),
+       INIT_CLKREG(&clk_pxa3xx_mmc1, "pxa2xx-mci.0", NULL),
+       INIT_CLKREG(&clk_pxa3xx_mmc2, "pxa2xx-mci.1", NULL),
 };
 
 #ifdef CONFIG_PM
@@ -529,28 +545,9 @@ void __init pxa3xx_init_irq(void)
  * device registration specific to PXA3xx.
  */
 
-static struct resource i2c_power_resources[] = {
-       {
-               .start  = 0x40f500c0,
-               .end    = 0x40f500d3,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = IRQ_PWRI2C,
-               .end    = IRQ_PWRI2C,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device pxa3xx_device_i2c_power = {
-       .name           = "pxa2xx-i2c",
-       .id             = 1,
-       .resource       = i2c_power_resources,
-       .num_resources  = ARRAY_SIZE(i2c_power_resources),
-};
-
 void __init pxa3xx_set_i2c_power_info(struct i2c_pxa_platform_data *info)
 {
-       pxa3xx_device_i2c_power.dev.platform_data = info;
+       pxa_register_device(&pxa3xx_device_i2c_power, info);
 }
 
 static struct platform_device *devices[] __initdata = {
@@ -559,6 +556,7 @@ static struct platform_device *devices[] __initdata = {
        &pxa_device_btuart,
        &pxa_device_stuart,
        &pxa_device_i2s,
+       &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
        &pxa27x_device_ssp2,
@@ -566,7 +564,6 @@ static struct platform_device *devices[] __initdata = {
        &pxa3xx_device_ssp4,
        &pxa27x_device_pwm0,
        &pxa27x_device_pwm1,
-       &pxa3xx_device_i2c_power,
 };
 
 static struct sys_device pxa3xx_sysdev[] = {
@@ -595,7 +592,7 @@ static int __init pxa3xx_init(void)
                 */
                ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
 
-               clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
+               clks_register(pxa3xx_clkregs, ARRAY_SIZE(pxa3xx_clkregs));
 
                if ((ret = pxa_init_dma(32)))
                        return ret;
index e7ea91ce7f02c8da83d78db74368068e6a04c578..5d02a7325586ab3b778cd8f8275fc9ad3774d218 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/i2c.h>
 #include <linux/smc91x.h>
+#include <linux/mfd/da903x.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/pxa3xx-regs.h>
 #include <mach/mfp-pxa930.h>
+#include <mach/i2c.h>
+#include <mach/regs-lcd.h>
+#include <mach/pxafb.h>
 
 #include "devices.h"
 #include "generic.h"
 
+#define GPIO_LCD_RESET (16)
+
 /* SAAR MFP configurations */
 static mfp_cfg_t saar_mfp_cfg[] __initdata = {
+       /* LCD */
+       GPIO23_LCD_DD0,
+       GPIO24_LCD_DD1,
+       GPIO25_LCD_DD2,
+       GPIO26_LCD_DD3,
+       GPIO27_LCD_DD4,
+       GPIO28_LCD_DD5,
+       GPIO29_LCD_DD6,
+       GPIO44_LCD_DD7,
+       GPIO21_LCD_CS,
+       GPIO22_LCD_VSYNC,
+       GPIO17_LCD_FCLK_RD,
+       GPIO18_LCD_LCLK_A0,
+       GPIO19_LCD_PCLK_WR,
+       GPIO16_GPIO, /* LCD reset */
+
        /* Ethernet */
        DF_nCS1_nCS3,
        GPIO97_GPIO,
@@ -64,12 +89,408 @@ static struct platform_device smc91x_device = {
        },
 };
 
+#if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULE)
+static uint16_t lcd_power_on[] = {
+       /* single frame */
+       SMART_CMD_NOOP,
+       SMART_CMD(0x00),
+       SMART_DELAY(0),
+
+       SMART_CMD_NOOP,
+       SMART_CMD(0x00),
+       SMART_DELAY(0),
+
+       SMART_CMD_NOOP,
+       SMART_CMD(0x00),
+       SMART_DELAY(0),
+
+       SMART_CMD_NOOP,
+       SMART_CMD(0x00),
+       SMART_DELAY(10),
+
+       /* calibration control */
+       SMART_CMD(0x00),
+       SMART_CMD(0xA4),
+       SMART_DAT(0x80),
+       SMART_DAT(0x01),
+       SMART_DELAY(150),
+
+       /*Power-On Init sequence*/
+       SMART_CMD(0x00),        /* output ctrl */
+       SMART_CMD(0x01),
+       SMART_DAT(0x01),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* wave ctrl */
+       SMART_CMD(0x02),
+       SMART_DAT(0x07),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x03),        /* entry mode */
+       SMART_DAT(0xD0),
+       SMART_DAT(0x30),
+       SMART_CMD(0x00),
+       SMART_CMD(0x08),        /* display ctrl 2 */
+       SMART_DAT(0x08),
+       SMART_DAT(0x08),
+       SMART_CMD(0x00),
+       SMART_CMD(0x09),        /* display ctrl 3 */
+       SMART_DAT(0x04),
+       SMART_DAT(0x2F),
+       SMART_CMD(0x00),
+       SMART_CMD(0x0A),        /* display ctrl 4 */
+       SMART_DAT(0x00),
+       SMART_DAT(0x08),
+       SMART_CMD(0x00),
+       SMART_CMD(0x0D),        /* Frame Marker position */
+       SMART_DAT(0x00),
+       SMART_DAT(0x08),
+       SMART_CMD(0x00),
+       SMART_CMD(0x60),        /* Driver output control */
+       SMART_DAT(0x27),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x61),        /* Base image display control */
+       SMART_DAT(0x00),
+       SMART_DAT(0x01),
+       SMART_CMD(0x00),
+       SMART_CMD(0x30),        /* Y settings 30h-3Dh */
+       SMART_DAT(0x07),
+       SMART_DAT(0x07),
+       SMART_CMD(0x00),
+       SMART_CMD(0x31),
+       SMART_DAT(0x00),
+       SMART_DAT(0x07),
+       SMART_CMD(0x00),
+       SMART_CMD(0x32),        /* Timing(3), ASW HOLD=0.5CLK */
+       SMART_DAT(0x04),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x33),        /* Timing(4), CKV ST=0CLK, CKV ED=1CLK */
+       SMART_DAT(0x03),
+       SMART_DAT(0x03),
+       SMART_CMD(0x00),
+       SMART_CMD(0x34),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x35),
+       SMART_DAT(0x02),
+       SMART_DAT(0x05),
+       SMART_CMD(0x00),
+       SMART_CMD(0x36),
+       SMART_DAT(0x1F),
+       SMART_DAT(0x1F),
+       SMART_CMD(0x00),
+       SMART_CMD(0x37),
+       SMART_DAT(0x07),
+       SMART_DAT(0x07),
+       SMART_CMD(0x00),
+       SMART_CMD(0x38),
+       SMART_DAT(0x00),
+       SMART_DAT(0x07),
+       SMART_CMD(0x00),
+       SMART_CMD(0x39),
+       SMART_DAT(0x04),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x3A),
+       SMART_DAT(0x03),
+       SMART_DAT(0x03),
+       SMART_CMD(0x00),
+       SMART_CMD(0x3B),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x3C),
+       SMART_DAT(0x02),
+       SMART_DAT(0x05),
+       SMART_CMD(0x00),
+       SMART_CMD(0x3D),
+       SMART_DAT(0x1F),
+       SMART_DAT(0x1F),
+       SMART_CMD(0x00),        /* Display control 1 */
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0x01),
+       SMART_CMD(0x00),        /* Power control 5 */
+       SMART_CMD(0x17),
+       SMART_DAT(0x00),
+       SMART_DAT(0x01),
+       SMART_CMD(0x00),        /* Power control 1 */
+       SMART_CMD(0x10),
+       SMART_DAT(0x10),
+       SMART_DAT(0xB0),
+       SMART_CMD(0x00),        /* Power control 2 */
+       SMART_CMD(0x11),
+       SMART_DAT(0x01),
+       SMART_DAT(0x30),
+       SMART_CMD(0x00),        /* Power control 3 */
+       SMART_CMD(0x12),
+       SMART_DAT(0x01),
+       SMART_DAT(0x9E),
+       SMART_CMD(0x00),        /* Power control 4 */
+       SMART_CMD(0x13),
+       SMART_DAT(0x17),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* Power control 3 */
+       SMART_CMD(0x12),
+       SMART_DAT(0x01),
+       SMART_DAT(0xBE),
+       SMART_DELAY(100),
+
+       /* display mode : 240*320 */
+       SMART_CMD(0x00),        /* RAM address set(H) 0*/
+       SMART_CMD(0x20),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* RAM address set(V)   4*/
+       SMART_CMD(0x21),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* Start of Window RAM address set(H) 8*/
+       SMART_CMD(0x50),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* End of Window RAM address set(H) 12*/
+       SMART_CMD(0x51),
+       SMART_DAT(0x00),
+       SMART_DAT(0xEF),
+       SMART_CMD(0x00),        /* Start of Window RAM address set(V) 16*/
+       SMART_CMD(0x52),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* End of Window RAM address set(V) 20*/
+       SMART_CMD(0x53),
+       SMART_DAT(0x01),
+       SMART_DAT(0x3F),
+       SMART_CMD(0x00),        /* Panel interface control 1 */
+       SMART_CMD(0x90),
+       SMART_DAT(0x00),
+       SMART_DAT(0x1A),
+       SMART_CMD(0x00),        /* Panel interface control 2 */
+       SMART_CMD(0x92),
+       SMART_DAT(0x04),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),        /* Panel interface control 3 */
+       SMART_CMD(0x93),
+       SMART_DAT(0x00),
+       SMART_DAT(0x05),
+       SMART_DELAY(20),
+};
+
+static uint16_t lcd_panel_on[] = {
+       SMART_CMD(0x00),
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0x21),
+       SMART_DELAY(1),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0x61),
+       SMART_DELAY(100),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x07),
+       SMART_DAT(0x01),
+       SMART_DAT(0x73),
+       SMART_DELAY(1),
+};
+
+static uint16_t lcd_panel_off[] = {
+       SMART_CMD(0x00),
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0x72),
+       SMART_DELAY(40),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0x01),
+       SMART_DELAY(1),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_DELAY(1),
+};
+
+static uint16_t lcd_power_off[] = {
+       SMART_CMD(0x00),
+       SMART_CMD(0x10),
+       SMART_DAT(0x00),
+       SMART_DAT(0x80),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x11),
+       SMART_DAT(0x01),
+       SMART_DAT(0x60),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x12),
+       SMART_DAT(0x01),
+       SMART_DAT(0xAE),
+       SMART_DELAY(40),
+
+       SMART_CMD(0x00),
+       SMART_CMD(0x10),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+};
+
+static uint16_t update_framedata[] = {
+       /* set display ram: 240*320 */
+       SMART_CMD(0x00), /* RAM address set(H) 0*/
+       SMART_CMD(0x20),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00), /* RAM address set(V) 4*/
+       SMART_CMD(0x21),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00), /* Start of Window RAM address set(H) 8 */
+       SMART_CMD(0x50),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00), /* End of Window RAM address set(H) 12 */
+       SMART_CMD(0x51),
+       SMART_DAT(0x00),
+       SMART_DAT(0xEF),
+       SMART_CMD(0x00), /* Start of Window RAM address set(V) 16 */
+       SMART_CMD(0x52),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00), /* End of Window RAM address set(V) 20 */
+       SMART_CMD(0x53),
+       SMART_DAT(0x01),
+       SMART_DAT(0x3F),
+
+       /* wait for vsync cmd before transferring frame data */
+       SMART_CMD_WAIT_FOR_VSYNC,
+
+       /* write ram */
+       SMART_CMD(0x00),
+       SMART_CMD(0x22),
+
+       /* write frame data */
+       SMART_CMD_WRITE_FRAME,
+};
+
+static void ltm022a97a_lcd_power(int on, struct fb_var_screeninfo *var)
+{
+       static int pin_requested = 0;
+       struct fb_info *info = container_of(var, struct fb_info, var);
+       int err;
+
+       if (!pin_requested) {
+               err = gpio_request(GPIO_LCD_RESET, "lcd reset");
+               if (err) {
+                       pr_err("failed to request gpio for LCD reset\n");
+                       return;
+               }
+
+               gpio_direction_output(GPIO_LCD_RESET, 0);
+               pin_requested = 1;
+       }
+
+       if (on) {
+               gpio_set_value(GPIO_LCD_RESET, 0); msleep(100);
+               gpio_set_value(GPIO_LCD_RESET, 1); msleep(10);
+
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_power_on));
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_panel_on));
+       } else {
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_panel_off));
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_power_off));
+       }
+
+       err = pxafb_smart_flush(info);
+       if (err)
+               pr_err("%s: timed out\n", __func__);
+}
+
+static void ltm022a97a_update(struct fb_info *info)
+{
+       pxafb_smart_queue(info, ARRAY_AND_SIZE(update_framedata));
+       pxafb_smart_flush(info);
+}
+
+static struct pxafb_mode_info toshiba_ltm022a97a_modes[] = {
+       [0] = {
+               .xres                   = 240,
+               .yres                   = 320,
+               .bpp                    = 16,
+               .a0csrd_set_hld         = 30,
+               .a0cswr_set_hld         = 30,
+               .wr_pulse_width         = 30,
+               .rd_pulse_width         = 30,
+               .op_hold_time           = 30,
+               .cmd_inh_time           = 60,
+
+               /* L_LCLK_A0 and L_LCLK_RD active low */
+               .sync                   = FB_SYNC_HOR_HIGH_ACT |
+                                         FB_SYNC_VERT_HIGH_ACT,
+       },
+};
+
+static struct pxafb_mach_info saar_lcd_info = {
+       .modes                  = toshiba_ltm022a97a_modes,
+       .num_modes              = 1,
+       .lcd_conn               = LCD_SMART_PANEL_8BPP | LCD_PCLK_EDGE_FALL,
+       .pxafb_lcd_power        = ltm022a97a_lcd_power,
+       .smart_update           = ltm022a97a_update,
+};
+
+static void __init saar_init_lcd(void)
+{
+       set_pxa_fb_info(&saar_lcd_info);
+}
+#else
+static inline void saar_init_lcd(void) {}
+#endif
+
+#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
+static struct da903x_subdev_info saar_da9034_subdevs[] = {
+       [0] = {
+               .name           = "da903x-backlight",
+               .id             = DA9034_ID_WLED,
+       },
+};
+
+static struct da903x_platform_data saar_da9034_info = {
+       .num_subdevs    = ARRAY_SIZE(saar_da9034_subdevs),
+       .subdevs        = saar_da9034_subdevs,
+};
+
+static struct i2c_board_info saar_i2c_info[] = {
+       [0] = {
+               .type           = "da9034",
+               .addr           = 0x34,
+               .platform_data  = &saar_da9034_info,
+               .irq            = gpio_to_irq(mfp_to_gpio(MFP_PIN_GPIO83)),
+       },
+};
+
+static void __init saar_init_i2c(void)
+{
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(saar_i2c_info));
+}
+#else
+static inline void saar_init_i2c(void) {}
+#endif
 static void __init saar_init(void)
 {
        /* initialize MFP configurations */
        pxa3xx_mfp_config(ARRAY_AND_SIZE(saar_mfp_cfg));
 
        platform_device_register(&smc91x_device);
+
+       saar_init_i2c();
+       saar_init_lcd();
 }
 
 MACHINE_START(SAAR, "PXA930 Handheld Platform (aka SAAR)")
index ad346addc028b849cec3ab100769475d02f4cd6f..d6f6904132a62328895909c7ab39df69daf26b79 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/io.h>
 #include <linux/sysdev.h>
 
+#include <mach/hardware.h>
+
 #define SMEMC_PHYS_BASE        (0x4A000000)
 #define SMEMC_PHYS_SIZE        (0x90)
 
index 3be76ee2bdbfd759b83eee07151ba7cf7917cc42..7299d87a1cb31f9b33d0ae9deadc2d9e30eab9a3 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/gpio.h>
 #include <linux/leds.h>
 #include <linux/mmc/host.h>
+#include <linux/mtd/physmap.h>
 #include <linux/pm.h>
 #include <linux/backlight.h>
 #include <linux/io.h>
@@ -122,6 +123,10 @@ static unsigned long spitz_pin_config[] __initdata = {
        GPIO105_GPIO,   /* SPITZ_GPIO_CF_IRQ */
        GPIO106_GPIO,   /* SPITZ_GPIO_CF2_IRQ */
 
+       /* I2C */
+       GPIO117_I2C_SCL,
+       GPIO118_I2C_SDA,
+
        GPIO1_GPIO | WAKEUP_ON_EDGE_RISE,
 };
 
@@ -609,10 +614,41 @@ static struct pxafb_mach_info spitz_pxafb_info = {
 };
 
 
+static struct mtd_partition sharpsl_rom_parts[] = {
+       {
+               .name   ="Boot PROM Filesystem",
+               .offset = 0x00140000,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data sharpsl_rom_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(sharpsl_rom_parts),
+       .parts          = sharpsl_rom_parts,
+};
+
+static struct resource sharpsl_rom_resources[] = {
+       {
+               .start  = 0x00000000,
+               .end    = 0x007fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device sharpsl_rom_device = {
+       .name   = "physmap-flash",
+       .id     = -1,
+       .resource = sharpsl_rom_resources,
+       .num_resources = ARRAY_SIZE(sharpsl_rom_resources),
+       .dev.platform_data = &sharpsl_rom_data,
+};
+
 static struct platform_device *devices[] __initdata = {
        &spitzscoop_device,
        &spitzkbd_device,
        &spitzled_device,
+       &sharpsl_rom_device,
 };
 
 static void spitz_poweroff(void)
index 2c31ec72568856019be0482d9dc4fa2a730dcb01..6f42004db3ed1fc398108ad35467cda4612838ae 100644 (file)
@@ -356,7 +356,7 @@ static int __devinit ssp_probe(struct platform_device *pdev, int type)
        }
        ssp->pdev = pdev;
 
-       ssp->clk = clk_get(&pdev->dev, "SSPCLK");
+       ssp->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssp->clk)) {
                ret = PTR_ERR(ssp->clk);
                goto err_free;
index 589d32b4fc46e55c46e822353d216318361da78e..58ef08a5224b566b18331da22d8a04a0d0923973 100644 (file)
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/smc91x.h>
+#include <linux/pwm_backlight.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/pxa3xx-regs.h>
 #include <mach/mfp-pxa930.h>
+#include <mach/pxafb.h>
+#include <mach/pxa27x_keypad.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -33,6 +36,45 @@ static mfp_cfg_t tavorevb_mfp_cfg[] __initdata = {
        /* Ethernet */
        DF_nCS1_nCS3,
        GPIO47_GPIO,
+
+       /* LCD */
+       GPIO23_LCD_DD0,
+       GPIO24_LCD_DD1,
+       GPIO25_LCD_DD2,
+       GPIO26_LCD_DD3,
+       GPIO27_LCD_DD4,
+       GPIO28_LCD_DD5,
+       GPIO29_LCD_DD6,
+       GPIO44_LCD_DD7,
+       GPIO21_LCD_CS,
+       GPIO22_LCD_CS2,
+
+       GPIO17_LCD_FCLK_RD,
+       GPIO18_LCD_LCLK_A0,
+       GPIO19_LCD_PCLK_WR,
+
+       /* LCD Backlight */
+       GPIO43_PWM3,    /* primary backlight */
+       GPIO32_PWM0,    /* secondary backlight */
+
+       /* Keypad */
+       GPIO0_KP_MKIN_0,
+       GPIO2_KP_MKIN_1,
+       GPIO4_KP_MKIN_2,
+       GPIO6_KP_MKIN_3,
+       GPIO8_KP_MKIN_4,
+       GPIO10_KP_MKIN_5,
+       GPIO12_KP_MKIN_6,
+       GPIO1_KP_MKOUT_0,
+       GPIO3_KP_MKOUT_1,
+       GPIO5_KP_MKOUT_2,
+       GPIO7_KP_MKOUT_3,
+       GPIO9_KP_MKOUT_4,
+       GPIO11_KP_MKOUT_5,
+       GPIO13_KP_MKOUT_6,
+
+       GPIO14_KP_DKIN_2,
+       GPIO15_KP_DKIN_3,
 };
 
 #define TAVOREVB_ETH_PHYS      (0x14000000)
@@ -64,12 +106,382 @@ static struct platform_device smc91x_device = {
        },
 };
 
+#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
+static unsigned int tavorevb_matrix_key_map[] = {
+       /* KEY(row, col, key_code) */
+       KEY(0, 4, KEY_A), KEY(0, 5, KEY_B), KEY(0, 6, KEY_C),
+       KEY(1, 4, KEY_E), KEY(1, 5, KEY_F), KEY(1, 6, KEY_G),
+       KEY(2, 4, KEY_I), KEY(2, 5, KEY_J), KEY(2, 6, KEY_K),
+       KEY(3, 4, KEY_M), KEY(3, 5, KEY_N), KEY(3, 6, KEY_O),
+       KEY(4, 5, KEY_R), KEY(4, 6, KEY_S),
+       KEY(5, 4, KEY_U), KEY(5, 4, KEY_V), KEY(5, 6, KEY_W),
+
+       KEY(6, 4, KEY_Y), KEY(6, 5, KEY_Z),
+
+       KEY(0, 3, KEY_0), KEY(2, 0, KEY_1), KEY(2, 1, KEY_2), KEY(2, 2, KEY_3),
+       KEY(2, 3, KEY_4), KEY(1, 0, KEY_5), KEY(1, 1, KEY_6), KEY(1, 2, KEY_7),
+       KEY(1, 3, KEY_8), KEY(0, 2, KEY_9),
+
+       KEY(6, 6, KEY_SPACE),
+       KEY(0, 0, KEY_KPASTERISK),      /* * */
+       KEY(0, 1, KEY_KPDOT),           /* # */
+
+       KEY(4, 1, KEY_UP),
+       KEY(4, 3, KEY_DOWN),
+       KEY(4, 0, KEY_LEFT),
+       KEY(4, 2, KEY_RIGHT),
+       KEY(6, 0, KEY_HOME),
+       KEY(3, 2, KEY_END),
+       KEY(6, 1, KEY_DELETE),
+       KEY(5, 2, KEY_BACK),
+       KEY(6, 3, KEY_CAPSLOCK),        /* KEY_LEFTSHIFT), */
+
+       KEY(4, 4, KEY_ENTER),           /* scroll push */
+       KEY(6, 2, KEY_ENTER),           /* keypad action */
+
+       KEY(3, 1, KEY_SEND),
+       KEY(5, 3, KEY_RECORD),
+       KEY(5, 0, KEY_VOLUMEUP),
+       KEY(5, 1, KEY_VOLUMEDOWN),
+
+       KEY(3, 0, KEY_F22),     /* soft1 */
+       KEY(3, 3, KEY_F23),     /* soft2 */
+};
+
+static struct pxa27x_keypad_platform_data tavorevb_keypad_info = {
+       .matrix_key_rows        = 7,
+       .matrix_key_cols        = 7,
+       .matrix_key_map         = tavorevb_matrix_key_map,
+       .matrix_key_map_size    = ARRAY_SIZE(tavorevb_matrix_key_map),
+       .debounce_interval      = 30,
+};
+
+static void __init tavorevb_init_keypad(void)
+{
+       pxa_set_keypad_info(&tavorevb_keypad_info);
+}
+#else
+static inline void tavorevb_init_keypad(void) {}
+#endif /* CONFIG_KEYBOARD_PXA27x || CONFIG_KEYBOARD_PXA27x_MODULE */
+
+#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static struct platform_pwm_backlight_data tavorevb_backlight_data[] = {
+       [0] = {
+               /* primary backlight */
+               .pwm_id         = 2,
+               .max_brightness = 100,
+               .dft_brightness = 100,
+               .pwm_period_ns  = 100000,
+       },
+       [1] = {
+               /* secondary backlight */
+               .pwm_id         = 0,
+               .max_brightness = 100,
+               .dft_brightness = 100,
+               .pwm_period_ns  = 100000,
+       },
+};
+
+static struct platform_device tavorevb_backlight_devices[] = {
+       [0] = {
+               .name           = "pwm-backlight",
+               .id             = 0,
+               .dev            = {
+                       .platform_data = &tavorevb_backlight_data[0],
+               },
+       },
+       [1] = {
+               .name           = "pwm-backlight",
+               .id             = 1,
+               .dev            = {
+                       .platform_data = &tavorevb_backlight_data[1],
+               },
+       },
+};
+
+static uint16_t panel_init[] = {
+       /* DSTB OUT */
+       SMART_CMD(0x00),
+       SMART_CMD_NOOP,
+       SMART_DELAY(1),
+
+       SMART_CMD(0x00),
+       SMART_CMD_NOOP,
+       SMART_DELAY(1),
+
+       SMART_CMD(0x00),
+       SMART_CMD_NOOP,
+       SMART_DELAY(1),
+
+       /* STB OUT */
+       SMART_CMD(0x00),
+       SMART_CMD(0x1D),
+       SMART_DAT(0x00),
+       SMART_DAT(0x05),
+       SMART_DELAY(1),
+
+       /* P-ON Init sequence */
+       SMART_CMD(0x00), /* OSC ON */
+       SMART_CMD(0x00),
+       SMART_DAT(0x00),
+       SMART_DAT(0x01),
+       SMART_CMD(0x00),
+       SMART_CMD(0x01), /* SOURCE DRIVER SHIFT DIRECTION and display RAM setting */
+       SMART_DAT(0x01),
+       SMART_DAT(0x27),
+       SMART_CMD(0x00),
+       SMART_CMD(0x02), /* LINE INV */
+       SMART_DAT(0x02),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x03), /* IF mode(1) */
+       SMART_DAT(0x01), /* 8bit smart mode(8-8),high speed write mode */
+       SMART_DAT(0x30),
+       SMART_CMD(0x07),
+       SMART_CMD(0x00), /* RAM Write Mode */
+       SMART_DAT(0x00),
+       SMART_DAT(0x03),
+       SMART_CMD(0x00),
+
+       /* DISPLAY Setting,  262K, fixed(NO scroll), no split screen */
+       SMART_CMD(0x07),
+       SMART_DAT(0x40), /* 16/18/19 BPP */
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x08), /* BP, FP Seting, BP=2H, FP=3H */
+       SMART_DAT(0x03),
+       SMART_DAT(0x02),
+       SMART_CMD(0x00),
+       SMART_CMD(0x0C), /* IF mode(2), using internal clock & MPU */
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x0D), /* Frame setting, 1Min. Frequence, 16CLK */
+       SMART_DAT(0x00),
+       SMART_DAT(0x10),
+       SMART_CMD(0x00),
+       SMART_CMD(0x12), /* Timing(1),ASW W=4CLK, ASW ST=1CLK */
+       SMART_DAT(0x03),
+       SMART_DAT(0x02),
+       SMART_CMD(0x00),
+       SMART_CMD(0x13), /* Timing(2),OEV ST=0.5CLK, OEV ED=1CLK */
+       SMART_DAT(0x01),
+       SMART_DAT(0x02),
+       SMART_CMD(0x00),
+       SMART_CMD(0x14), /* Timing(3), ASW HOLD=0.5CLK */
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x15), /* Timing(4), CKV ST=0CLK, CKV ED=1CLK */
+       SMART_DAT(0x20),
+       SMART_DAT(0x00),
+       SMART_CMD(0x00),
+       SMART_CMD(0x1C),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x03),
+       SMART_CMD(0x00),
+       SMART_DAT(0x04),
+       SMART_DAT(0x03),
+       SMART_CMD(0x03),
+       SMART_CMD(0x01),
+       SMART_DAT(0x03),
+       SMART_DAT(0x04),
+       SMART_CMD(0x03),
+       SMART_CMD(0x02),
+       SMART_DAT(0x04),
+       SMART_DAT(0x03),
+       SMART_CMD(0x03),
+       SMART_CMD(0x03),
+       SMART_DAT(0x03),
+       SMART_DAT(0x03),
+       SMART_CMD(0x03),
+       SMART_CMD(0x04),
+       SMART_DAT(0x01),
+       SMART_DAT(0x01),
+       SMART_CMD(0x03),
+       SMART_CMD(0x05),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x04),
+       SMART_CMD(0x02),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x04),
+       SMART_CMD(0x03),
+       SMART_DAT(0x01),
+       SMART_DAT(0x3F),
+       SMART_DELAY(0),
+
+       /* DISP RAM setting: 240*320 */
+       SMART_CMD(0x04), /* HADDR, START 0 */
+       SMART_CMD(0x06),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00), /* x1,3 */
+       SMART_CMD(0x04), /* HADDR,  END   4 */
+       SMART_CMD(0x07),
+       SMART_DAT(0x00),
+       SMART_DAT(0xEF), /* x2, 7 */
+       SMART_CMD(0x04), /* VADDR, START 8 */
+       SMART_CMD(0x08),
+       SMART_DAT(0x00), /* y1, 10 */
+       SMART_DAT(0x00), /* y1, 11 */
+       SMART_CMD(0x04), /* VADDR, END 12 */
+       SMART_CMD(0x09),
+       SMART_DAT(0x01), /* y2, 14 */
+       SMART_DAT(0x3F), /* y2, 15 */
+       SMART_CMD(0x02), /* RAM ADDR SETTING 16 */
+       SMART_CMD(0x00),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00), /* x1, 19 */
+       SMART_CMD(0x02), /* RAM ADDR SETTING 20 */
+       SMART_CMD(0x01),
+       SMART_DAT(0x00), /* y1, 22 */
+       SMART_DAT(0x00), /* y1, 23 */
+};
+
+static uint16_t panel_on[] = {
+       /* Power-IC ON */
+       SMART_CMD(0x01),
+       SMART_CMD(0x02),
+       SMART_DAT(0x07),
+       SMART_DAT(0x7D),
+       SMART_CMD(0x01),
+       SMART_CMD(0x03),
+       SMART_DAT(0x00),
+       SMART_DAT(0x05),
+       SMART_CMD(0x01),
+       SMART_CMD(0x04),
+       SMART_DAT(0x00),
+       SMART_DAT(0x00),
+       SMART_CMD(0x01),
+       SMART_CMD(0x05),
+       SMART_DAT(0x00),
+       SMART_DAT(0x15),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0xC0),
+       SMART_DAT(0x10),
+       SMART_DELAY(30),
+
+       /* DISP ON */
+       SMART_CMD(0x01),
+       SMART_CMD(0x01),
+       SMART_DAT(0x00),
+       SMART_DAT(0x01),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0xFF),
+       SMART_DAT(0xFE),
+       SMART_DELAY(150),
+};
+
+static uint16_t panel_off[] = {
+       SMART_CMD(0x00),
+       SMART_CMD(0x1E),
+       SMART_DAT(0x00),
+       SMART_DAT(0x0A),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0xFF),
+       SMART_DAT(0xEE),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0xF8),
+       SMART_DAT(0x12),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0xE8),
+       SMART_DAT(0x11),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0xC0),
+       SMART_DAT(0x11),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0x40),
+       SMART_DAT(0x11),
+       SMART_CMD(0x01),
+       SMART_CMD(0x00),
+       SMART_DAT(0x00),
+       SMART_DAT(0x10),
+};
+
+static uint16_t update_framedata[] = {
+       /* write ram */
+       SMART_CMD(0x02),
+       SMART_CMD(0x02),
+
+       /* write frame data */
+       SMART_CMD_WRITE_FRAME,
+};
+
+static void ltm020d550_lcd_power(int on, struct fb_var_screeninfo *var)
+{
+       struct fb_info *info = container_of(var, struct fb_info, var);
+
+       if (on) {
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(panel_init));
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(panel_on));
+       } else {
+               pxafb_smart_queue(info, ARRAY_AND_SIZE(panel_off));
+       }
+
+       if (pxafb_smart_flush(info))
+               pr_err("%s: timed out\n", __func__);
+}
+
+static void ltm020d550_update(struct fb_info *info)
+{
+       pxafb_smart_queue(info, ARRAY_AND_SIZE(update_framedata));
+       pxafb_smart_flush(info);
+}
+
+static struct pxafb_mode_info toshiba_ltm020d550_modes[] = {
+       [0] = {
+               .xres                   = 240,
+               .yres                   = 320,
+               .bpp                    = 16,
+               .a0csrd_set_hld         = 30,
+               .a0cswr_set_hld         = 30,
+               .wr_pulse_width         = 30,
+               .rd_pulse_width         = 170,
+               .op_hold_time           = 30,
+               .cmd_inh_time           = 60,
+
+               /* L_LCLK_A0 and L_LCLK_RD active low */
+               .sync                   = FB_SYNC_HOR_HIGH_ACT |
+                                         FB_SYNC_VERT_HIGH_ACT,
+       },
+};
+
+static struct pxafb_mach_info tavorevb_lcd_info = {
+       .modes                  = toshiba_ltm020d550_modes,
+       .num_modes              = 1,
+       .lcd_conn               = LCD_SMART_PANEL_8BPP | LCD_PCLK_EDGE_FALL,
+       .pxafb_lcd_power        = ltm020d550_lcd_power,
+       .smart_update           = ltm020d550_update,
+};
+
+static void __init tavorevb_init_lcd(void)
+{
+       platform_device_register(&tavorevb_backlight_devices[0]);
+       platform_device_register(&tavorevb_backlight_devices[1]);
+       set_pxa_fb_info(&tavorevb_lcd_info);
+}
+#else
+static inline void tavorevb_init_lcd(void) {}
+#endif /* CONFIG_FB_PXA || CONFIG_FB_PXA_MODULE */
+
 static void __init tavorevb_init(void)
 {
        /* initialize MFP configurations */
        pxa3xx_mfp_config(ARRAY_AND_SIZE(tavorevb_mfp_cfg));
 
        platform_device_register(&smc91x_device);
+
+       tavorevb_init_lcd();
+       tavorevb_init_keypad();
 }
 
 MACHINE_START(TAVOREVB, "PXA930 Evaluation Board (aka TavorEVB)")
index f8a9a62959e5bfe9cb426e75560efb17a08f7194..0016241585190e3770de17ac6e02b0db57547a2f 100644 (file)
@@ -22,8 +22,8 @@
 #include <asm/div64.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
+#include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <asm/mach-types.h>
 
 /*
  * This is PXA's sched_clock implementation. This has a resolution
@@ -150,18 +150,11 @@ static struct irqaction pxa_ost0_irq = {
 
 static void __init pxa_timer_init(void)
 {
-       unsigned long clock_tick_rate;
+       unsigned long clock_tick_rate = get_clock_tick_rate();
 
        OIER = 0;
        OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
 
-       if (cpu_is_pxa25x())
-               clock_tick_rate = 3686400;
-       else if (machine_is_mainstone())
-               clock_tick_rate = 3249600;
-       else
-               clock_tick_rate = 3250000;
-
        set_oscr2ns_scale(clock_tick_rate);
 
        ckevt_pxa_osmr0.mult =
index 224897a67d1593113cb43806ef861cad5ec95190..3332e5d0356c522b7c266995f5f88dd26e02342c 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mfd/tmio.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
 #include <linux/pm.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
@@ -733,6 +734,45 @@ static void tosa_tc6393xb_teardown(struct platform_device *dev)
        gpio_free(TOSA_GPIO_CARD_VCC_ON);
 }
 
+#ifdef CONFIG_MFD_TC6393XB
+static struct fb_videomode tosa_tc6393xb_lcd_mode[] = {
+       {
+               .xres = 480,
+               .yres = 640,
+               .pixclock = 0x002cdf00,/* PLL divisor */
+               .left_margin = 0x004c,
+               .right_margin = 0x005b,
+               .upper_margin = 0x0001,
+               .lower_margin = 0x000d,
+               .hsync_len = 0x0002,
+               .vsync_len = 0x0001,
+               .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode = FB_VMODE_NONINTERLACED,
+       },{
+               .xres = 240,
+               .yres = 320,
+               .pixclock = 0x00e7f203,/* PLL divisor */
+               .left_margin = 0x0024,
+               .right_margin = 0x002f,
+               .upper_margin = 0x0001,
+               .lower_margin = 0x000d,
+               .hsync_len = 0x0002,
+               .vsync_len = 0x0001,
+               .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+               .vmode = FB_VMODE_NONINTERLACED,
+       }
+};
+
+static struct tmio_fb_data tosa_tc6393xb_fb_config = {
+       .lcd_set_power  = tc6393xb_lcd_set_power,
+       .lcd_mode       = tc6393xb_lcd_mode,
+       .num_modes      = ARRAY_SIZE(tosa_tc6393xb_lcd_mode),
+       .modes          = &tosa_tc6393xb_lcd_mode[0],
+       .height         = 82,
+       .width          = 60,
+};
+#endif
+
 static struct tc6393xb_platform_data tosa_tc6393xb_data = {
        .scr_pll2cr     = 0x0cc1,
        .scr_gper       = 0x3300,
@@ -748,6 +788,9 @@ static struct tc6393xb_platform_data tosa_tc6393xb_data = {
        .resume         = tosa_tc6393xb_resume,
 
        .nand_data      = &tosa_tc6393xb_nand_config,
+#ifdef CONFIG_MFD_TC6393XB
+       .fb_data        = &tosa_tc6393xb_fb_config,
+#endif
 
        .resume_restore = 1,
 };
@@ -789,6 +832,36 @@ static struct spi_board_info spi_board_info[] __initdata = {
        },
 };
 
+static struct mtd_partition sharpsl_rom_parts[] = {
+       {
+               .name   ="Boot PROM Filesystem",
+               .offset = 0x00160000,
+               .size   = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data sharpsl_rom_data = {
+       .width          = 2,
+       .nr_parts       = ARRAY_SIZE(sharpsl_rom_parts),
+       .parts          = sharpsl_rom_parts,
+};
+
+static struct resource sharpsl_rom_resources[] = {
+       {
+               .start  = 0x00000000,
+               .end    = 0x007fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device sharpsl_rom_device = {
+       .name   = "physmap-flash",
+       .id     = -1,
+       .resource = sharpsl_rom_resources,
+       .num_resources = ARRAY_SIZE(sharpsl_rom_resources),
+       .dev.platform_data = &sharpsl_rom_data,
+};
+
 static struct platform_device *devices[] __initdata = {
        &tosascoop_device,
        &tosascoop_jc_device,
@@ -798,6 +871,7 @@ static struct platform_device *devices[] __initdata = {
        &tosa_gpio_keys_device,
        &tosaled_device,
        &tosa_bt_device,
+       &sharpsl_rom_device,
 };
 
 static void tosa_poweroff(void)
index 8138044334668849506b15e299a4952b85c84901..218d2001f1dfc0c070e8bcae2f6db128070d9ed9 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/gpio.h>
 #include <linux/pwm_backlight.h>
 #include <linux/smc91x.h>
 
@@ -25,7 +26,6 @@
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/audio.h>
-#include <mach/gpio.h>
 #include <mach/pxafb.h>
 #include <mach/zylonite.h>
 #include <mach/mmc.h>
index 0f244744daaeb3c7e776a0abb27c325f664e2ef9..28e4e623780be2342ab0a65af4ee1fe74b18f650 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 
-#include <mach/gpio.h>
 #include <mach/mfp-pxa320.h>
 #include <mach/zylonite.h>
 
index 5ccde7cf39e868ce129c4f4fc204903d1f72f6d8..ad911854eb4cfd51558e9666db9359205b132674 100644 (file)
@@ -7,9 +7,17 @@ config MACH_REALVIEW_EB
        help
          Include support for the ARM(R) RealView Emulation Baseboard platform.
 
+config REALVIEW_EB_A9MP
+       bool "Support Multicore Cortex-A9"
+       depends on MACH_REALVIEW_EB
+       select CPU_V7
+       help
+         Enable support for the Cortex-A9MPCore tile on the Realview platform.
+
 config REALVIEW_EB_ARM11MP
        bool "Support ARM11MPCore tile"
        depends on MACH_REALVIEW_EB
+       select CPU_V6
        help
          Enable support for the ARM11MPCore tile on the Realview platform.
 
@@ -25,6 +33,7 @@ config REALVIEW_EB_ARM11MP_REVB
 
 config MACH_REALVIEW_PB11MP
        bool "Support RealView/PB11MPCore platform"
+       select CPU_V6
        select ARM_GIC
        help
          Include support for the ARM(R) RealView MPCore Platform Baseboard.
@@ -33,8 +42,29 @@ config MACH_REALVIEW_PB11MP
 
 config MACH_REALVIEW_PB1176
        bool "Support RealView/PB1176 platform"
+       select CPU_V6
        select ARM_GIC
        help
          Include support for the ARM(R) RealView ARM1176 Platform Baseboard.
 
+config MACH_REALVIEW_PBA8
+       bool "Support RealView/PB-A8 platform"
+       select CPU_V7
+       select ARM_GIC
+       help
+         Include support for the ARM(R) RealView Cortex-A8 Platform Baseboard.
+         PB-A8 is a platform with an on-board Cortex-A8 and has support for
+         PCI-E and Compact Flash.
+
+config REALVIEW_HIGH_PHYS_OFFSET
+       bool "High physical base address for the RealView platform"
+       depends on !MACH_REALVIEW_PB1176
+       default y
+       help
+         RealView boards other than PB1176 have the RAM available at
+         0x70000000, 256MB of which being mirrored at 0x00000000. If
+         the board supports 512MB of RAM, this option allows the
+         memory to be accessed contiguously at the high physical
+         offset.
+
 endmenu
index d2ae077431dd5629b7805924c18ed63399ad8ba6..7bea8ffc4b5922cc05bff5000356aa8069aa9663 100644 (file)
@@ -6,5 +6,6 @@ obj-y                                   := core.o clock.o
 obj-$(CONFIG_MACH_REALVIEW_EB)         += realview_eb.o
 obj-$(CONFIG_MACH_REALVIEW_PB11MP)     += realview_pb11mp.o
 obj-$(CONFIG_MACH_REALVIEW_PB1176)     += realview_pb1176.o
+obj-$(CONFIG_MACH_REALVIEW_PBA8)       += realview_pba8.o
 obj-$(CONFIG_SMP)                      += platsmp.o headsmp.o localtimer.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
index c7e75acfe6c9b1911a5825c2b3136ad9b719d445..d97e003d3df4c2237be7e2b02a706d4819655b27 100644 (file)
@@ -1,4 +1,9 @@
+ifeq ($(CONFIG_REALVIEW_HIGH_PHYS_OFFSET),y)
+   zreladdr-y  := 0x70008000
+params_phys-y  := 0x70000100
+initrd_phys-y  := 0x70800000
+else
    zreladdr-y  := 0x00008000
 params_phys-y  := 0x00000100
 initrd_phys-y  := 0x00800000
-
+endif
index 3347c4236a60bd6cb2b34cbadc09d0d966614ebf..a7043115de72638022aefa73f7a829a49e515302 100644 (file)
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
+#include <linux/string.h>
 #include <linux/clk.h>
 #include <linux/mutex.h>
 
 
 #include "clock.h"
 
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-       mutex_unlock(&clocks_mutex);
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-       module_put(clk->owner);
-}
-EXPORT_SYMBOL(clk_put);
-
 int clk_enable(struct clk *clk)
 {
        return 0;
@@ -65,7 +41,9 @@ EXPORT_SYMBOL(clk_get_rate);
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       return rate;
+       struct icst307_vco vco;
+       vco = icst307_khz_to_vco(clk->params, rate / 1000);
+       return icst307_khz(clk->params, vco) * 1000;
 }
 EXPORT_SYMBOL(clk_round_rate);
 
@@ -78,57 +56,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 
                vco = icst307_khz_to_vco(clk->params, rate / 1000);
                clk->rate = icst307_khz(clk->params, vco) * 1000;
-
-               printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
-                       clk->name, vco.s, vco.r, vco.v);
-
                clk->setvco(clk, vco);
                ret = 0;
        }
        return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
-
-/*
- * These are fixed clocks.
- */
-static struct clk kmi_clk = {
-       .name   = "KMIREFCLK",
-       .rate   = 24000000,
-};
-
-static struct clk uart_clk = {
-       .name   = "UARTCLK",
-       .rate   = 24000000,
-};
-
-static struct clk mmci_clk = {
-       .name   = "MCLK",
-       .rate   = 24000000,
-};
-
-int clk_register(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_del(&clk->node);
-       mutex_unlock(&clocks_mutex);
-}
-EXPORT_SYMBOL(clk_unregister);
-
-static int __init clk_init(void)
-{
-       clk_register(&kmi_clk);
-       clk_register(&uart_clk);
-       clk_register(&mmci_clk);
-       return 0;
-}
-arch_initcall(clk_init);
index dadba695e181dd18f572d6af6140427195205c54..ebbb0f06b6007860802116670fe8dca9e2fb2e4e 100644 (file)
@@ -12,14 +12,8 @@ struct module;
 struct icst307_params;
 
 struct clk {
-       struct list_head        node;
        unsigned long           rate;
-       struct module           *owner;
-       const char              *name;
        const struct icst307_params *params;
        void                    *data;
        void                    (*setvco)(struct clk *, struct icst307_vco vco);
 };
-
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
index 2f04d54711e7b86ad204a0916ba012e5234d91fd..5f1d55963cedb8e7b4d3cbd0b6e71a24c84b10c9 100644 (file)
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
 #include <linux/io.h>
+#include <linux/smc911x.h>
 
+#include <asm/clkdev.h>
 #include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/leds.h>
+#include <asm/mach-types.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst307.h>
 
@@ -49,7 +52,7 @@
 
 #define REALVIEW_REFCOUNTER    (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET)
 
-/* used by entry-macro.S */
+/* used by entry-macro.S and platsmp.c */
 void __iomem *gic_cpu_base_addr;
 
 /*
@@ -124,6 +127,29 @@ int realview_flash_register(struct resource *res, u32 num)
        return platform_device_register(&realview_flash_device);
 }
 
+static struct smc911x_platdata realview_smc911x_platdata = {
+       .flags          = SMC911X_USE_32BIT,
+       .irq_flags      = IRQF_SHARED,
+       .irq_polarity   = 1,
+};
+
+static struct platform_device realview_eth_device = {
+       .name           = "smc911x",
+       .id             = 0,
+       .num_resources  = 2,
+};
+
+int realview_eth_register(const char *name, struct resource *res)
+{
+       if (name)
+               realview_eth_device.name = name;
+       realview_eth_device.resource = res;
+       if (strcmp(realview_eth_device.name, "smc911x") == 0)
+               realview_eth_device.dev.platform_data = &realview_smc911x_platdata;
+
+       return platform_device_register(&realview_eth_device);
+}
+
 static struct resource realview_i2c_resource = {
        .start          = REALVIEW_I2C_BASE,
        .end            = REALVIEW_I2C_BASE + SZ_4K - 1,
@@ -177,9 +203,14 @@ static const struct icst307_params realview_oscvco_params = {
 static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco)
 {
        void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET;
-       void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET;
+       void __iomem *sys_osc;
        u32 val;
 
+       if (machine_is_realview_pb1176())
+               sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC0_OFFSET;
+       else
+               sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC4_OFFSET;
+
        val = readl(sys_osc) & ~0x7ffff;
        val |= vco.v | (vco.r << 9) | (vco.s << 16);
 
@@ -188,12 +219,59 @@ static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco)
        writel(0, sys_lock);
 }
 
-struct clk realview_clcd_clk = {
-       .name   = "CLCDCLK",
+static struct clk oscvco_clk = {
        .params = &realview_oscvco_params,
        .setvco = realview_oscvco_set,
 };
 
+/*
+ * These are fixed clocks.
+ */
+static struct clk ref24_clk = {
+       .rate   = 24000000,
+};
+
+static struct clk_lookup lookups[] = {
+       {       /* UART0 */
+               .dev_id         = "dev:f1",
+               .clk            = &ref24_clk,
+       }, {    /* UART1 */
+               .dev_id         = "dev:f2",
+               .clk            = &ref24_clk,
+       }, {    /* UART2 */
+               .dev_id         = "dev:f3",
+               .clk            = &ref24_clk,
+       }, {    /* UART3 */
+               .dev_id         = "fpga:09",
+               .clk            = &ref24_clk,
+       }, {    /* KMI0 */
+               .dev_id         = "fpga:06",
+               .clk            = &ref24_clk,
+       }, {    /* KMI1 */
+               .dev_id         = "fpga:07",
+               .clk            = &ref24_clk,
+       }, {    /* MMC0 */
+               .dev_id         = "fpga:05",
+               .clk            = &ref24_clk,
+       }, {    /* EB:CLCD */
+               .dev_id         = "dev:20",
+               .clk            = &oscvco_clk,
+       }, {    /* PB:CLCD */
+               .dev_id         = "issp:20",
+               .clk            = &oscvco_clk,
+       }
+};
+
+static int __init clk_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
+       return 0;
+}
+arch_initcall(clk_init);
+
 /*
  * CLCD support.
  */
@@ -226,7 +304,30 @@ static struct clcd_panel vga = {
        .width          = -1,
        .height         = -1,
        .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
+       .bpp            = 16,
+};
+
+static struct clcd_panel xvga = {
+       .mode           = {
+               .name           = "XVGA",
+               .refresh        = 60,
+               .xres           = 1024,
+               .yres           = 768,
+               .pixclock       = 15748,
+               .left_margin    = 152,
+               .right_margin   = 48,
+               .upper_margin   = 23,
+               .lower_margin   = 3,
+               .hsync_len      = 104,
+               .vsync_len      = 4,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED,
+       },
+       .width          = -1,
+       .height         = -1,
+       .tim2           = TIM2_BCD | TIM2_IPC,
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
        .bpp            = 16,
 };
 
@@ -249,7 +350,7 @@ static struct clcd_panel sanyo_3_8_in = {
        .width          = -1,
        .height         = -1,
        .tim2           = TIM2_BCD,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
        .bpp            = 16,
 };
 
@@ -272,7 +373,7 @@ static struct clcd_panel sanyo_2_5_in = {
        .width          = -1,
        .height         = -1,
        .tim2           = TIM2_IVS | TIM2_IHS | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
        .bpp            = 16,
 };
 
@@ -295,7 +396,7 @@ static struct clcd_panel epson_2_2_in = {
        .width          = -1,
        .height         = -1,
        .tim2           = TIM2_BCD | TIM2_IPC,
-       .cntl           = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
+       .cntl           = CNTL_LCDTFT | CNTL_BGR | CNTL_LCDVCOMP(1),
        .bpp            = 16,
 };
 
@@ -308,9 +409,15 @@ static struct clcd_panel epson_2_2_in = {
 static struct clcd_panel *realview_clcd_panel(void)
 {
        void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET;
-       struct clcd_panel *panel = &vga;
+       struct clcd_panel *vga_panel;
+       struct clcd_panel *panel;
        u32 val;
 
+       if (machine_is_realview_eb())
+               vga_panel = &vga;
+       else
+               vga_panel = &xvga;
+
        val = readl(sys_clcd) & SYS_CLCD_ID_MASK;
        if (val == SYS_CLCD_ID_SANYO_3_8)
                panel = &sanyo_3_8_in;
@@ -319,11 +426,11 @@ static struct clcd_panel *realview_clcd_panel(void)
        else if (val == SYS_CLCD_ID_EPSON_2_2)
                panel = &epson_2_2_in;
        else if (val == SYS_CLCD_ID_VGA)
-               panel = &vga;
+               panel = vga_panel;
        else {
                printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n",
                        val);
-               panel = &vga;
+               panel = vga_panel;
        }
 
        return panel;
@@ -358,12 +465,18 @@ static void realview_clcd_enable(struct clcd_fb *fb)
        writel(val, sys_clcd);
 }
 
-static unsigned long framesize = SZ_1M;
-
 static int realview_clcd_setup(struct clcd_fb *fb)
 {
+       unsigned long framesize;
        dma_addr_t dma;
 
+       if (machine_is_realview_eb())
+               /* VGA, 16bpp */
+               framesize = 640 * 480 * 2;
+       else
+               /* XVGA, 16bpp */
+               framesize = 1024 * 768 * 2;
+
        fb->panel               = realview_clcd_panel();
 
        fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize,
@@ -588,7 +701,7 @@ void __init realview_timer_init(unsigned int timer_irq)
         * The dummy clock device has to be registered before the main device
         * so that the latter will broadcast the clock events
         */
-       local_timer_setup(smp_processor_id());
+       local_timer_setup();
 #endif
 
        /* 
index 3cea92c70d8f1df407e3b7f10da4d0470ab5ee0d..63be2abdc19ce299d52556ef4e68a28de6edabd8 100644 (file)
@@ -48,12 +48,10 @@ extern struct platform_device realview_flash_device;
 extern struct platform_device realview_i2c_device;
 extern struct mmc_platform_data realview_mmc0_plat_data;
 extern struct mmc_platform_data realview_mmc1_plat_data;
-extern struct clk realview_clcd_clk;
 extern struct clcd_board clcd_plat_data;
 extern void __iomem *gic_cpu_base_addr;
 #ifdef CONFIG_LOCAL_TIMERS
-extern void __iomem *twd_base_addr;
-extern unsigned int twd_size;
+extern void __iomem *twd_base;
 #endif
 extern void __iomem *timer0_va_base;
 extern void __iomem *timer1_va_base;
@@ -63,5 +61,6 @@ extern void __iomem *timer3_va_base;
 extern void realview_leds_event(led_event_t ledevt);
 extern void realview_timer_init(unsigned int timer_irq);
 extern int realview_flash_register(struct resource *res, u32 num);
+extern int realview_eth_register(const char *name, struct resource *res);
 
 #endif
index 09748cbcd10e790b1150bad55ef75f1d76f44739..be048e3e8799fe9b7e9cfc05c474b6e90e7d5fe5 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/smp.h>
 #include <linux/completion.h>
 
+#include <asm/cacheflush.h>
+
 extern volatile int pen_release;
 
 static DECLARE_COMPLETION(cpu_killed);
@@ -21,7 +23,8 @@ static inline void cpu_enter_lowpower(void)
 {
        unsigned int v;
 
-       asm volatile(   "mcr    p15, 0, %1, c7, c14, 0\n"
+       flush_cache_all();
+       asm volatile(
        "       mcr     p15, 0, %1, c7, c5, 0\n"
        "       mcr     p15, 0, %1, c7, c10, 4\n"
        /*
index 8d699fd324d0a559b5bfb1a1638c3603d4154cb3..268d7701fa9bbc5409a89dc3876d832c94669cb1 100644 (file)
 #ifdef CONFIG_REALVIEW_EB_ARM11MP_REVB
 #define REALVIEW_EB11MP_SCU_BASE       0x10100000      /* SCU registers */
 #define REALVIEW_EB11MP_GIC_CPU_BASE   0x10100100      /* Generic interrupt controller CPU interface */
-#define REALVIEW_EB11MP_TWD_BASE       0x10100700
-#define REALVIEW_EB11MP_TWD_SIZE       0x00000100
+#define REALVIEW_EB11MP_TWD_BASE       0x10100600
 #define REALVIEW_EB11MP_GIC_DIST_BASE  0x10101000      /* Generic interrupt controller distributor */
 #define REALVIEW_EB11MP_L220_BASE      0x10102000      /* L220 registers */
 #define REALVIEW_EB11MP_SYS_PLD_CTRL1  0xD8            /* Register offset for MPCore sysctl */
 #else
 #define REALVIEW_EB11MP_SCU_BASE       0x1F000000      /* SCU registers */
 #define REALVIEW_EB11MP_GIC_CPU_BASE   0x1F000100      /* Generic interrupt controller CPU interface */
-#define REALVIEW_EB11MP_TWD_BASE       0x1F000700
-#define REALVIEW_EB11MP_TWD_SIZE       0x00000100
+#define REALVIEW_EB11MP_TWD_BASE       0x1F000600
 #define REALVIEW_EB11MP_GIC_DIST_BASE  0x1F001000      /* Generic interrupt controller distributor */
 #define REALVIEW_EB11MP_L220_BASE      0x1F002000      /* L220 registers */
 #define REALVIEW_EB11MP_SYS_PLD_CTRL1  0x74            /* Register offset for MPCore sysctl */
 #define NR_IRQS                        NR_IRQS_EB
 #endif
 
-#if defined(CONFIG_REALVIEW_EB_ARM11MP) \
+#if defined(CONFIG_REALVIEW_EB_ARM11MP) || defined(CONFIG_REALVIEW_EB_A9MP) \
        && (!defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_EB11MP))
 #undef MAX_GIC_NR
 #define MAX_GIC_NR             NR_GIC_EB11MP
 #define REALVIEW_EB_PROC_ARM9          0x02000000
 #define REALVIEW_EB_PROC_ARM11         0x04000000
 #define REALVIEW_EB_PROC_ARM11MP       0x06000000
+#define REALVIEW_EB_PROC_A9MP          0x0C000000
 
 #define check_eb_proc(proc_type)                                               \
        ((readl(__io_address(REALVIEW_SYS_PROCID)) & REALVIEW_EB_PROC_MASK)     \
 #define core_tile_eb11mp()     0
 #endif
 
+#ifdef CONFIG_REALVIEW_EB_A9MP
+#define core_tile_a9mp()       check_eb_proc(REALVIEW_EB_PROC_A9MP)
+#else
+#define core_tile_a9mp()       0
+#endif
+
+#define machine_is_realview_eb_mp() \
+       (machine_is_realview_eb() && (core_tile_eb11mp() || core_tile_a9mp()))
+
 #endif /* __ASM_ARCH_BOARD_EB_H */
index ecd80e58631e5cf7f9ad5202c74a39a684d584c0..53ea0e7a1267b9957a231530e9bf3e645c161061 100644 (file)
@@ -77,8 +77,7 @@
  */
 #define REALVIEW_TC11MP_SCU_BASE               0x1F000000      /* IRQ, Test chip */
 #define REALVIEW_TC11MP_GIC_CPU_BASE           0x1F000100      /* Test chip interrupt controller CPU interface */
-#define REALVIEW_TC11MP_TWD_BASE               0x1F000700
-#define REALVIEW_TC11MP_TWD_SIZE               0x00000100
+#define REALVIEW_TC11MP_TWD_BASE               0x1F000600
 #define REALVIEW_TC11MP_GIC_DIST_BASE          0x1F001000      /* Test chip interrupt controller distributor */
 #define REALVIEW_TC11MP_L220_BASE              0x1F002000      /* L220 registers */
 
diff --git a/arch/arm/mach-realview/include/mach/board-pba8.h b/arch/arm/mach-realview/include/mach/board-pba8.h
new file mode 100644 (file)
index 0000000..c8bed8f
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * include/asm-arm/arch-realview/board-pba8.h
+ *
+ * Copyright (C) 2008 ARM Limited
+ *
+ * This program is free software; you can 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 Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __ASM_ARCH_BOARD_PBA8_H
+#define __ASM_ARCH_BOARD_PBA8_H
+
+#include <mach/platform.h>
+
+/*
+ * Peripheral addresses
+ */
+#define REALVIEW_PBA8_UART0_BASE               0x10009000      /* UART 0 */
+#define REALVIEW_PBA8_UART1_BASE               0x1000A000      /* UART 1 */
+#define REALVIEW_PBA8_UART2_BASE               0x1000B000      /* UART 2 */
+#define REALVIEW_PBA8_UART3_BASE               0x1000C000      /* UART 3 */
+#define REALVIEW_PBA8_SSP_BASE                 0x1000D000      /* Synchronous Serial Port */
+#define REALVIEW_PBA8_WATCHDOG0_BASE           0x1000F000      /* Watchdog 0 */
+#define REALVIEW_PBA8_WATCHDOG_BASE            0x10010000      /* watchdog interface */
+#define REALVIEW_PBA8_TIMER0_1_BASE            0x10011000      /* Timer 0 and 1 */
+#define REALVIEW_PBA8_TIMER2_3_BASE            0x10012000      /* Timer 2 and 3 */
+#define REALVIEW_PBA8_GPIO0_BASE               0x10013000      /* GPIO port 0 */
+#define REALVIEW_PBA8_RTC_BASE                 0x10017000      /* Real Time Clock */
+#define REALVIEW_PBA8_TIMER4_5_BASE            0x10018000      /* Timer 4/5 */
+#define REALVIEW_PBA8_TIMER6_7_BASE            0x10019000      /* Timer 6/7 */
+#define REALVIEW_PBA8_SCTL_BASE                        0x1001A000      /* System Controller */
+#define REALVIEW_PBA8_CLCD_BASE                        0x10020000      /* CLCD */
+#define REALVIEW_PBA8_ONB_SRAM_BASE            0x10060000      /* On-board SRAM */
+#define REALVIEW_PBA8_DMC_BASE                 0x100E0000      /* DMC configuration */
+#define REALVIEW_PBA8_SMC_BASE                 0x100E1000      /* SMC configuration */
+#define REALVIEW_PBA8_CAN_BASE                 0x100E2000      /* CAN bus */
+#define REALVIEW_PBA8_CF_BASE                  0x18000000      /* Compact flash */
+#define REALVIEW_PBA8_CF_MEM_BASE              0x18003000      /* SMC for Compact flash */
+#define REALVIEW_PBA8_GIC_CPU_BASE             0x1E000000      /* Generic interrupt controller CPU interface */
+#define REALVIEW_PBA8_FLASH0_BASE              0x40000000
+#define REALVIEW_PBA8_FLASH0_SIZE              SZ_64M
+#define REALVIEW_PBA8_FLASH1_BASE              0x44000000
+#define REALVIEW_PBA8_FLASH1_SIZE              SZ_64M
+#define REALVIEW_PBA8_ETH_BASE                 0x4E000000      /* Ethernet */
+#define REALVIEW_PBA8_USB_BASE                 0x4F000000      /* USB */
+#define REALVIEW_PBA8_GIC_DIST_BASE            0x1E001000      /* Generic interrupt controller distributor */
+#define REALVIEW_PBA8_LT_BASE                  0xC0000000      /* Logic Tile expansion */
+#define REALVIEW_PBA8_SDRAM6_BASE              0x70000000      /* SDRAM bank 6 256MB */
+#define REALVIEW_PBA8_SDRAM7_BASE              0x80000000      /* SDRAM bank 7 256MB */
+
+#define REALVIEW_PBA8_SYS_PLD_CTRL1            0x74
+
+/*
+ * PBA8 PCI regions
+ */
+#define REALVIEW_PBA8_PCI_BASE                 0x90040000      /* PCI-X Unit base */
+#define REALVIEW_PBA8_PCI_IO_BASE              0x90050000      /* IO Region on AHB */
+#define REALVIEW_PBA8_PCI_MEM_BASE             0xA0000000      /* MEM Region on AHB */
+
+#define REALVIEW_PBA8_PCI_BASE_SIZE            0x10000         /* 16 Kb */
+#define REALVIEW_PBA8_PCI_IO_SIZE              0x1000          /* 4 Kb */
+#define REALVIEW_PBA8_PCI_MEM_SIZE             0x20000000      /* 512 MB */
+
+/*
+ * Irqs
+ */
+#define IRQ_PBA8_GIC_START                     32
+
+/* L220
+#define IRQ_PBA8_L220_EVENT    (IRQ_PBA8_GIC_START + 29)
+#define IRQ_PBA8_L220_SLAVE    (IRQ_PBA8_GIC_START + 30)
+#define IRQ_PBA8_L220_DECODE   (IRQ_PBA8_GIC_START + 31)
+*/
+
+/*
+ * PB-A8 on-board gic irq sources
+ */
+#define IRQ_PBA8_WATCHDOG      (IRQ_PBA8_GIC_START + 0)        /* Watchdog timer */
+#define IRQ_PBA8_SOFT          (IRQ_PBA8_GIC_START + 1)        /* Software interrupt */
+#define IRQ_PBA8_COMMRx                (IRQ_PBA8_GIC_START + 2)        /* Debug Comm Rx interrupt */
+#define IRQ_PBA8_COMMTx                (IRQ_PBA8_GIC_START + 3)        /* Debug Comm Tx interrupt */
+#define IRQ_PBA8_TIMER0_1      (IRQ_PBA8_GIC_START + 4)        /* Timer 0/1 (default timer) */
+#define IRQ_PBA8_TIMER2_3      (IRQ_PBA8_GIC_START + 5)        /* Timer 2/3 */
+#define IRQ_PBA8_GPIO0         (IRQ_PBA8_GIC_START + 6)        /* GPIO 0 */
+#define IRQ_PBA8_GPIO1         (IRQ_PBA8_GIC_START + 7)        /* GPIO 1 */
+#define IRQ_PBA8_GPIO2         (IRQ_PBA8_GIC_START + 8)        /* GPIO 2 */
+                                                               /* 9 reserved */
+#define IRQ_PBA8_RTC           (IRQ_PBA8_GIC_START + 10)       /* Real Time Clock */
+#define IRQ_PBA8_SSP           (IRQ_PBA8_GIC_START + 11)       /* Synchronous Serial Port */
+#define IRQ_PBA8_UART0         (IRQ_PBA8_GIC_START + 12)       /* UART 0 on development chip */
+#define IRQ_PBA8_UART1         (IRQ_PBA8_GIC_START + 13)       /* UART 1 on development chip */
+#define IRQ_PBA8_UART2         (IRQ_PBA8_GIC_START + 14)       /* UART 2 on development chip */
+#define IRQ_PBA8_UART3         (IRQ_PBA8_GIC_START + 15)       /* UART 3 on development chip */
+#define IRQ_PBA8_SCI           (IRQ_PBA8_GIC_START + 16)       /* Smart Card Interface */
+#define IRQ_PBA8_MMCI0A                (IRQ_PBA8_GIC_START + 17)       /* Multimedia Card 0A */
+#define IRQ_PBA8_MMCI0B                (IRQ_PBA8_GIC_START + 18)       /* Multimedia Card 0B */
+#define IRQ_PBA8_AACI          (IRQ_PBA8_GIC_START + 19)       /* Audio Codec */
+#define IRQ_PBA8_KMI0          (IRQ_PBA8_GIC_START + 20)       /* Keyboard/Mouse port 0 */
+#define IRQ_PBA8_KMI1          (IRQ_PBA8_GIC_START + 21)       /* Keyboard/Mouse port 1 */
+#define IRQ_PBA8_CHARLCD       (IRQ_PBA8_GIC_START + 22)       /* Character LCD */
+#define IRQ_PBA8_CLCD          (IRQ_PBA8_GIC_START + 23)       /* CLCD controller */
+#define IRQ_PBA8_DMAC          (IRQ_PBA8_GIC_START + 24)       /* DMA controller */
+#define IRQ_PBA8_PWRFAIL       (IRQ_PBA8_GIC_START + 25)       /* Power failure */
+#define IRQ_PBA8_PISMO         (IRQ_PBA8_GIC_START + 26)       /* PISMO interface */
+#define IRQ_PBA8_DoC           (IRQ_PBA8_GIC_START + 27)       /* Disk on Chip memory controller */
+#define IRQ_PBA8_ETH           (IRQ_PBA8_GIC_START + 28)       /* Ethernet controller */
+#define IRQ_PBA8_USB           (IRQ_PBA8_GIC_START + 29)       /* USB controller */
+#define IRQ_PBA8_TSPEN         (IRQ_PBA8_GIC_START + 30)       /* Touchscreen pen */
+#define IRQ_PBA8_TSKPAD                (IRQ_PBA8_GIC_START + 31)       /* Touchscreen keypad */
+
+/* ... */
+#define IRQ_PBA8_PCI0          (IRQ_PBA8_GIC_START + 50)
+#define IRQ_PBA8_PCI1          (IRQ_PBA8_GIC_START + 51)
+#define IRQ_PBA8_PCI2          (IRQ_PBA8_GIC_START + 52)
+#define IRQ_PBA8_PCI3          (IRQ_PBA8_GIC_START + 53)
+
+#define IRQ_PBA8_SMC           -1
+#define IRQ_PBA8_SCTL          -1
+
+#define NR_GIC_PBA8            1
+
+/*
+ * Only define NR_IRQS if less than NR_IRQS_PBA8
+ */
+#define NR_IRQS_PBA8           (IRQ_PBA8_GIC_START + 64)
+
+#if defined(CONFIG_MACH_REALVIEW_PBA8)
+
+#if !defined(NR_IRQS) || (NR_IRQS < NR_IRQS_PBA8)
+#undef NR_IRQS
+#define NR_IRQS                        NR_IRQS_PBA8
+#endif
+
+#if !defined(MAX_GIC_NR) || (MAX_GIC_NR < NR_GIC_PBA8)
+#undef MAX_GIC_NR
+#define MAX_GIC_NR             NR_GIC_PBA8
+#endif
+
+#endif /* CONFIG_MACH_REALVIEW_PBA8 */
+
+#endif /* __ASM_ARCH_BOARD_PBA8_H */
diff --git a/arch/arm/mach-realview/include/mach/clkdev.h b/arch/arm/mach-realview/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
index 7196bcadff0ce21ef55ce3ee2a7f018eaaad498e..92dbcb9e17923f7f26551f690c74a4d975e1a8e5 100644 (file)
@@ -8,15 +8,36 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
-*/
+ */
+
+#if defined(CONFIG_MACH_REALVIEW_EB) || \
+    defined(CONFIG_MACH_REALVIEW_PB11MP) || \
+    defined(CONFIG_MACH_REALVIEW_PBA8)
+#ifndef DEBUG_LL_UART_OFFSET
+#define DEBUG_LL_UART_OFFSET   0x00009000
+#elif DEBUG_LL_UART_OFFSET != 0x00009000
+#warning "DEBUG_LL_UART_OFFSET already defined to a different value"
+#endif
+#endif
+
+#ifdef CONFIG_MACH_REALVIEW_PB1176
+#ifndef DEBUG_LL_UART_OFFSET
+#define DEBUG_LL_UART_OFFSET   0x0010c000
+#elif DEBUG_LL_UART_OFFSET != 0x0010c000
+#warning "DEBUG_LL_UART_OFFSET already defined to a different value"
+#endif
+#endif
+
+#ifndef DEBUG_LL_UART_OFFSET
+#error "Unknown RealView platform"
+#endif
 
                .macro  addruart,rx
                mrc     p15, 0, \rx, c1, c0
                tst     \rx, #1                 @ MMU enabled?
                moveq   \rx,      #0x10000000
-               movne   \rx,      #0xf0000000   @ virtual base
-               orr     \rx, \rx, #0x00009000
+               movne   \rx,      #0xfb000000   @ virtual base
+               orr     \rx, \rx, #DEBUG_LL_UART_OFFSET
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
diff --git a/arch/arm/mach-realview/include/mach/dma.h b/arch/arm/mach-realview/include/mach/dma.h
deleted file mode 100644 (file)
index f1a5a1a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *  arch/arm/mach-realview/include/mach/dma.h
- *
- *  Copyright (C) 2003 ARM Limited.
- *  Copyright (C) 1997,1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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
- */
index 79a93b3dfca935cbc1f4c0c8a960ce95e6c12a9a..b42c14f89acb4aa0fbce4fc5c9bbfdd2d498b561 100644 (file)
 #include <asm/sizes.h>
 
 /* macro to get at IO space when running virtually */
-#define IO_ADDRESS(x)          (((x) & 0x0fffffff) + 0xf0000000)
+/*
+ * Statically mapped addresses:
+ *
+ * 10xx xxxx -> fbxx xxxx
+ * 1exx xxxx -> fdxx xxxx
+ * 1fxx xxxx -> fexx xxxx
+ */
+#define IO_ADDRESS(x)          (((x) & 0x03ffffff) + 0xfb000000)
 #define __io_address(n)                __io(IO_ADDRESS(n))
 
 #endif
index aa069424d3101d36d5c4bce47947fc47e409d90e..f05bcdf605d8815364c20133ce30c062bd721b9f 100644 (file)
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-
-#define __io(a)                        __io(a)
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 02a918529db39251ea6d0f464f39d8f93218b0b4..fe5cb987aa215d7d4f7a1e1fc0be2bf5a501e439 100644 (file)
@@ -25,6 +25,7 @@
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
 #include <mach/board-pb1176.h>
+#include <mach/board-pba8.h>
 
 #define IRQ_LOCALTIMER         29
 #define IRQ_LOCALWDOG          30
index 0e673483a141d8087ca73cb12e10337de280e996..293c30025e7e0eb42438cf5fb20be26082e7cd2b 100644 (file)
 /*
  * Physical DRAM offset.
  */
+#ifdef CONFIG_REALVIEW_HIGH_PHYS_OFFSET
+#define PHYS_OFFSET            UL(0x70000000)
+#else
 #define PHYS_OFFSET            UL(0x00000000)
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus(x)       ((x) - PAGE_OFFSET)
-#define __bus_to_virt(x)       ((x) + PAGE_OFFSET)
+#endif
 
 #endif
index 79f50f218e77f3a59ee18e14f2e0dab6c0bf2218..415d634d52ab2b8153a24de774e5159357c01a02 100644 (file)
@@ -23,6 +23,7 @@
 #include <mach/board-eb.h>
 #include <mach/board-pb11mp.h>
 #include <mach/board-pb1176.h>
+#include <mach/board-pba8.h>
 
 #define AMBA_UART_DR(base)     (*(volatile unsigned char *)((base) + 0x00))
 #define AMBA_UART_LCRH(base)   (*(volatile unsigned char *)((base) + 0x2c))
@@ -40,6 +41,8 @@ static inline unsigned long get_uart_base(void)
                return REALVIEW_PB11MP_UART0_BASE;
        else if (machine_is_realview_pb1176())
                return REALVIEW_PB1176_UART0_BASE;
+       else if (machine_is_realview_pba8())
+               return REALVIEW_PBA8_UART0_BASE;
        else
                return 0;
 }
index 48cbcc873db255d9477c4ce6fb98b25ca0d0d3b0..fe0de1b507ac20b6305b49ff341e8a0b575251ab 100644 (file)
@@ -18,4 +18,4 @@
  * 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 + 0x18000000)
+#define VMALLOC_END            0xf8000000
index 44d178cd573342b5cc3578353c18b724e9b4f1e8..9019ef2e56115ac72f5b359bd2da1d68999a5d7b 100644 (file)
@@ -38,18 +38,14 @@ void local_timer_interrupt(void)
 
 #ifdef CONFIG_LOCAL_TIMERS
 
-#define TWD_BASE(cpu)  (twd_base_addr + (cpu) * twd_size)
-
 /* set up by the platform code */
-void __iomem *twd_base_addr;
-unsigned int twd_size;
+void __iomem *twd_base;
 
 static unsigned long mpcore_timer_rate;
 
 static void local_timer_set_mode(enum clock_event_mode mode,
                                 struct clock_event_device *clk)
 {
-       void __iomem *base = TWD_BASE(smp_processor_id());
        unsigned long ctrl;
 
        switch(mode) {
@@ -68,17 +64,16 @@ static void local_timer_set_mode(enum clock_event_mode mode,
                ctrl = 0;
        }
 
-       __raw_writel(ctrl, base + TWD_TIMER_CONTROL);
+       __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
 }
 
 static int local_timer_set_next_event(unsigned long evt,
                                      struct clock_event_device *unused)
 {
-       void __iomem *base = TWD_BASE(smp_processor_id());
-       unsigned long ctrl = __raw_readl(base + TWD_TIMER_CONTROL);
+       unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
 
-       __raw_writel(evt, base + TWD_TIMER_COUNTER);
-       __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, base + TWD_TIMER_CONTROL);
+       __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
+       __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL);
 
        return 0;
 }
@@ -91,19 +86,16 @@ static int local_timer_set_next_event(unsigned long evt,
  */
 int local_timer_ack(void)
 {
-       void __iomem *base = TWD_BASE(smp_processor_id());
-
-       if (__raw_readl(base + TWD_TIMER_INTSTAT)) {
-               __raw_writel(1, base + TWD_TIMER_INTSTAT);
+       if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
+               __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
                return 1;
        }
 
        return 0;
 }
 
-static void __cpuinit twd_calibrate_rate(unsigned int cpu)
+static void __cpuinit twd_calibrate_rate(void)
 {
-       void __iomem *base = TWD_BASE(cpu);
        unsigned long load, count;
        u64 waitjiffies;
 
@@ -124,15 +116,15 @@ static void __cpuinit twd_calibrate_rate(unsigned int cpu)
                waitjiffies += 5;
 
                                 /* enable, no interrupt or reload */
-               __raw_writel(0x1, base + TWD_TIMER_CONTROL);
+               __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
 
                                 /* maximum value */
-               __raw_writel(0xFFFFFFFFU, base + TWD_TIMER_COUNTER);
+               __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
 
                while (get_jiffies_64() < waitjiffies)
                        udelay(10);
 
-               count = __raw_readl(base + TWD_TIMER_COUNTER);
+               count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
 
                mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
 
@@ -142,18 +134,19 @@ static void __cpuinit twd_calibrate_rate(unsigned int cpu)
 
        load = mpcore_timer_rate / HZ;
 
-       __raw_writel(load, base + TWD_TIMER_LOAD);
+       __raw_writel(load, twd_base + TWD_TIMER_LOAD);
 }
 
 /*
  * Setup the local clock events for a CPU.
  */
-void __cpuinit local_timer_setup(unsigned int cpu)
+void __cpuinit local_timer_setup(void)
 {
+       unsigned int cpu = smp_processor_id();
        struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
        unsigned long flags;
 
-       twd_calibrate_rate(cpu);
+       twd_calibrate_rate();
 
        clk->name               = "local_timer";
        clk->features           = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
@@ -178,9 +171,9 @@ void __cpuinit local_timer_setup(unsigned int cpu)
 /*
  * take a local timer down
  */
-void __cpuexit local_timer_stop(unsigned int cpu)
+void __cpuexit local_timer_stop(void)
 {
-       __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL);
+       __raw_writel(0, twd_base + TWD_TIMER_CONTROL);
 }
 
 #else  /* CONFIG_LOCAL_TIMERS */
@@ -190,8 +183,9 @@ static void dummy_timer_set_mode(enum clock_event_mode mode,
 {
 }
 
-void __cpuinit local_timer_setup(unsigned int cpu)
+void __cpuinit local_timer_setup(void)
 {
+       unsigned int cpu = smp_processor_id();
        struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
 
        clk->name               = "dummy_timer";
index e102aeb0f76e8d6abdd69e8458b12a11d597a3ce..8fce85f330332d6ffbb27d2a4186a8117c5bccaa 100644 (file)
@@ -23,6 +23,8 @@
 #include <mach/board-pb11mp.h>
 #include <mach/scu.h>
 
+#include "core.h"
+
 extern void realview_secondary_startup(void);
 
 /*
@@ -31,15 +33,20 @@ extern void realview_secondary_startup(void);
  */
 volatile int __cpuinitdata pen_release = -1;
 
+static void __iomem *scu_base_addr(void)
+{
+       if (machine_is_realview_eb_mp())
+               return __io_address(REALVIEW_EB11MP_SCU_BASE);
+       else if (machine_is_realview_pb11mp())
+               return __io_address(REALVIEW_TC11MP_SCU_BASE);
+       else
+               return (void __iomem *)0;
+}
+
 static unsigned int __init get_core_count(void)
 {
        unsigned int ncores;
-       void __iomem *scu_base = 0;
-
-       if (machine_is_realview_eb() && core_tile_eb11mp())
-               scu_base = __io_address(REALVIEW_EB11MP_SCU_BASE);
-       else if (machine_is_realview_pb11mp())
-               scu_base = __io_address(REALVIEW_TC11MP_SCU_BASE);
+       void __iomem *scu_base = scu_base_addr();
 
        if (scu_base) {
                ncores = __raw_readl(scu_base + SCU_CONFIG);
@@ -56,14 +63,7 @@ static unsigned int __init get_core_count(void)
 static void scu_enable(void)
 {
        u32 scu_ctrl;
-       void __iomem *scu_base;
-
-       if (machine_is_realview_eb() && core_tile_eb11mp())
-               scu_base = __io_address(REALVIEW_EB11MP_SCU_BASE);
-       else if (machine_is_realview_pb11mp())
-               scu_base = __io_address(REALVIEW_TC11MP_SCU_BASE);
-       else
-               BUG();
+       void __iomem *scu_base = scu_base_addr();
 
        scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
        scu_ctrl |= 1;
@@ -88,10 +88,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
         * core (e.g. timer irq), then they will not have been enabled
         * for us: do so
         */
-       if (machine_is_realview_eb() && core_tile_eb11mp())
-               gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE));
-       else if (machine_is_realview_pb11mp())
-               gic_cpu_init(0, __io_address(REALVIEW_TC11MP_GIC_CPU_BASE));
+       gic_cpu_init(0, gic_cpu_base_addr);
 
        /*
         * let the primary processor know we're out of the
@@ -232,9 +229,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
         * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in
         * realview_timer_init
         */
-       if ((machine_is_realview_eb() && core_tile_eb11mp()) ||
-           machine_is_realview_pb11mp())
-               local_timer_setup(cpu);
+       local_timer_setup();
 #endif
 
        /*
index eb829eb1ebe29dceb394952205fae68e52575c47..bed39ed976133628be7755cc0e63f395628637dc 100644 (file)
@@ -108,7 +108,7 @@ static struct map_desc realview_eb11mp_io_desc[] __initdata = {
 static void __init realview_eb_map_io(void)
 {
        iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc));
-       if (core_tile_eb11mp())
+       if (core_tile_eb11mp() || core_tile_a9mp())
                iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc));
 }
 
@@ -242,12 +242,6 @@ static struct resource realview_eb_eth_resources[] = {
        },
 };
 
-static struct platform_device realview_eb_eth_device = {
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(realview_eb_eth_resources),
-       .resource       = realview_eb_eth_resources,
-};
-
 /*
  * Detect and register the correct Ethernet device. RealView/EB rev D
  * platforms use the newer SMSC LAN9118 Ethernet chip
@@ -255,26 +249,24 @@ static struct platform_device realview_eb_eth_device = {
 static int eth_device_register(void)
 {
        void __iomem *eth_addr = ioremap(REALVIEW_EB_ETH_BASE, SZ_4K);
+       const char *name = NULL;
        u32 idrev;
 
        if (!eth_addr)
                return -ENOMEM;
 
        idrev = readl(eth_addr + 0x50);
-       if ((idrev & 0xFFFF0000) == 0x01180000)
-               /* SMSC LAN9118 chip present */
-               realview_eb_eth_device.name = "smc911x";
-       else
-               /* SMSC 91C111 chip present */
-               realview_eb_eth_device.name = "smc91x";
+       if ((idrev & 0xFFFF0000) != 0x01180000)
+               /* SMSC LAN9118 not present, use LAN91C111 instead */
+               name = "smc91x";
 
        iounmap(eth_addr);
-       return platform_device_register(&realview_eb_eth_device);
+       return realview_eth_register(name, realview_eb_eth_resources);
 }
 
 static void __init gic_init_irq(void)
 {
-       if (core_tile_eb11mp()) {
+       if (core_tile_eb11mp() || core_tile_a9mp()) {
                unsigned int pldctrl;
 
                /* new irq mode */
@@ -342,10 +334,9 @@ static void __init realview_eb_timer_init(void)
        timer2_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE);
        timer3_va_base = __io_address(REALVIEW_EB_TIMER2_3_BASE) + 0x20;
 
-       if (core_tile_eb11mp()) {
+       if (core_tile_eb11mp() || core_tile_a9mp()) {
 #ifdef CONFIG_LOCAL_TIMERS
-               twd_base_addr = __io_address(REALVIEW_EB11MP_TWD_BASE);
-               twd_size = REALVIEW_EB11MP_TWD_SIZE;
+               twd_base = __io_address(REALVIEW_EB11MP_TWD_BASE);
 #endif
                timer_irq = IRQ_EB11MP_TIMER0_1;
        } else
@@ -362,7 +353,7 @@ static void __init realview_eb_init(void)
 {
        int i;
 
-       if (core_tile_eb11mp()) {
+       if (core_tile_eb11mp() || core_tile_a9mp()) {
                realview_eb11mp_fixup();
 
 #ifdef CONFIG_CACHE_L2X0
@@ -372,8 +363,6 @@ static void __init realview_eb_init(void)
 #endif
        }
 
-       clk_register(&realview_clcd_clk);
-
        realview_flash_register(&realview_eb_flash_resource, 1);
        platform_device_register(&realview_i2c_device);
        eth_device_register();
@@ -392,7 +381,7 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .phys_io        = REALVIEW_EB_UART0_BASE,
        .io_pg_offst    = (IO_ADDRESS(REALVIEW_EB_UART0_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = PHYS_OFFSET + 0x00000100,
        .map_io         = realview_eb_map_io,
        .init_irq       = gic_init_irq,
        .timer          = &realview_eb_timer,
index cccdb3eb90fe94e0a41ffb6e30171759a6a3fe53..8f0683c22140fdced876f5e72c696151faec4ca4 100644 (file)
@@ -222,13 +222,6 @@ static struct resource realview_pb1176_smsc911x_resources[] = {
        },
 };
 
-static struct platform_device realview_pb1176_smsc911x_device = {
-       .name           = "smc911x",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(realview_pb1176_smsc911x_resources),
-       .resource       = realview_pb1176_smsc911x_resources,
-};
-
 static void __init gic_init_irq(void)
 {
        /* ARM1176 DevChip GIC, primary */
@@ -265,10 +258,8 @@ static void __init realview_pb1176_init(void)
        l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff);
 #endif
 
-       clk_register(&realview_clcd_clk);
-
        realview_flash_register(&realview_pb1176_flash_resource, 1);
-       platform_device_register(&realview_pb1176_smsc911x_device);
+       realview_eth_register(NULL, realview_pb1176_smsc911x_resources);
 
        for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
                struct amba_device *d = amba_devs[i];
@@ -284,7 +275,7 @@ MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .phys_io        = REALVIEW_PB1176_UART0_BASE,
        .io_pg_offst    = (IO_ADDRESS(REALVIEW_PB1176_UART0_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = PHYS_OFFSET + 0x00000100,
        .map_io         = realview_pb1176_map_io,
        .init_irq       = gic_init_irq,
        .timer          = &realview_pb1176_timer,
index 8b863148ec18b2b55f3571aa713d3bb787630ed5..3ebdb2dadd6f02c2430fc657a8fc9e51b81d85cb 100644 (file)
@@ -230,13 +230,6 @@ static struct resource realview_pb11mp_smsc911x_resources[] = {
        },
 };
 
-static struct platform_device realview_pb11mp_smsc911x_device = {
-       .name           = "smc911x",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(realview_pb11mp_smsc911x_resources),
-       .resource       = realview_pb11mp_smsc911x_resources,
-};
-
 struct resource realview_pb11mp_cf_resources[] = {
        [0] = {
                .start          = REALVIEW_PB11MP_CF_BASE,
@@ -292,8 +285,7 @@ static void __init realview_pb11mp_timer_init(void)
        timer3_va_base = __io_address(REALVIEW_PB11MP_TIMER2_3_BASE) + 0x20;
 
 #ifdef CONFIG_LOCAL_TIMERS
-       twd_base_addr = __io_address(REALVIEW_TC11MP_TWD_BASE);
-       twd_size = REALVIEW_TC11MP_TWD_SIZE;
+       twd_base = __io_address(REALVIEW_TC11MP_TWD_BASE);
 #endif
        realview_timer_init(IRQ_TC11MP_TIMER0_1);
 }
@@ -312,11 +304,9 @@ static void __init realview_pb11mp_init(void)
        l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff);
 #endif
 
-       clk_register(&realview_clcd_clk);
-
        realview_flash_register(realview_pb11mp_flash_resource,
                                ARRAY_SIZE(realview_pb11mp_flash_resource));
-       platform_device_register(&realview_pb11mp_smsc911x_device);
+       realview_eth_register(NULL, realview_pb11mp_smsc911x_resources);
        platform_device_register(&realview_i2c_device);
        platform_device_register(&realview_pb11mp_cf_device);
 
@@ -334,7 +324,7 @@ MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .phys_io        = REALVIEW_PB11MP_UART0_BASE,
        .io_pg_offst    = (IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE) >> 18) & 0xfffc,
-       .boot_params    = 0x00000100,
+       .boot_params    = PHYS_OFFSET + 0x00000100,
        .map_io         = realview_pb11mp_map_io,
        .init_irq       = gic_init_irq,
        .timer          = &realview_pb11mp_timer,
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
new file mode 100644 (file)
index 0000000..34c9443
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ *  linux/arch/arm/mach-realview/realview_pba8.c
+ *
+ *  Copyright (C) 2008 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/amba/bus.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/gic.h>
+#include <asm/hardware/icst307.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/mmc.h>
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/board-pba8.h>
+#include <mach/irqs.h>
+
+#include "core.h"
+#include "clock.h"
+
+static struct map_desc realview_pba8_io_desc[] __initdata = {
+       {
+               .virtual        = IO_ADDRESS(REALVIEW_SYS_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_SYS_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBA8_GIC_CPU_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBA8_GIC_CPU_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBA8_GIC_DIST_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBA8_GIC_DIST_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_SCTL_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_SCTL_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBA8_TIMER0_1_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBA8_TIMER0_1_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(REALVIEW_PBA8_TIMER2_3_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBA8_TIMER2_3_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+#ifdef CONFIG_PCI
+       {
+               .virtual        = PCIX_UNIT_BASE,
+               .pfn            = __phys_to_pfn(REALVIEW_PBA8_PCI_BASE),
+               .length         = REALVIEW_PBA8_PCI_BASE_SIZE,
+               .type           = MT_DEVICE
+       },
+#endif
+#ifdef CONFIG_DEBUG_LL
+       {
+               .virtual        = IO_ADDRESS(REALVIEW_PBA8_UART0_BASE),
+               .pfn            = __phys_to_pfn(REALVIEW_PBA8_UART0_BASE),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+#endif
+};
+
+static void __init realview_pba8_map_io(void)
+{
+       iotable_init(realview_pba8_io_desc, ARRAY_SIZE(realview_pba8_io_desc));
+}
+
+/*
+ * RealView PBA8Core AMBA devices
+ */
+
+#define GPIO2_IRQ              { IRQ_PBA8_GPIO2, NO_IRQ }
+#define GPIO2_DMA              { 0, 0 }
+#define GPIO3_IRQ              { IRQ_PBA8_GPIO3, NO_IRQ }
+#define GPIO3_DMA              { 0, 0 }
+#define AACI_IRQ               { IRQ_PBA8_AACI, NO_IRQ }
+#define AACI_DMA               { 0x80, 0x81 }
+#define MMCI0_IRQ              { IRQ_PBA8_MMCI0A, IRQ_PBA8_MMCI0B }
+#define MMCI0_DMA              { 0x84, 0 }
+#define KMI0_IRQ               { IRQ_PBA8_KMI0, NO_IRQ }
+#define KMI0_DMA               { 0, 0 }
+#define KMI1_IRQ               { IRQ_PBA8_KMI1, NO_IRQ }
+#define KMI1_DMA               { 0, 0 }
+#define PBA8_SMC_IRQ           { NO_IRQ, NO_IRQ }
+#define PBA8_SMC_DMA           { 0, 0 }
+#define MPMC_IRQ               { NO_IRQ, NO_IRQ }
+#define MPMC_DMA               { 0, 0 }
+#define PBA8_CLCD_IRQ          { IRQ_PBA8_CLCD, NO_IRQ }
+#define PBA8_CLCD_DMA          { 0, 0 }
+#define DMAC_IRQ               { IRQ_PBA8_DMAC, NO_IRQ }
+#define DMAC_DMA               { 0, 0 }
+#define SCTL_IRQ               { NO_IRQ, NO_IRQ }
+#define SCTL_DMA               { 0, 0 }
+#define PBA8_WATCHDOG_IRQ      { IRQ_PBA8_WATCHDOG, NO_IRQ }
+#define PBA8_WATCHDOG_DMA      { 0, 0 }
+#define PBA8_GPIO0_IRQ         { IRQ_PBA8_GPIO0, NO_IRQ }
+#define PBA8_GPIO0_DMA         { 0, 0 }
+#define GPIO1_IRQ              { IRQ_PBA8_GPIO1, NO_IRQ }
+#define GPIO1_DMA              { 0, 0 }
+#define PBA8_RTC_IRQ           { IRQ_PBA8_RTC, NO_IRQ }
+#define PBA8_RTC_DMA           { 0, 0 }
+#define SCI_IRQ                        { IRQ_PBA8_SCI, NO_IRQ }
+#define SCI_DMA                        { 7, 6 }
+#define PBA8_UART0_IRQ         { IRQ_PBA8_UART0, NO_IRQ }
+#define PBA8_UART0_DMA         { 15, 14 }
+#define PBA8_UART1_IRQ         { IRQ_PBA8_UART1, NO_IRQ }
+#define PBA8_UART1_DMA         { 13, 12 }
+#define PBA8_UART2_IRQ         { IRQ_PBA8_UART2, NO_IRQ }
+#define PBA8_UART2_DMA         { 11, 10 }
+#define PBA8_UART3_IRQ         { IRQ_PBA8_UART3, NO_IRQ }
+#define PBA8_UART3_DMA         { 0x86, 0x87 }
+#define PBA8_SSP_IRQ           { IRQ_PBA8_SSP, NO_IRQ }
+#define PBA8_SSP_DMA           { 9, 8 }
+
+/* FPGA Primecells */
+AMBA_DEVICE(aaci,      "fpga:04",      AACI,           NULL);
+AMBA_DEVICE(mmc0,      "fpga:05",      MMCI0,          &realview_mmc0_plat_data);
+AMBA_DEVICE(kmi0,      "fpga:06",      KMI0,           NULL);
+AMBA_DEVICE(kmi1,      "fpga:07",      KMI1,           NULL);
+AMBA_DEVICE(uart3,     "fpga:09",      PBA8_UART3,     NULL);
+
+/* DevChip Primecells */
+AMBA_DEVICE(smc,       "dev:00",       PBA8_SMC,       NULL);
+AMBA_DEVICE(sctl,      "dev:e0",       SCTL,           NULL);
+AMBA_DEVICE(wdog,      "dev:e1",       PBA8_WATCHDOG, NULL);
+AMBA_DEVICE(gpio0,     "dev:e4",       PBA8_GPIO0,     NULL);
+AMBA_DEVICE(gpio1,     "dev:e5",       GPIO1,          NULL);
+AMBA_DEVICE(gpio2,     "dev:e6",       GPIO2,          NULL);
+AMBA_DEVICE(rtc,       "dev:e8",       PBA8_RTC,       NULL);
+AMBA_DEVICE(sci0,      "dev:f0",       SCI,            NULL);
+AMBA_DEVICE(uart0,     "dev:f1",       PBA8_UART0,     NULL);
+AMBA_DEVICE(uart1,     "dev:f2",       PBA8_UART1,     NULL);
+AMBA_DEVICE(uart2,     "dev:f3",       PBA8_UART2,     NULL);
+AMBA_DEVICE(ssp0,      "dev:f4",       PBA8_SSP,       NULL);
+
+/* Primecells on the NEC ISSP chip */
+AMBA_DEVICE(clcd,      "issp:20",      PBA8_CLCD,      &clcd_plat_data);
+AMBA_DEVICE(dmac,      "issp:30",      DMAC,           NULL);
+
+static struct amba_device *amba_devs[] __initdata = {
+       &dmac_device,
+       &uart0_device,
+       &uart1_device,
+       &uart2_device,
+       &uart3_device,
+       &smc_device,
+       &clcd_device,
+       &sctl_device,
+       &wdog_device,
+       &gpio0_device,
+       &gpio1_device,
+       &gpio2_device,
+       &rtc_device,
+       &sci0_device,
+       &ssp0_device,
+       &aaci_device,
+       &mmc0_device,
+       &kmi0_device,
+       &kmi1_device,
+};
+
+/*
+ * RealView PB-A8 platform devices
+ */
+static struct resource realview_pba8_flash_resource[] = {
+       [0] = {
+               .start          = REALVIEW_PBA8_FLASH0_BASE,
+               .end            = REALVIEW_PBA8_FLASH0_BASE + REALVIEW_PBA8_FLASH0_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = REALVIEW_PBA8_FLASH1_BASE,
+               .end            = REALVIEW_PBA8_FLASH1_BASE + REALVIEW_PBA8_FLASH1_SIZE - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct resource realview_pba8_smsc911x_resources[] = {
+       [0] = {
+               .start          = REALVIEW_PBA8_ETH_BASE,
+               .end            = REALVIEW_PBA8_ETH_BASE + SZ_64K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = IRQ_PBA8_ETH,
+               .end            = IRQ_PBA8_ETH,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+struct resource realview_pba8_cf_resources[] = {
+       [0] = {
+               .start          = REALVIEW_PBA8_CF_BASE,
+               .end            = REALVIEW_PBA8_CF_BASE + SZ_4K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start          = REALVIEW_PBA8_CF_MEM_BASE,
+               .end            = REALVIEW_PBA8_CF_MEM_BASE + SZ_4K - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start          = -1,           /* FIXME: Find correct irq */
+               .end            = -1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device realview_pba8_cf_device = {
+       .name           = "compactflash",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(realview_pba8_cf_resources),
+       .resource       = realview_pba8_cf_resources,
+};
+
+static void __init gic_init_irq(void)
+{
+       /* ARM PB-A8 on-board GIC */
+       gic_cpu_base_addr = __io_address(REALVIEW_PBA8_GIC_CPU_BASE);
+       gic_dist_init(0, __io_address(REALVIEW_PBA8_GIC_DIST_BASE), IRQ_PBA8_GIC_START);
+       gic_cpu_init(0, __io_address(REALVIEW_PBA8_GIC_CPU_BASE));
+}
+
+static void __init realview_pba8_timer_init(void)
+{
+       timer0_va_base = __io_address(REALVIEW_PBA8_TIMER0_1_BASE);
+       timer1_va_base = __io_address(REALVIEW_PBA8_TIMER0_1_BASE) + 0x20;
+       timer2_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE);
+       timer3_va_base = __io_address(REALVIEW_PBA8_TIMER2_3_BASE) + 0x20;
+
+       realview_timer_init(IRQ_PBA8_TIMER0_1);
+}
+
+static struct sys_timer realview_pba8_timer = {
+       .init           = realview_pba8_timer_init,
+};
+
+static void __init realview_pba8_init(void)
+{
+       int i;
+
+       realview_flash_register(realview_pba8_flash_resource,
+                               ARRAY_SIZE(realview_pba8_flash_resource));
+       realview_eth_register(NULL, realview_pba8_smsc911x_resources);
+       platform_device_register(&realview_i2c_device);
+       platform_device_register(&realview_pba8_cf_device);
+
+       for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+               struct amba_device *d = amba_devs[i];
+               amba_device_register(d, &iomem_resource);
+       }
+
+#ifdef CONFIG_LEDS
+       leds_event = realview_leds_event;
+#endif
+}
+
+MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
+       /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+       .phys_io        = REALVIEW_PBA8_UART0_BASE,
+       .io_pg_offst    = (IO_ADDRESS(REALVIEW_PBA8_UART0_BASE) >> 18) & 0xfffc,
+       .boot_params    = PHYS_OFFSET + 0x00000100,
+       .map_io         = realview_pba8_map_io,
+       .init_irq       = gic_init_irq,
+       .timer          = &realview_pba8_timer,
+       .init_machine   = realview_pba8_init,
+MACHINE_END
index 9f0553b7ec28d4417ddbce9e4a6393eb502b88d3..20da7f486e5167627378d3a9442db8fff0a7d370 100644 (file)
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-/*
- * GCC is totally crap at loading/storing data.  We try to persuade it
- * to do the right thing by using these whereever possible instead of
- * the above.
- */
-#define __arch_base_getb(b,o)                  \
- ({                                            \
-       unsigned int __v, __r = (b);            \
-       __asm__ __volatile__(                   \
-               "ldrb   %0, [%1, %2]"           \
-               : "=r" (__v)                    \
-               : "r" (__r), "Ir" (o));         \
-       __v;                                    \
- })
-
-#define __arch_base_getl(b,o)                  \
- ({                                            \
-       unsigned int __v, __r = (b);            \
-       __asm__ __volatile__(                   \
-               "ldr    %0, [%1, %2]"           \
-               : "=r" (__v)                    \
-               : "r" (__r), "Ir" (o));         \
-       __v;                                    \
- })
-
-#define __arch_base_putb(v,b,o)                        \
- ({                                            \
-       unsigned int __r = (b);                 \
-       __asm__ __volatile__(                   \
-               "strb   %0, [%1, %2]"           \
-               :                               \
-               : "r" (v), "r" (__r), "Ir" (o));\
- })
-
-#define __arch_base_putl(v,b,o)                        \
- ({                                            \
-       unsigned int __r = (b);                 \
-       __asm__ __volatile__(                   \
-               "str    %0, [%1, %2]"           \
-               :                               \
-               : "r" (v), "r" (__r), "Ir" (o));\
- })
-
 /*
  * We use two different types of addressing - PC style addresses, and ARM
  * addresses.  PC style accesses the PC hardware with the normal PC IO
@@ -232,15 +189,13 @@ DECLARE_IO(int,l,"")
        result;                                                                 \
 })
 
-#define __ioaddrc(port)                __ioaddr(port)
-
 #define inb(p)         (__builtin_constant_p((p)) ? __inbc(p)    : __inb(p))
 #define inw(p)         (__builtin_constant_p((p)) ? __inwc(p)    : __inw(p))
 #define inl(p)         (__builtin_constant_p((p)) ? __inlc(p)    : __inl(p))
 #define outb(v,p)      (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
 #define outw(v,p)      (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
 #define outl(v,p)      (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-#define __ioaddr(p)    (__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p))
+
 /* the following macro is deprecated */
 #define ioaddr(port)   ((unsigned long)__ioaddr((port)))
 
index 4ce6ca97f66966dd530661bc697cb21c84895db5..3d2037496e38cd4955f29ecb9ca1f09e715e7608 100644 (file)
@@ -44,3 +44,4 @@
 
 #define IRQ_TIMER              IRQ_TIMER0
 
+#define NR_IRQS                        128
similarity index 71%
rename from arch/arm/mach-rpc/include/mach/dma.h
rename to arch/arm/mach-rpc/include/mach/isa-dma.h
index 360b56f8f29f10b87cd7183ba7ce7199acca0ca1..bad720548587e1b1722f3b8fa1b7071d0cb6f2de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  arch/arm/mach-rpc/include/mach/dma.h
+ *  arch/arm/mach-rpc/include/mach/isa-dma.h
  *
  *  Copyright (C) 1997 Russell King
  *
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
 
-/*
- * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
- */
-#define MAX_DMA_ADDRESS                0xd0000000
 #define MAX_DMA_CHANNELS       8
 
 #define DMA_0                  0
index 9bf7e43e286337f8847a59c79c96303a022d9f45..78191bf251926838b31e02fc8b19bc6158c5d2a1 100644 (file)
  */
 #define PHYS_OFFSET    UL(0x10000000)
 
-/*
- * These are exactly the same on the RiscPC as the
- * physical memory view.
- */
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
 /*
  * Cache flushing area - ROM
  */
index 8f4878e4f591930af6d1a2d88bca838aeff14e2e..cf5901ffd38519a7357d19924741f55885361906 100644 (file)
@@ -17,7 +17,4 @@
 
 #define PHYS_OFFSET    UL(0x0C000000)
 
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
 #endif
index 99fdc736698c25c2428aa6ede50a759b718d84b3..63a30d1dd4250e6c838d3e5c63242a3fa1959116 100644 (file)
@@ -7,6 +7,7 @@
 config CPU_S3C2410
        bool
        depends on ARCH_S3C2410
+       select CPU_ARM920T
        select S3C2410_CLOCK
        select S3C2410_GPIO
        select CPU_LLSERIAL_S3C2410
@@ -32,11 +33,6 @@ config S3C2410_GPIO
        help
          GPIO code for S3C2410 and similar processors
 
-config S3C2410_CLOCK
-       bool
-       help
-         Clock code for the S3C2410, and similar processors
-
 config SIMTEC_NOR
        bool
        help
@@ -84,6 +80,7 @@ config ARCH_BAST
        select PM_SIMTEC if PM
        select SIMTEC_NOR
        select MACH_BAST_IDE
+       select S3C24XX_DCLK
        select ISA
        help
          Say Y here if you are using the Simtec Electronics EB2410ITX
@@ -121,6 +118,7 @@ config MACH_TCT_HAMMER
 config MACH_VR1000
        bool "Thorcom VR1000"
        select PM_SIMTEC if PM
+       select S3C24XX_DCLK
        select SIMTEC_NOR
        select MACH_BAST_IDE
        select CPU_S3C2410
index 00f31f8c4e7814bafb347b5efab6cec6fc9a6d50..fca02f82711c03339c65f93fee75ce196ca830eb 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
 obj-$(CONFIG_CPU_S3C2410_DMA)  += dma.o
 obj-$(CONFIG_S3C2410_PM)       += pm.o sleep.o
 obj-$(CONFIG_S3C2410_GPIO)     += gpio.o
-obj-$(CONFIG_S3C2410_CLOCK)    += clock.o
 
 # Machine support
 
index 7d914a470b6c7d228d8bf841380524b6fd65a56f..552b4c778fdc7f6ab450cae8df014570f7f36ee1 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 
-#include <asm/dma.h>
 #include <mach/dma.h>
 
 #include <plat/cpu.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-ac97.h>
+#include <plat/regs-ac97.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
 #include <asm/plat-s3c24xx/regs-iis.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
        [DMACH_XD0] = {
index 891b53cd69b86a6a3e543fd3f3a7a34a53471bc6..13358ce2128c7c16346d4d65932c13dbf3630cdf 100644 (file)
 #include <linux/sysdev.h>
 #include <mach/hardware.h>
 
-/*
- * This is the maximum DMA address(physical address) that can be DMAd to.
- *
- */
-#define MAX_DMA_ADDRESS                0x40000000
 #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
 
 /* We use `virtual` dma channels to hide the fact we have only a limited
@@ -254,7 +249,7 @@ typedef unsigned long dma_device_t;
  * request a dma channel exclusivley
 */
 
-extern int s3c2410_dma_request(dmach_t channel,
+extern int s3c2410_dma_request(unsigned int channel,
                               struct s3c2410_dma_client *, void *dev);
 
 
@@ -263,14 +258,14 @@ extern int s3c2410_dma_request(dmach_t channel,
  * change the state of the dma channel
 */
 
-extern int s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op);
+extern int s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op);
 
 /* s3c2410_dma_setflags
  *
  * set the channel's flags to a given state
 */
 
-extern int s3c2410_dma_setflags(dmach_t channel,
+extern int s3c2410_dma_setflags(unsigned int channel,
                                unsigned int flags);
 
 /* s3c2410_dma_free
@@ -278,7 +273,7 @@ extern int s3c2410_dma_setflags(dmach_t channel,
  * free the dma channel (will also abort any outstanding operations)
 */
 
-extern int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *);
+extern int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *);
 
 /* s3c2410_dma_enqueue
  *
@@ -287,7 +282,7 @@ extern int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *);
  * drained before the buffer is given to the DMA system.
 */
 
-extern int s3c2410_dma_enqueue(dmach_t channel, void *id,
+extern int s3c2410_dma_enqueue(unsigned int channel, void *id,
                               dma_addr_t data, int size);
 
 /* s3c2410_dma_config
@@ -295,7 +290,7 @@ extern int s3c2410_dma_enqueue(dmach_t channel, void *id,
  * configure the dma channel
 */
 
-extern int s3c2410_dma_config(dmach_t channel, int xferunit, int dcon);
+extern int s3c2410_dma_config(unsigned int channel, int xferunit, int dcon);
 
 /* s3c2410_dma_devconfig
  *
@@ -310,11 +305,11 @@ extern int s3c2410_dma_devconfig(int channel, enum s3c2410_dmasrc source,
  * get the position that the dma transfer is currently at
 */
 
-extern int s3c2410_dma_getposition(dmach_t channel,
+extern int s3c2410_dma_getposition(unsigned int channel,
                                   dma_addr_t *src, dma_addr_t *dest);
 
-extern int s3c2410_dma_set_opfn(dmach_t, s3c2410_dma_opfn_t rtn);
-extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
+extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
+extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
 
 /* DMA Register definitions */
 
diff --git a/arch/arm/mach-s3c2410/include/mach/gpio-core.h b/arch/arm/mach-s3c2410/include/mach/gpio-core.h
new file mode 100644 (file)
index 0000000..6c9fbb9
--- /dev/null
@@ -0,0 +1,34 @@
+/* arch/arm/mach-s3c24100/include/mach/gpio-core.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C2410 - GPIO core support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_GPIO_CORE_H
+#define __ASM_ARCH_GPIO_CORE_H __FILE__
+
+#include <plat/gpio-core.h>
+#include <mach/regs-gpio.h>
+
+extern struct s3c_gpio_chip s3c24xx_gpios[];
+
+static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int pin)
+{
+       struct s3c_gpio_chip *chip;
+
+       if (pin > S3C2410_GPG10)
+               return NULL;
+
+       chip = &s3c24xx_gpios[pin/32];
+       return (S3C2410_GPIO_OFFSET(pin) > chip->chip.ngpio) ? chip : NULL;
+}
+
+#endif /* __ASM_ARCH_GPIO_CORE_H */
index 3b52b86498a6a4060cccaee1f720b61bb5a02674..e0349af8a483f29be67a42ff302f155670792b94 100644 (file)
 #define gpio_set_value __gpio_set_value
 #define gpio_cansleep  __gpio_cansleep
 
+/* some boards require extra gpio capacity to support external
+ * devices that need GPIO.
+ */
+
+#define ARCH_NR_GPIOS  (256 + CONFIG_S3C24XX_GPIO_EXTRA)
+
 #include <asm-generic/gpio.h>
index 950c71bf14893376341e9e6ecc3768b882419993..9565903d490b971f864a8f9ae271fdc9c4f07215 100644 (file)
 #define IRQ_S3C2443_HSMMC      S3C2410_IRQ(20)         /* IRQ_SDI */
 #define IRQ_S3C2443_NAND       S3C2410_IRQ(24)         /* reserved */
 
+#define IRQ_HSMMC0             IRQ_S3C2443_HSMMC
+
 #define IRQ_S3C2443_LCD1       S3C2410_IRQSUB(14)
 #define IRQ_S3C2443_LCD2       S3C2410_IRQSUB(15)
 #define IRQ_S3C2443_LCD3       S3C2410_IRQSUB(16)
 #define NR_IRQS (IRQ_S3C2440_AC97+1)
 #endif
 
+/* compatibility define. */
+#define IRQ_UART3              IRQ_S3C2443_UART3
+#define IRQ_S3CUART_RX3                IRQ_S3C2443_RX3
+#define IRQ_S3CUART_TX3                IRQ_S3C2443_TX3
+#define IRQ_S3CUART_ERR3       IRQ_S3C2443_ERR3
+
 /* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */
 #define FIQ_START              IRQ_EINT0
 
index 23c470c2e5b13cf1420a542875c80ab07547cc4a..255fdfeaf957a6d80e692cd24430dca7ec409c58 100644 (file)
 #ifndef __ASM_ARCH_MAP_H
 #define __ASM_ARCH_MAP_H
 
+#include <plat/map-base.h>
 #include <plat/map.h>
 
 #define S3C2410_ADDR(x)                S3C_ADDR(x)
 
-/* interrupt controller is the first thing we put in, to make
- * the assembly code for the irq detection easier
- */
-#define S3C24XX_VA_IRQ    S3C_VA_IRQ
-#define S3C2410_PA_IRQ    (0x4A000000)
-#define S3C24XX_SZ_IRQ    SZ_1M
-
-/* memory controller registers */
-#define S3C24XX_VA_MEMCTRL S3C_VA_MEM
-#define S3C2410_PA_MEMCTRL (0x48000000)
-#define S3C24XX_SZ_MEMCTRL SZ_1M
-
 /* USB host controller */
 #define S3C2410_PA_USBHOST (0x49000000)
-#define S3C24XX_SZ_USBHOST SZ_1M
 
 /* DMA controller */
 #define S3C2410_PA_DMA    (0x4B000000)
 #define S3C24XX_SZ_DMA    SZ_1M
 
 /* Clock and Power management */
-#define S3C24XX_VA_CLKPWR  S3C_VA_SYS
 #define S3C2410_PA_CLKPWR  (0x4C000000)
-#define S3C24XX_SZ_CLKPWR  SZ_1M
 
 /* LCD controller */
 #define S3C2410_PA_LCD    (0x4D000000)
 
 /* NAND flash controller */
 #define S3C2410_PA_NAND           (0x4E000000)
-#define S3C24XX_SZ_NAND           SZ_1M
-
-/* UARTs */
-#define S3C24XX_VA_UART           S3C_VA_UART
-#define S3C2410_PA_UART           (0x50000000)
-#define S3C24XX_SZ_UART           SZ_1M
-
-/* Timers */
-#define S3C24XX_VA_TIMER   S3C_VA_TIMER
-#define S3C2410_PA_TIMER   (0x51000000)
-#define S3C24XX_SZ_TIMER   SZ_1M
-
-/* USB Device port */
-#define S3C2410_PA_USBDEV  (0x52000000)
-#define S3C24XX_SZ_USBDEV  SZ_1M
-
-/* Watchdog */
-#define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG
-#define S3C2410_PA_WATCHDOG (0x53000000)
-#define S3C24XX_SZ_WATCHDOG SZ_1M
 
 /* IIC hardware controller */
 #define S3C2410_PA_IIC    (0x54000000)
-#define S3C24XX_SZ_IIC    SZ_1M
 
 /* IIS controller */
 #define S3C2410_PA_IIS    (0x55000000)
-#define S3C24XX_SZ_IIS    SZ_1M
-
-/* GPIO ports */
-
-/* the calculation for the VA of this must ensure that
- * it is the same distance apart from the UART in the
- * phsyical address space, as the initial mapping for the IO
- * is done as a 1:1 maping. This puts it (currently) at
- * 0xFA800000, which is not in the way of any current mapping
- * by the base system.
-*/
-
-#define S3C2410_PA_GPIO           (0x56000000)
-#define S3C24XX_VA_GPIO           ((S3C2410_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
-#define S3C24XX_SZ_GPIO           SZ_1M
 
 /* RTC */
 #define S3C2410_PA_RTC    (0x57000000)
 
 /* ADC */
 #define S3C2410_PA_ADC    (0x58000000)
-#define S3C24XX_SZ_ADC    SZ_1M
 
 /* SPI */
 #define S3C2410_PA_SPI    (0x59000000)
-#define S3C24XX_SZ_SPI    SZ_1M
 
 /* SDI */
 #define S3C2410_PA_SDI    (0x5A000000)
-#define S3C24XX_SZ_SDI    SZ_1M
 
 /* CAMIF */
 #define S3C2440_PA_CAMIF   (0x4F000000)
 #define S3C2443_PA_HSMMC   (0x4A800000)
 #define S3C2443_SZ_HSMMC   (256)
 
-/* ISA style IO, for each machine to sort out mappings for, if it
- * implements it. We reserve two 16M regions for ISA.
- */
-
-#define S3C24XX_VA_ISA_WORD  S3C2410_ADDR(0x02000000)
-#define S3C24XX_VA_ISA_BYTE  S3C2410_ADDR(0x03000000)
-
 /* physical addresses of all the chip-select areas */
 
 #define S3C2410_CS0 (0x00000000)
 #define S3C24XX_PA_TIMER    S3C2410_PA_TIMER
 #define S3C24XX_PA_USBDEV   S3C2410_PA_USBDEV
 #define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG
-#define S3C24XX_PA_IIC      S3C2410_PA_IIC
 #define S3C24XX_PA_IIS      S3C2410_PA_IIS
 #define S3C24XX_PA_GPIO     S3C2410_PA_GPIO
 #define S3C24XX_PA_RTC      S3C2410_PA_RTC
 #define S3C24XX_PA_ADC      S3C2410_PA_ADC
 #define S3C24XX_PA_SPI      S3C2410_PA_SPI
+#define S3C24XX_PA_SDI      S3C2410_PA_SDI
+#define S3C24XX_PA_NAND            S3C2410_PA_NAND
 
-/* deal with the registers that move under the 2412/2413 */
-
-#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
-#ifndef __ASSEMBLY__
-extern void __iomem *s3c24xx_va_gpio2;
-#endif
-#ifdef CONFIG_CPU_S3C2412_ONLY
-#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10)
-#else
-#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2
-#endif
-#else
-#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO
-#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO
-#endif
+#define S3C_PA_IIC          S3C2410_PA_IIC
+#define S3C_PA_UART        S3C24XX_PA_UART
+#define S3C_PA_HSMMC0      S3C2443_PA_HSMMC
 
 #endif /* __ASM_ARCH_MAP_H */
index 93782628a786dbb476fa282614b565fcda6b5b95..6f1e5871ae4be02a8cfe130e3dd42cc4b7a26f91 100644 (file)
@@ -13,7 +13,4 @@
 
 #define PHYS_OFFSET    UL(0x30000000)
 
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt(x) __phys_to_virt(x)
-
 #endif
index b3f90aa7807689b390eb74a97944ffeabfcd0cba..2a5d90e957fb5c3353a561493dae335028fc5922 100644 (file)
 #define S3C2410_CLKCON_IIS          (1<<17)
 #define S3C2410_CLKCON_SPI          (1<<18)
 
-#define S3C2410_PLLCON_MDIVSHIFT     12
-#define S3C2410_PLLCON_PDIVSHIFT     4
-#define S3C2410_PLLCON_SDIVSHIFT     0
-#define S3C2410_PLLCON_MDIVMASK             ((1<<(1+(19-12)))-1)
-#define S3C2410_PLLCON_PDIVMASK             ((1<<5)-1)
-#define S3C2410_PLLCON_SDIVMASK             3
-
 /* DCLKCON register addresses in gpio.h */
 
 #define S3C2410_DCLKCON_DCLK0EN             (1<<0)
 #define S3C2410_CLKSLOW_SLOWVAL(x)     (x)
 #define S3C2410_CLKSLOW_GET_SLOWVAL(x) ((x) & 7)
 
-#ifndef __ASSEMBLY__
-
-#include <asm/div64.h>
-
-static inline unsigned int
-s3c2410_get_pll(unsigned int pllval, unsigned int baseclk)
-{
-       unsigned int mdiv, pdiv, sdiv;
-       uint64_t fvco;
-
-       mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT;
-       pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT;
-       sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT;
-
-       mdiv &= S3C2410_PLLCON_MDIVMASK;
-       pdiv &= S3C2410_PLLCON_PDIVMASK;
-       sdiv &= S3C2410_PLLCON_SDIVMASK;
-
-       fvco = (uint64_t)baseclk * (mdiv + 8);
-       do_div(fvco, (pdiv + 2) << sdiv);
-
-       return (unsigned int)fvco;
-}
-
-#endif /* __ASSEMBLY__ */
-
 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
 
 /* extra registers */
index 528080ceac44ddf7edfd9b9aa267a1c9590156b6..3210776130672b5e47dd51529c522500c47f1861 100644 (file)
 #define S3C24XX_EXTINT1           S3C24XX_GPIOREG2(0x8C)
 #define S3C24XX_EXTINT2           S3C24XX_GPIOREG2(0x90)
 
-/* values for S3C2410_EXTINT0/1/2 */
-#define S3C2410_EXTINT_LOWLEV   (0x00)
-#define S3C2410_EXTINT_HILEV    (0x01)
-#define S3C2410_EXTINT_FALLEDGE         (0x02)
-#define S3C2410_EXTINT_RISEEDGE         (0x04)
-#define S3C2410_EXTINT_BOTHEDGE         (0x06)
-
 /* interrupt filtering conrrol for EINT16..EINT23 */
 #define S3C2410_EINFLT0           S3C2410_GPIOREG(0x94)
 #define S3C2410_EINFLT1           S3C2410_GPIOREG(0x98)
index 46d46f5b99f2817b92c43729928371f0d3a8fb08..774f3adfe8ade0fb5bef6a5d2defc5af3fc4e6bf 100644 (file)
@@ -22,5 +22,12 @@ struct s3c2410_spi_info {
        void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
 };
 
+/* Standard setup / suspend routines for SPI GPIO pins. */
+
+extern void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
+                                                int enable);
+
+extern void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
+                                             int enable);
 
 #endif /* __ASM_ARCH_SPI_H */
index 43535a0e718699ca063b648ce37443fd68e6d5aa..7613d0a384ba23d47cd054562e8aa50b66dfff9d 100644 (file)
@@ -13,7 +13,7 @@
 #include <mach/hardware.h>
 #include <linux/io.h>
 
-#include <asm/plat-s3c/regs-watchdog.h>
+#include <plat/regs-watchdog.h>
 #include <mach/regs-clock.h>
 
 #include <linux/clk.h>
diff --git a/arch/arm/mach-s3c2410/include/mach/tick.h b/arch/arm/mach-s3c2410/include/mach/tick.h
new file mode 100644 (file)
index 0000000..544da41
--- /dev/null
@@ -0,0 +1,15 @@
+/* linux/arch/arm/mach-s3c2410/include/mach/tick.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C2410 - timer tick support
+ */
+
+#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
+
+static inline int s3c24xx_ostimer_pending(void)
+{
+       return __raw_readl(S3C2410_SRCPND) & SRCPND_TIMER4;
+}
index ab39491beee209328854aef56651b4e829d30171..c9432103750d3a1ab7f67461b170ae550b4acbd1 100644 (file)
@@ -1,3 +1,4 @@
+
 /* arch/arm/mach-s3c2410/include/mach/uncompress.h
  *
  * Copyright (c) 2003, 2007 Simtec Electronics
index d061fea01900138879c776af78150e2966942db3..6d6995afeb439013d19833cc1f360c986a270b32 100644 (file)
@@ -52,6 +52,7 @@
 #include <mach/regs-lcd.h>
 #include <mach/regs-gpio.h>
 
+#include <plat/iic.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
 
@@ -150,7 +151,7 @@ static struct platform_device *amlm5900_devices[] __initdata = {
 #endif
        &s3c_device_adc,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_usb,
        &s3c_device_rtc,
        &s3c_device_usbgadget,
@@ -233,6 +234,7 @@ static void __init amlm5900_init(void)
 #ifdef CONFIG_FB_S3C2410
        s3c24xx_fb_set_platdata(&amlm5900_fb_info);
 #endif
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices));
 }
 
index 8db9c700e3c24cbf621a2403960e6fe159ac4fb3..01bd76725b920040a6b7ea1687d1c84770f32f54 100644 (file)
@@ -44,8 +44,8 @@
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 
-#include <asm/plat-s3c/nand.h>
-#include <asm/plat-s3c/iic.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
 #include <mach/fb.h>
 
 #include <linux/mtd/mtd.h>
@@ -406,7 +406,7 @@ static struct platform_device bast_sio = {
  * standard 100KHz i2c bus frequency
 */
 
-static struct s3c2410_platform_i2c bast_i2c_info = {
+static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
        .flags          = 0,
        .slave_addr     = 0x10,
        .bus_freq       = 100*1000,
@@ -553,7 +553,7 @@ static struct platform_device *bast_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_rtc,
        &s3c_device_nand,
        &bast_device_dm9k,
@@ -588,7 +588,8 @@ static void __init bast_map_io(void)
        s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
 
        s3c_device_nand.dev.platform_data = &bast_nand_info;
-       s3c_device_i2c.dev.platform_data = &bast_i2c_info;
+
+       s3c_i2c0_set_platdata(&bast_i2c_info);
 
        s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
        s3c24xx_init_clocks(0);
index 98716d0108e9d670747c56b45598fb78253961b2..821a1668c3acccd6a1bee3abafe79a82008960a4 100644 (file)
 #include <mach/h1940.h>
 #include <mach/h1940-latch.h>
 #include <mach/fb.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
 
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/pll.h>
 #include <plat/pm.h>
 
 static struct map_desc h1940_iodesc[] __initdata = {
@@ -183,7 +185,7 @@ static struct platform_device *h1940_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_usbgadget,
        &s3c_device_leds,
@@ -215,6 +217,7 @@ static void __init h1940_init(void)
 
        s3c24xx_fb_set_platdata(&h1940_fb_info);
        s3c24xx_udc_set_platdata(&h1940_udc_cfg);
+       s3c_i2c0_set_platdata(NULL);
 
        /* Turn off suspend on both USB ports, and switch the
         * selectable USB port to USB device mode. */
@@ -223,10 +226,9 @@ static void __init h1940_init(void)
                              S3C2410_MISCCR_USBSUSPND0 |
                              S3C2410_MISCCR_USBSUSPND1, 0x0);
 
-       tmp = (
-                0x78 << S3C2410_PLLCON_MDIVSHIFT)
-             | (0x02 << S3C2410_PLLCON_PDIVSHIFT)
-             | (0x03 << S3C2410_PLLCON_SDIVSHIFT);
+       tmp =   (0x78 << S3C24XX_PLLCON_MDIVSHIFT)
+             | (0x02 << S3C24XX_PLLCON_PDIVSHIFT)
+             | (0x03 << S3C24XX_PLLCON_SDIVSHIFT);
        writel(tmp, S3C2410_UPLLCON);
 
        platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
index 82505517846c532f32e87db5e927e0da18e541fa..05a5e877b49b73b7ccfa20734544b8f1f089e2c7 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
-#include <linux/delay.h>
 #include <linux/gpio_keys.h>
 #include <linux/init.h>
 #include <linux/input.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 
-#include <asm/plat-s3c/iic.h>
+#include <plat/iic.h>
 #include <plat/regs-serial.h>
 
 #include <plat/clock.h>
 #include <plat/cpu.h>
 #include <plat/devs.h>
 #include <plat/s3c2410.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/udc.h>
 
 static struct map_desc n30_iodesc[] __initdata = {
        /* nothing here yet */
@@ -320,7 +319,7 @@ static struct s3c2410fb_mach_info n30_fb_info __initdata = {
 static struct platform_device *n30_devices[] __initdata = {
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_usb,
        &s3c_device_usbgadget,
@@ -332,7 +331,7 @@ static struct platform_device *n30_devices[] __initdata = {
 static struct platform_device *n35_devices[] __initdata = {
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_usbgadget,
        &n35_button_device,
@@ -501,7 +500,7 @@ static void __init n30_init_irq(void)
 static void __init n30_init(void)
 {
        s3c24xx_fb_set_platdata(&n30_fb_info);
-       s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+       s3c_device_i2c0.dev.platform_data = &n30_i2ccfg;
        s3c24xx_udc_set_platdata(&n30_udc_cfg);
 
        /* Turn off suspend on both USB ports, and switch the
index d8255cf87e446ef07f8f719d2413bf2957ab6b1a..f6c7261a4a12b56ff545cd293c4016dda25941a0 100644 (file)
@@ -35,6 +35,7 @@
 #include <plat/s3c2410.h>
 #include <plat/clock.h>
 #include <plat/devs.h>
+#include <plat/iic.h>
 #include <plat/cpu.h>
 
 static struct map_desc otom11_iodesc[] __initdata = {
@@ -94,7 +95,7 @@ static struct platform_device *otom11_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_rtc,
        &otom_device_nor,
@@ -109,6 +110,7 @@ static void __init otom11_map_io(void)
 
 static void __init otom11_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices));
 }
 
index 661807e14e8a56f8b2c1eb304bc15543a5b05d31..9678a53ceeb13589da76d6328fa1003dd00fd305 100644 (file)
 #include <mach/leds-gpio.h>
 #include <plat/regs-serial.h>
 #include <mach/fb.h>
-#include <asm/plat-s3c/nand.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/nand.h>
+#include <plat/udc.h>
 #include <mach/spi.h>
 #include <mach/spi-gpio.h>
+#include <plat/iic.h>
 
 #include <plat/common-smdk.h>
 #include <plat/devs.h>
@@ -247,7 +248,7 @@ static struct platform_device *qt2410_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_sdi,
        &s3c_device_usbgadget,
@@ -349,6 +350,7 @@ static void __init qt2410_machine_init(void)
        s3c2410_gpio_setpin(S3C2410_GPB0, 1);
 
        s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
+       s3c_i2c0_set_platdata(NULL);
 
        s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT);
 
index 152527bb287290e28522c581fbff65368eab4b08..c49126ccb1d59dadeed853e4b0be2b60f610b6f5 100644 (file)
@@ -47,6 +47,7 @@
 #include <asm/mach-types.h>
 
 #include <plat/regs-serial.h>
+#include <plat/iic.h>
 
 #include <plat/devs.h>
 #include <plat/cpu.h>
@@ -89,7 +90,7 @@ static struct platform_device *smdk2410_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
 };
 
@@ -102,6 +103,7 @@ static void __init smdk2410_map_io(void)
 
 static void __init smdk2410_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
        smdk_machine_init();
 }
index 309dcf4c870af92c8603276d0b7f1e3ccfa83939..8fdb0430bd48098faa9bd55eb94ce7f11444d75c 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/mach-types.h>
 
 #include <plat/regs-serial.h>
+#include <plat/iic.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
 
@@ -127,7 +128,7 @@ static struct s3c2410_uartcfg tct_hammer_uartcfgs[] = {
 static struct platform_device *tct_hammer_devices[] __initdata = {
        &s3c_device_adc,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_usb,
        &s3c_device_rtc,
        &s3c_device_usbgadget,
@@ -146,6 +147,7 @@ static void __init tct_hammer_map_io(void)
 
 static void __init tct_hammer_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(tct_hammer_devices, ARRAY_SIZE(tct_hammer_devices));
 }
 
index 941353af16dc85f546107e222f5a5c5bec3649a9..61a1ea9c5c5cd46bf58ed1d78a3deda89003b0d3 100644 (file)
@@ -47,6 +47,7 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <plat/iic.h>
 
 #include "usb-simtec.h"
 #include "nor-simtec.h"
@@ -334,7 +335,7 @@ static struct platform_device *vr1000_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_adc,
        &serial_device,
        &vr1000_dm9k0,
@@ -384,6 +385,7 @@ static void __init vr1000_map_io(void)
 
 static void __init vr1000_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
 
        i2c_register_board_info(0, vr1000_i2c_devs,
index ac79b536c4c3d5510f84e969e5cb4cfe5faecb9e..feb141b1f915bf131622b6388ce69901e9636797 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
@@ -28,6 +29,8 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
+#include <plat/cpu-freq.h>
+
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 
@@ -35,6 +38,7 @@
 #include <plat/cpu.h>
 #include <plat/devs.h>
 #include <plat/clock.h>
+#include <plat/pll.h>
 
 /* Initial IO mappings */
 
@@ -59,25 +63,28 @@ void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
  * machine specific initialisation.
 */
 
-void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
+void __init s3c2410_map_io(void)
 {
-       /* register our io-tables */
-
        iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
-       iotable_init(mach_desc, mach_size);
 }
 
-void __init s3c2410_init_clocks(int xtal)
+void __init_or_cpufreq s3c2410_setup_clocks(void)
 {
+       struct clk *xtal_clk;
        unsigned long tmp;
+       unsigned long xtal;
        unsigned long fclk;
        unsigned long hclk;
        unsigned long pclk;
 
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
        /* now we've got our machine bits initialised, work out what
         * clocks we've got */
 
-       fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
+       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
 
        tmp = __raw_readl(S3C2410_CLKDIVN);
 
@@ -95,7 +102,13 @@ void __init s3c2410_init_clocks(int xtal)
         * console to use them
         */
 
-       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2410_init_clocks(int xtal)
+{
+       s3c24xx_register_baseclocks(xtal);
+       s3c2410_setup_clocks();
        s3c2410_baseclk_add();
 }
 
index c59a9d2ee9a642c355d9a092bc4e738053ba5784..ca99564ae4b56c917a73a48dd357244c2d3fe654 100644 (file)
@@ -7,6 +7,7 @@
 config CPU_S3C2412
        bool
        depends on ARCH_S3C2410
+       select CPU_ARM926T
        select CPU_LLSERIAL_S3C2440
        select S3C2412_PM if PM
        select S3C2412_DMA if S3C2410_DMA
index 96d9eb15424f38087ec3b2a210add4ab7ea4d842..a037df5e1c2da52103b3b635bc18653f7b541999 100644 (file)
@@ -93,12 +93,6 @@ static int s3c2412_upll_enable(struct clk *clk, int enable)
 
 /* clock selections */
 
-/* CPU EXTCLK input */
-static struct clk clk_ext = {
-       .name           = "extclk",
-       .id             = -1,
-};
-
 static struct clk clk_erefclk = {
        .name           = "erefclk",
        .id             = -1,
@@ -773,5 +767,6 @@ int __init s3c2412_baseclk_add(void)
                s3c2412_clkcon_enable(clkp, 0);
        }
 
+       s3c_pwmclk_init();
        return 0;
 }
index ba0591e71f329aff73ae383c3549f22d17390507..919856c9433f013fb81678a485a32abc8290859c 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/serial_core.h>
 #include <linux/io.h>
 
-#include <asm/dma.h>
 #include <mach/dma.h>
 
 #include <plat/dma.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-ac97.h>
+#include <plat/regs-ac97.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
 #include <asm/plat-s3c24xx/regs-s3c2412-iis.h>
 #include <asm/plat-s3c24xx/regs-iis.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 
 #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
 
index b08f18c8c47a0144868763d46c44eb844b93eb6b..ecddbbb34832b01d8b0cb3612b0f23bb65085e92 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/sysdev.h>
-#include <linux/delay.h>
 #include <linux/serial_core.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
@@ -31,8 +30,8 @@
 #include <asm/mach/irq.h>
 
 #include <plat/regs-serial.h>
-#include <asm/plat-s3c/nand.h>
-#include <asm/plat-s3c/iic.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
 
 #include <mach/regs-power.h>
 #include <mach/regs-gpio.h>
@@ -52,7 +51,8 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/pm.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
 
 static struct map_desc jive_iodesc[] __initdata = {
 };
@@ -398,11 +398,12 @@ static struct s3c2410_spigpio_info jive_lcd_spi = {
        .bus_num        = 1,
        .pin_clk        = S3C2410_GPG8,
        .pin_mosi       = S3C2410_GPB8,
+       .num_chipselect = 1,
        .chip_select    = jive_lcd_spi_chipselect,
 };
 
 static struct platform_device jive_device_lcdspi = {
-       .name           = "s3c24xx-spi-gpio",
+       .name           = "spi_s3c24xx_gpio",
        .id             = 1,
        .num_resources  = 0,
        .dev.platform_data = &jive_lcd_spi,
@@ -419,11 +420,12 @@ static struct s3c2410_spigpio_info jive_wm8750_spi = {
        .bus_num        = 2,
        .pin_clk        = S3C2410_GPB4,
        .pin_mosi       = S3C2410_GPB9,
+       .num_chipselect = 1,
        .chip_select    = jive_wm8750_chipselect,
 };
 
 static struct platform_device jive_device_wm8750 = {
-       .name           = "s3c24xx-spi-gpio",
+       .name           = "spi_s3c24xx_gpio",
        .id             = 2,
        .num_resources  = 0,
        .dev.platform_data = &jive_wm8750_spi,
@@ -450,14 +452,14 @@ static struct spi_board_info __initdata jive_spi_devs[] = {
 
 /* I2C bus and device configuration. */
 
-static struct s3c2410_platform_i2c jive_i2c_cfg = {
+static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = {
        .max_freq       = 80 * 1000,
        .bus_freq       = 50 * 1000,
        .flags          = S3C_IICFLG_FILTER,
        .sda_delay      = 2,
 };
 
-static struct i2c_board_info jive_i2c_devs[] = {
+static struct i2c_board_info jive_i2c_devs[] __initdata = {
        [0] = {
                I2C_BOARD_INFO("lis302dl", 0x1c),
                .irq    = IRQ_EINT14,
@@ -470,7 +472,7 @@ static struct platform_device *jive_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_rtc,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_lcd,
        &jive_device_lcdspi,
        &jive_device_wm8750,
@@ -663,7 +665,7 @@ static void __init jive_machine_init(void)
 
        spi_register_board_info(jive_spi_devs, ARRAY_SIZE(jive_spi_devs));
 
-       s3c_device_i2c.dev.platform_data = &jive_i2c_cfg;
+       s3c_i2c0_set_platdata(&jive_i2c_cfg);
        i2c_register_board_info(0, jive_i2c_devs, ARRAY_SIZE(jive_i2c_devs));
 
        pm_power_off = jive_power_off;
index c719b5a740a914cc2a5d75e8f9bec7d02b2fb3e5..eba66aa6bd209da9d3fbd920e110b9f09eaace16 100644 (file)
@@ -37,7 +37,8 @@
 #include <mach/regs-lcd.h>
 
 #include <mach/idle.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/udc.h>
+#include <plat/iic.h>
 #include <mach/fb.h>
 
 #include <plat/s3c2410.h>
@@ -105,7 +106,7 @@ static struct platform_device *smdk2413_devices[] __initdata = {
        &s3c_device_usb,
        //&s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_usbgadget,
 };
@@ -142,6 +143,7 @@ static void __init smdk2413_machine_init(void)
 
 
        s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
+       s3c_i2c0_set_platdata(NULL);
 
        platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices));
        smdk_machine_init();
index 4cfa19ad9be015947c8b9f538a29f76715c3a388..11e8ad49fc7be740a941a386a291ed9cfa31d013 100644 (file)
@@ -39,7 +39,8 @@
 #include <mach/idle.h>
 #include <mach/fb.h>
 
-#include <asm/plat-s3c/nand.h>
+#include <plat/iic.h>
+#include <plat/nand.h>
 
 #include <plat/s3c2410.h>
 #include <plat/s3c2412.h>
@@ -122,7 +123,7 @@ static struct s3c2410_platform_nand vstms_nand_info = {
 static struct platform_device *vstms_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_rtc,
        &s3c_device_nand,
@@ -151,6 +152,7 @@ static void __init vstms_map_io(void)
 
 static void __init vstms_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices));
 }
 
index 313759c3da69fcc0ba4f357342f2191475a9ed4b..5b5aba69ec3f57b46c92275ca52cb4b569070610 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 #include <mach/reset.h>
 #include <mach/idle.h>
 
+#include <plat/cpu-freq.h>
+
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 #include <mach/regs-power.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-gpioj.h>
 #include <mach/regs-dsc.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 #include <mach/regs-s3c2412.h>
 
 #include <plat/s3c2412.h>
@@ -47,6 +50,7 @@
 #include <plat/devs.h>
 #include <plat/clock.h>
 #include <plat/pm.h>
+#include <plat/pll.h>
 
 #ifndef CONFIG_CPU_S3C2412_ONLY
 void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
@@ -136,7 +140,7 @@ static void s3c2412_hard_reset(void)
  * machine specific initialisation.
 */
 
-void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
+void __init s3c2412_map_io(void)
 {
        /* move base of IO */
 
@@ -153,20 +157,25 @@ void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
        /* register our io-tables */
 
        iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
-       iotable_init(mach_desc, mach_size);
 }
 
-void __init s3c2412_init_clocks(int xtal)
+void __init_or_cpufreq s3c2412_setup_clocks(void)
 {
+       struct clk *xtal_clk;
        unsigned long tmp;
+       unsigned long xtal;
        unsigned long fclk;
        unsigned long hclk;
        unsigned long pclk;
 
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
        /* now we've got our machine bits initialised, work out what
         * clocks we've got */
 
-       fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
+       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal * 2);
 
        clk_mpll.rate = fclk;
 
@@ -183,11 +192,17 @@ void __init s3c2412_init_clocks(int xtal)
        printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
               print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
 
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2412_init_clocks(int xtal)
+{
        /* initialise the clocks here, to allow other things like the
         * console to use them
         */
 
-       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+       s3c24xx_register_baseclocks(xtal);
+       s3c2412_setup_clocks();
        s3c2412_baseclk_add();
 }
 
index 25de042ab9961745e1f125d56c2d070392a1ea1d..cde5ae9a43400e650f280641019a9bf4c3c7973e 100644 (file)
@@ -7,6 +7,7 @@
 config CPU_S3C2440
        bool
        depends on ARCH_S3C2410
+       select CPU_ARM920T
        select S3C2410_CLOCK
        select S3C2410_PM if PM
        select S3C2410_GPIO
@@ -28,8 +29,10 @@ menu "S3C2440 Machines"
 config MACH_ANUBIS
        bool "Simtec Electronics ANUBIS"
        select CPU_S3C2440
+       select S3C24XX_DCLK
        select PM_SIMTEC if PM
        select HAVE_PATA_PLATFORM
+       select S3C24XX_GPIO_EXTRA64
        help
          Say Y here if you are using the Simtec Electronics ANUBIS
          development system
@@ -37,7 +40,9 @@ config MACH_ANUBIS
 config MACH_OSIRIS
        bool "Simtec IM2440D20 (OSIRIS) module"
        select CPU_S3C2440
+       select S3C24XX_DCLK
        select PM_SIMTEC if PM
+       select S3C24XX_GPIO_EXTRA128
        help
          Say Y here if you are using the Simtec IM2440D20 module, also
          known as the Osiris.
index 32303f6a83219dc5f2a3b6b263610ae77121d40a..5b5ee0b8f4e0b236ec9a4922f90e3f69b3ce67d0 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/sysdev.h>
 #include <linux/serial_core.h>
 
-#include <asm/dma.h>
 #include <mach/dma.h>
 
 #include <plat/dma.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-ac97.h>
+#include <plat/regs-ac97.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
 #include <asm/plat-s3c24xx/regs-iis.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
        [DMACH_XD0] = {
index e2beca4704847daee81d643f0870a65c81eca5f6..b05d56e230a1338c2c965499547f8e56247a34ba 100644 (file)
@@ -39,7 +39,8 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
-#include <asm/plat-s3c/nand.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -366,6 +367,8 @@ static struct sm501_initdata anubis_sm501_initdata = {
                .mask   = 0,
        },
 
+       .devices        = SM501_USE_GPIO,
+
        /* set the SDRAM and bus clocks */
        .mclk           = 72 * MHZ,
        .m1xclk         = 144 * MHZ,
@@ -373,10 +376,12 @@ static struct sm501_initdata anubis_sm501_initdata = {
 
 static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
        [0] = {
+               .bus_num        = 1,
                .pin_scl        = 44,
                .pin_sda        = 45,
        },
        [1] = {
+               .bus_num        = 2,
                .pin_scl        = 40,
                .pin_sda        = 41,
        },
@@ -384,6 +389,7 @@ static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
 
 static struct sm501_platdata anubis_sm501_platdata = {
        .init           = &anubis_sm501_initdata,
+       .gpio_base      = -1,
        .gpio_i2c       = anubis_sm501_gpio_i2c,
        .gpio_i2c_nr    = ARRAY_SIZE(anubis_sm501_gpio_i2c),
 };
@@ -404,7 +410,7 @@ static struct platform_device *anubis_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_wdt,
        &s3c_device_adc,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_rtc,
        &s3c_device_nand,
        &anubis_device_ide0,
@@ -468,6 +474,7 @@ static void __init anubis_map_io(void)
 
 static void __init anubis_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
 
        i2c_register_board_info(0, anubis_i2c_devs,
index 66876c6f2f1c593f643cbdd9be679a7949597a27..0a6d0a5d961b10a6ce76aae9dcd0945262910626 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/mach/irq.h>
 
 #include <mach/hardware.h>
+#include <mach/fb.h>
 #include <asm/irq.h>
 #include <asm/mach-types.h>
 
@@ -35,7 +36,8 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
-#include <asm/plat-s3c/nand.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -45,6 +47,7 @@
 #include <plat/clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
+#include <asm/plat-s3c24xx/mci.h>
 
 static struct map_desc at2440evb_iodesc[] __initdata = {
        /* Nothing here */
@@ -162,19 +165,60 @@ static struct platform_device at2440evb_device_eth = {
        },
 };
 
+static struct s3c24xx_mci_pdata at2440evb_mci_pdata = {
+       .gpio_detect    = S3C2410_GPG10,
+};
+
+/* 7" LCD panel */
+
+static struct s3c2410fb_display at2440evb_lcd_cfg __initdata = {
+
+       .lcdcon5        = S3C2410_LCDCON5_FRM565 |
+                         S3C2410_LCDCON5_INVVLINE |
+                         S3C2410_LCDCON5_INVVFRAME |
+                         S3C2410_LCDCON5_PWREN |
+                         S3C2410_LCDCON5_HWSWP,
+
+       .type           = S3C2410_LCDCON1_TFT,
+
+       .width          = 800,
+       .height         = 480,
+
+       .pixclock       = 33333, /* HCLK 60 MHz, divisor 2 */
+       .xres           = 800,
+       .yres           = 480,
+       .bpp            = 16,
+       .left_margin    = 88,
+       .right_margin   = 40,
+       .hsync_len      = 128,
+       .upper_margin   = 32,
+       .lower_margin   = 11,
+       .vsync_len      = 2,
+};
+
+static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = {
+       .displays       = &at2440evb_lcd_cfg,
+       .num_displays   = 1,
+       .default_display = 0,
+};
+
 static struct platform_device *at2440evb_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_wdt,
        &s3c_device_adc,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_rtc,
        &s3c_device_nand,
+       &s3c_device_sdi,
+       &s3c_device_lcd,
        &at2440evb_device_eth,
 };
 
 static void __init at2440evb_map_io(void)
 {
        s3c_device_nand.dev.platform_data = &at2440evb_nand_info;
+       s3c_device_sdi.name = "s3c2440-sdi";
+       s3c_device_sdi.dev.platform_data = &at2440evb_mci_pdata;
 
        s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc));
        s3c24xx_init_clocks(16934400);
@@ -183,6 +227,9 @@ static void __init at2440evb_map_io(void)
 
 static void __init at2440evb_init(void)
 {
+       s3c24xx_fb_set_platdata(&at2440evb_fb_info);
+       s3c_i2c0_set_platdata(NULL);
+
        platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices));
 }
 
index a546307fd53d8abb2ff39d84bc2a72b401c893ea..7aeaa972d7f5856bb46e9a6156190dd6f065c693 100644 (file)
@@ -37,6 +37,7 @@
 //#include <asm/debug-ll.h>
 #include <mach/regs-gpio.h>
 #include <plat/regs-serial.h>
+#include <plat/iic.h>
 
 #include <plat/s3c2410.h>
 #include <plat/s3c2440.h>
@@ -107,7 +108,7 @@ static struct platform_device *nexcoder_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_rtc,
        &s3c_device_camif,
@@ -142,6 +143,7 @@ static void __init nexcoder_map_io(void)
 
 static void __init nexcoder_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices));
 };
 
index 2361d606abc50fdd85ddd84c7ac54473d61a9145..41a00f57e5da67d05651052c2aae9e207b96b944 100644 (file)
@@ -37,7 +37,8 @@
 #include <mach/regs-gpio.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
-#include <asm/plat-s3c/nand.h>
+#include <plat/nand.h>
+#include <plat/iic.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -335,7 +336,7 @@ static struct i2c_board_info osiris_i2c_devs[] __initdata = {
 /* Standard Osiris devices */
 
 static struct platform_device *osiris_devices[] __initdata = {
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_wdt,
        &s3c_device_nand,
        &osiris_pcmcia,
@@ -398,6 +399,8 @@ static void __init osiris_init(void)
        sysdev_class_register(&osiris_pm_sysclass);
        sysdev_register(&osiris_pm_sysdev);
 
+       s3c_i2c0_set_platdata(NULL);
+
        i2c_register_board_info(0, osiris_i2c_devs,
                                ARRAY_SIZE(osiris_i2c_devs));
 
index 4d14c7cff89214eaab3357ec5b138fa27b64b41b..12d378f84ad2d717cd8cab0cccceef548e0fbe4a 100644 (file)
@@ -42,7 +42,7 @@
 #include <mach/regs-lcd.h>
 
 #include <mach/h1940.h>
-#include <asm/plat-s3c/nand.h>
+#include <plat/nand.h>
 #include <mach/fb.h>
 
 #include <plat/clock.h>
@@ -179,7 +179,7 @@ static struct platform_device *rx3715_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
        &s3c_device_nand,
 };
index fefeaaa4155fff74bb21d9320b38063342b54acd..db6eafbd4d9036f707497fdc66935e921c1938f8 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <mach/idle.h>
 #include <mach/fb.h>
+#include <plat/iic.h>
 
 #include <plat/s3c2410.h>
 #include <plat/s3c2440.h>
@@ -152,7 +153,7 @@ static struct platform_device *smdk2440_devices[] __initdata = {
        &s3c_device_usb,
        &s3c_device_lcd,
        &s3c_device_wdt,
-       &s3c_device_i2c,
+       &s3c_device_i2c0,
        &s3c_device_iis,
 };
 
@@ -166,6 +167,7 @@ static void __init smdk2440_map_io(void)
 static void __init smdk2440_machine_init(void)
 {
        s3c24xx_fb_set_platdata(&smdk2440_fb_info);
+       s3c_i2c0_set_platdata(NULL);
 
        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
        smdk_machine_init();
index 26d131a77074ae7efe431099491b1ade31738109..b289d198020e0c180bb5bbe8fa77df8934305f06 100644 (file)
@@ -7,6 +7,7 @@
 config CPU_S3C2442
        bool
        depends on ARCH_S3C2410
+       select CPU_ARM920T
        select S3C2410_CLOCK
        select S3C2410_GPIO
        select S3C2410_PM if PM
index 14252f57375468d4d9809fe5e6475550962a688d..212141baebec29ac005c0bc4699762ed6945fcd1 100644 (file)
@@ -24,6 +24,7 @@ config MACH_SMDK2443
        bool "SMDK2443"
        select CPU_S3C2443
        select MACH_SMDK
+       select S3C_DEV_HSMMC
        help
          Say Y here if you are using an SMDK2443
 
index f854e7385e3c75c44ea10f4917c42a92da338f2c..2785d69c95b0dabc972004115efe66b73b6e8df1 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/sysdev.h>
 #include <linux/clk.h>
 #include <linux/mutex.h>
-#include <linux/delay.h>
 #include <linux/serial_core.h>
 #include <linux/io.h>
 
@@ -39,6 +38,8 @@
 
 #include <mach/regs-s3c2443-clock.h>
 
+#include <plat/cpu-freq.h>
+
 #include <plat/s3c2443.h>
 #include <plat/clock.h>
 #include <plat/cpu.h>
@@ -145,12 +146,6 @@ static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk,
 
 /* clock selections */
 
-/* CPU EXTCLK input */
-static struct clk clk_ext = {
-       .name           = "ext",
-       .id             = -1,
-};
-
 static struct clk clk_mpllref = {
        .name           = "mpllref",
        .parent         = &clk_xtal,
@@ -165,14 +160,6 @@ static struct clk clk_mpll = {
 };
 #endif
 
-static struct clk clk_epllref;
-
-static struct clk clk_epll = {
-       .name           = "epll",
-       .parent         = &clk_epllref,
-       .id             = -1,
-};
-
 static struct clk clk_i2s_ext = {
        .name           = "i2s-ext",
        .id             = -1,
@@ -1011,22 +998,20 @@ static struct clk *clks[] __initdata = {
        &clk_prediv,
 };
 
-void __init s3c2443_init_clocks(int xtal)
+void __init_or_cpufreq s3c2443_setup_clocks(void)
 {
-       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
        unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
        unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+       struct clk *xtal_clk;
+       unsigned long xtal;
        unsigned long pll;
        unsigned long fclk;
        unsigned long hclk;
        unsigned long pclk;
-       struct clk *clkp;
-       int ret;
-       int ptr;
 
-       /* s3c2443 parents h and p clocks from prediv */
-       clk_h.parent = &clk_prediv;
-       clk_p.parent = &clk_prediv;
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
 
        pll = s3c2443_get_mpll(mpllcon, xtal);
        clk_msysclk.rate = pll;
@@ -1036,13 +1021,29 @@ void __init s3c2443_init_clocks(int xtal)
        hclk /= s3c2443_get_hdiv(clkdiv0);
        pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
 
-       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
 
        printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
               (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
               print_mhz(pll), print_mhz(fclk),
               print_mhz(hclk), print_mhz(pclk));
 
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c2443_init_clocks(int xtal)
+{
+       struct clk *clkp;
+       unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+       int ret;
+       int ptr;
+
+       /* s3c2443 parents h and p clocks from prediv */
+       clk_h.parent = &clk_prediv;
+       clk_p.parent = &clk_prediv;
+
+       s3c24xx_register_baseclocks(xtal);
+       s3c2443_setup_clocks();
        s3c2443_clk_initparents();
 
        for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
@@ -1056,7 +1057,7 @@ void __init s3c2443_init_clocks(int xtal)
        }
 
        clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
-
+       clk_epll.parent = &clk_epllref;
        clk_usb_bus.parent = &clk_usb_bus_host;
 
        /* ensure usb bus clock is within correct rate of 48MHz */
@@ -1105,4 +1106,6 @@ void __init s3c2443_init_clocks(int xtal)
 
                (clkp->enable)(clkp, 0);
        }
+
+       s3c_pwmclk_init();
 }
index f73ccb25ff9488136cbcbae50e16a1a03f5b384d..2a58a4d5aa5ae44e196c59acb8838e851defe4a3 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/serial_core.h>
 #include <linux/io.h>
 
-#include <asm/dma.h>
 #include <mach/dma.h>
 
 #include <plat/dma.h>
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-ac97.h>
+#include <plat/regs-ac97.h>
 #include <mach/regs-mem.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
 #include <asm/plat-s3c24xx/regs-iis.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 
 #define MAP(x) { \
                [0]     = (x) | DMA_CH_VALID,   \
index a7fe65f3dcc16a08b0212adfd4abd373174d7435..039a4624310508fcfec0e9226ead564d6e610df2 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <mach/idle.h>
 #include <mach/fb.h>
+#include <plat/iic.h>
 
 #include <plat/s3c2410.h>
 #include <plat/s3c2440.h>
@@ -103,8 +104,8 @@ static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = {
 
 static struct platform_device *smdk2443_devices[] __initdata = {
        &s3c_device_wdt,
-       &s3c_device_i2c,
-       &s3c_device_hsmmc,
+       &s3c_device_i2c0,
+       &s3c_device_hsmmc0,
 };
 
 static void __init smdk2443_map_io(void)
@@ -116,6 +117,7 @@ static void __init smdk2443_map_io(void)
 
 static void __init smdk2443_machine_init(void)
 {
+       s3c_i2c0_set_platdata(NULL);
        platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices));
        smdk_machine_init();
 }
index bbeddf9ddcb1a68c99835f039f10a150c66f64f2..ce2ec32989304d6e6323639fa4c99dcf96578a00 100644 (file)
@@ -81,10 +81,9 @@ void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
  * machine specific initialisation.
  */
 
-void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size)
+void __init s3c2443_map_io(void)
 {
        iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
-       iotable_init(mach_desc, mach_size);
 }
 
 /* need to register class before we actually register the device, and
diff --git a/arch/arm/mach-s3c24a0/include/mach/debug-macro.S b/arch/arm/mach-s3c24a0/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..f0ef0ab
--- /dev/null
@@ -0,0 +1,28 @@
+/* arch/arm/mach-s3c2410/include/mach/debug-macro.S
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* pull in the relevant register and map files. */
+
+#include <mach/map.h>
+#include <plat/regs-serial.h>
+
+       .macro addruart, rx
+               mrc     p15, 0, \rx, c1, c0
+               tst     \rx, #1
+               ldreq   \rx, = S3C24XX_PA_UART
+               ldrne   \rx, = S3C24XX_VA_UART
+#if CONFIG_DEBUG_S3C_UART != 0
+               add     \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+#endif
+       .endm
+
+/* include the reset of the code which will do the work, we're only
+ * compiling for a single cpu processor type so the default of s3c2440
+ * will be fine with us.
+ */
+
+#include <plat/debug-macro.S>
diff --git a/arch/arm/mach-s3c24a0/include/mach/irqs.h b/arch/arm/mach-s3c24a0/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..ae8c0e3
--- /dev/null
@@ -0,0 +1,115 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/irqs.h
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *   Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can 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_24A0_IRQS_H
+#define __ASM_ARCH_24A0_IRQS_H __FILE__
+
+#define IRQ_EINT0t2    S3C2410_IRQ(0)  /* 16 */
+/* for generic entry-macro.S */
+#define IRQ_EINT0      IRQ_EINT0t2
+
+#define IRQ_EINT3t6    S3C2410_IRQ(1)
+#define IRQ_EINT7t10   S3C2410_IRQ(2)
+#define IRQ_EINT11t14  S3C2410_IRQ(3)
+#define IRQ_EINT15t18  S3C2410_IRQ(4)  /* 20 */
+#define IRQ_TICK       S3C2410_IRQ(5)
+#define IRQ_DCTQ       S3C2410_IRQ(6)
+#define IRQ_MC         S3C2410_IRQ(7)
+#define IRQ_ME         S3C2410_IRQ(8)  /* 24 */
+#define IRQ_KEYPAD     S3C2410_IRQ(9)
+#define IRQ_TIMER0     S3C2410_IRQ(10)
+#define IRQ_TIMER1     S3C2410_IRQ(11)
+#define IRQ_TIMER2     S3C2410_IRQ(12)
+#define IRQ_TIMER3_4   S3C2410_IRQ(13)
+#define IRQ_OS_TIMER   IRQ_TIMER3_4
+#define IRQ_LCD                S3C2410_IRQ(14)
+#define IRQ_CAM_C      S3C2410_IRQ(15)
+#define IRQ_WDT_BATFLT S3C2410_IRQ(16) /* 32 */
+#define IRQ_UART0      S3C2410_IRQ(17)
+#define IRQ_CAM_P      S3C2410_IRQ(18)
+#define IRQ_MODEM      S3C2410_IRQ(19)
+#define IRQ_DMA                S3C2410_IRQ(20)
+#define IRQ_SDI                S3C2410_IRQ(21)
+#define IRQ_SPI0       S3C2410_IRQ(22)
+#define IRQ_UART1      S3C2410_IRQ(23)
+#define IRQ_AC97_NFLASH        S3C2410_IRQ(24) /* 40 */
+#define IRQ_USBD       S3C2410_IRQ(25)
+#define IRQ_USBH       S3C2410_IRQ(26)
+#define IRQ_IIC                S3C2410_IRQ(27)
+#define IRQ_IRDA_MSTICK        S3C2410_IRQ(28) /* 44 */
+#define IRQ_VLX_SPI1   S3C2410_IRQ(29)
+#define IRQ_RTC                S3C2410_IRQ(30) /* 46 */
+#define IRQ_ADC_PEN     S3C2410_IRQ(31)
+
+/* interrupts generated from the external interrupts sources */
+#define IRQ_EINT00     S3C2410_IRQ(32) /* 48 */
+#define IRQ_EINT1      S3C2410_IRQ(33)
+#define IRQ_EINT2      S3C2410_IRQ(34)
+#define IRQ_EINT3      S3C2410_IRQ(35)
+#define IRQ_EINT4      S3C2410_IRQ(36)
+#define IRQ_EINT5      S3C2410_IRQ(37)
+#define IRQ_EINT6      S3C2410_IRQ(38)
+#define IRQ_EINT7      S3C2410_IRQ(39)
+#define IRQ_EINT8      S3C2410_IRQ(40)
+#define IRQ_EINT9      S3C2410_IRQ(41)
+#define IRQ_EINT10     S3C2410_IRQ(42)
+#define IRQ_EINT11     S3C2410_IRQ(43)
+#define IRQ_EINT12     S3C2410_IRQ(44)
+#define IRQ_EINT13     S3C2410_IRQ(45)
+#define IRQ_EINT14     S3C2410_IRQ(46)
+#define IRQ_EINT15     S3C2410_IRQ(47)
+#define IRQ_EINT16     S3C2410_IRQ(48)
+#define IRQ_EINT17     S3C2410_IRQ(49)
+#define IRQ_EINT18     S3C2410_IRQ(50)
+
+/* SUB IRQS */
+#define IRQ_S3CUART_RX0                S3C2410_IRQ(51) /* 67 */
+#define IRQ_S3CUART_TX0                S3C2410_IRQ(52)
+#define IRQ_S3CUART_ERR0       S3C2410_IRQ(53)
+
+#define IRQ_S3CUART_RX1                S3C2410_IRQ(54)
+#define IRQ_S3CUART_TX1                S3C2410_IRQ(55)
+#define IRQ_S3CUART_ERR1       S3C2410_IRQ(56)
+
+#define IRQ_S3CUART_RX2                (0x0)
+#define IRQ_S3CUART_TX2                (0x0)
+#define IRQ_S3CUART_ERR2       (0x0)
+
+
+#define IRQ_IRDA       S3C2410_IRQ(57)
+#define IRQ_MSTICK     S3C2410_IRQ(58)
+#define IRQ_RESERVED0  S3C2410_IRQ(59)
+#define IRQ_RESERVED1  S3C2410_IRQ(60)
+#define IRQ_RESERVED2  S3C2410_IRQ(61)
+#define IRQ_TIMER3     S3C2410_IRQ(62)
+#define IRQ_TIMER4     S3C2410_IRQ(63)
+#define IRQ_WDT                S3C2410_IRQ(64)
+#define IRQ_BATFLT     S3C2410_IRQ(65)
+#define IRQ_POST       S3C2410_IRQ(66)
+#define IRQ_DISP_FIFO  S3C2410_IRQ(67)
+#define IRQ_PENUP      S3C2410_IRQ(68)
+#define IRQ_PENDN      S3C2410_IRQ(69)
+#define IRQ_ADC                S3C2410_IRQ(70)
+#define IRQ_DISP_FRAME S3C2410_IRQ(71)
+#define IRQ_NFLASH     S3C2410_IRQ(72)
+#define IRQ_AC97       S3C2410_IRQ(73)
+#define IRQ_SPI1       S3C2410_IRQ(74)
+#define IRQ_VLX                S3C2410_IRQ(75)
+#define IRQ_DMA0       S3C2410_IRQ(76)
+#define IRQ_DMA1       S3C2410_IRQ(77)
+#define IRQ_DMA2       S3C2410_IRQ(78)
+#define IRQ_DMA3       S3C2410_IRQ(79)
+
+#define IRQ_TC         (0x0)
+
+#define NR_IRQS                (IRQ_DMA3+1)
+
+#endif /* __ASM_ARCH_24A0_IRQS_H */
diff --git a/arch/arm/mach-s3c24a0/include/mach/map.h b/arch/arm/mach-s3c24a0/include/mach/map.h
new file mode 100644 (file)
index 0000000..a011327
--- /dev/null
@@ -0,0 +1,85 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/map.h
+ *
+ * Copyright 2003,2007  Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24A0 - Memory map definitions
+ *
+ * This program is free software; you can 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_24A0_MAP_H
+#define __ASM_ARCH_24A0_MAP_H __FILE__
+
+#include <plat/map-base.h>
+#include <plat/map.h>
+
+#define S3C24A0_PA_IO_BASE     (0x40000000)
+#define S3C24A0_PA_CLKPWR      (0x40000000)
+#define S3C24A0_PA_IRQ         (0x40200000)
+#define S3C24A0_PA_DMA         (0x40400000)
+#define S3C24A0_PA_MEMCTRL     (0x40C00000)
+#define S3C24A0_PA_NAND                (0x40C00000)
+#define S3C24A0_PA_SROM                (0x40C20000)
+#define S3C24A0_PA_SDRAM       (0x40C40000)
+#define S3C24A0_PA_BUSM                (0x40CE0000)
+#define S3C24A0_PA_USBHOST     (0x41000000)
+#define S3C24A0_PA_MODEMIF     (0x41180000)
+#define S3C24A0_PA_IRDA                (0x41800000)
+#define S3C24A0_PA_TIMER       (0x44000000)
+#define S3C24A0_PA_WATCHDOG    (0x44100000)
+#define S3C24A0_PA_RTC         (0x44200000)
+#define S3C24A0_PA_UART                (0x44400000)
+#define S3C24A0_PA_UART0       (S3C24A0_PA_UART)
+#define S3C24A0_PA_UART1       (S3C24A0_PA_UART + 0x4000)
+#define S3C24A0_PA_SPI         (0x44500000)
+#define S3C24A0_PA_IIC         (0x44600000)
+#define S3C24A0_PA_IIS         (0x44700000)
+#define S3C24A0_PA_GPIO                (0x44800000)
+#define S3C24A0_PA_KEYIF       (0x44900000)
+#define S3C24A0_PA_USBDEV      (0x44A00000)
+#define S3C24A0_PA_AC97                (0x45000000)
+#define S3C24A0_PA_ADC         (0x45800000)
+#define S3C24A0_PA_SDI         (0x46000000)
+#define S3C24A0_PA_MS          (0x46100000)
+#define S3C24A0_PA_LCD         (0x4A000000)
+#define S3C24A0_PA_VPOST       (0x4A100000)
+
+/* physical addresses of all the chip-select areas */
+
+#define S3C24A0_CS0    (0x00000000)
+#define S3C24A0_CS1    (0x04000000)
+#define S3C24A0_CS2    (0x08000000)
+#define S3C24A0_CS3    (0x0C000000)
+#define S3C24A0_CS4    (0x10000000)
+#define S3C24A0_CS5    (0x40000000)
+
+#define S3C24A0_SDRAM_PA       (S3C24A0_CS4)
+
+/* Use a single interface for common resources between S3C24XX cpus */
+
+#define S3C24XX_PA_IRQ         S3C24A0_PA_IRQ
+#define S3C24XX_PA_MEMCTRL     S3C24A0_PA_MEMCTRL
+#define S3C24XX_PA_USBHOST     S3C24A0_PA_USBHOST
+#define S3C24XX_PA_DMA         S3C24A0_PA_DMA
+#define S3C24XX_PA_CLKPWR      S3C24A0_PA_CLKPWR
+#define S3C24XX_PA_LCD         S3C24A0_PA_LCD
+#define S3C24XX_PA_UART                S3C24A0_PA_UART
+#define S3C24XX_PA_TIMER       S3C24A0_PA_TIMER
+#define S3C24XX_PA_USBDEV      S3C24A0_PA_USBDEV
+#define S3C24XX_PA_WATCHDOG    S3C24A0_PA_WATCHDOG
+#define S3C24XX_PA_IIS         S3C24A0_PA_IIS
+#define S3C24XX_PA_GPIO                S3C24A0_PA_GPIO
+#define S3C24XX_PA_RTC         S3C24A0_PA_RTC
+#define S3C24XX_PA_ADC         S3C24A0_PA_ADC
+#define S3C24XX_PA_SPI         S3C24A0_PA_SPI
+#define S3C24XX_PA_SDI         S3C24A0_PA_SDI
+#define S3C24XX_PA_NAND                S3C24A0_PA_NAND
+
+#define S3C_PA_UART            S3C24A0_PA_UART
+#define S3C_PA_IIC             S3C24A0_PA_IIC
+
+#endif /* __ASM_ARCH_24A0_MAP_H */
diff --git a/arch/arm/mach-s3c24a0/include/mach/memory.h b/arch/arm/mach-s3c24a0/include/mach/memory.h
new file mode 100644 (file)
index 0000000..585211c
--- /dev/null
@@ -0,0 +1,19 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/memory.h
+ *  from linux/include/asm-arm/arch-rpc/memory.h
+ *
+ *  Copyright (C) 1996,1997,1998 Russell King.
+ *
+ * This program is free software; you can 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_24A0_MEMORY_H
+#define __ASM_ARCH_24A0_MEMORY_H __FILE__
+
+#define PHYS_OFFSET UL(0x10000000)
+
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff --git a/arch/arm/mach-s3c24a0/include/mach/regs-clock.h b/arch/arm/mach-s3c24a0/include/mach/regs-clock.h
new file mode 100644 (file)
index 0000000..af2abd7
--- /dev/null
@@ -0,0 +1,88 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C24A0 clock register definitions
+*/
+
+#ifndef __ASM_ARCH_24A0_REGS_CLOCK_H
+#define __ASM_ARCH_24A0_REGS_CLOCK_H __FILE__
+
+#define S3C24A0_MPLLCON                S3C2410_CLKREG(0x10)
+#define S3C24A0_UPLLCON                S3C2410_CLKREG(0x14)
+#define S3C24A0_CLKCON         S3C2410_CLKREG(0x20)
+#define S3C24A0_CLKSRC         S3C2410_CLKREG(0x24)
+#define S3C24A0_CLKDIVN                S3C2410_CLKREG(0x28)
+
+/* CLKCON register bits */
+
+#define S3C24A0_CLKCON_VLX     (1<<29)
+#define S3C24A0_CLKCON_VPOST   (1<<28)
+#define S3C24A0_CLKCON_WDT     (1<<27) /* reserved */
+#define S3C24A0_CLKCON_MPEGDCTQ        (1<<26)
+#define S3C24A0_CLKCON_VPOSTIF (1<<25)
+#define S3C24A0_CLKCON_MPEG4IF (1<<24)
+#define S3C24A0_CLKCON_CAM_UPLL        (1<<23)
+#define S3C24A0_CLKCON_LCDC    (1<<22)
+#define S3C24A0_CLKCON_CAM_HCLK        (1<<21)
+#define S3C24A0_CLKCON_MPEG4   (1<<20)
+#define S3C24A0_CLKCON_KEYPAD  (1<<19)
+#define S3C24A0_CLKCON_ADC     (1<<18)
+#define S3C24A0_CLKCON_SDI     (1<<17)
+#define S3C24A0_CLKCON_MS      (1<<16) /* memory stick */
+#define S3C24A0_CLKCON_USBD    (1<<15)
+#define S3C24A0_CLKCON_GPIO    (1<<14)
+#define S3C24A0_CLKCON_IIS     (1<<13)
+#define S3C24A0_CLKCON_IIC     (1<<12)
+#define S3C24A0_CLKCON_SPI     (1<<11)
+#define S3C24A0_CLKCON_UART1   (1<<10)
+#define S3C24A0_CLKCON_UART0   (1<<9)
+#define S3C24A0_CLKCON_PWMT    (1<<8)
+#define S3C24A0_CLKCON_USBH    (1<<7)
+#define S3C24A0_CLKCON_AC97    (1<<6)
+#define S3C24A0_CLKCON_IrDA    (1<<4)
+#define S3C24A0_CLKCON_IDLE    (1<<2)
+#define S3C24A0_CLKCON_MON     (1<<1)
+#define S3C24A0_CLKCON_STOP    (1<<0)
+
+/* CLKSRC register bits */
+
+#define S3C24A0_CLKSRC_OSC     (1<<8)  /* CLKSRC */
+#define S3C24A0_CLKSRC_UPLL    (1<<7)
+#define S3C24A0_CLKSRC_MPLL    (1<<5)
+#define S3C24A0_CLKSRC_EXT     (1<<4)
+
+/* Use a single interface with the common code, for s3c24xx */
+
+#define S3C2410_MPLLCON                S3C24A0_MPLLCON
+#define S3C2410_UPLLCON                S3C24A0_UPLLCON
+#define S3C2410_CLKCON         S3C24A0_CLKCON
+#define S3C2410_CLKSLOW                S3C24A0_CLKSRC
+#define S3C2410_CLKDIVN                S3C24A0_CLKDIVN
+
+#define S3C2410_CLKCON_IDLE    S3C24A0_CLKCON_IDLE
+#define S3C2410_CLKCON_POWER   S3C24A0_CLKCON_STOP
+#define S3C2410_CLKCON_LCDC    S3C24A0_CLKCON_LCDC
+#define S3C2410_CLKCON_USBH    S3C24A0_CLKCON_USBH
+#define S3C2410_CLKCON_USBD    S3C24A0_CLKCON_USBD
+#define S3C2410_CLKCON_PWMT    S3C24A0_CLKCON_PWMT
+#define S3C2410_CLKCON_SDI     S3C24A0_CLKCON_SDI
+#define S3C2410_CLKCON_UART0   S3C24A0_CLKCON_UART0
+#define S3C2410_CLKCON_UART1   S3C24A0_CLKCON_UART1
+#define S3C2410_CLKCON_GPIO    S3C24A0_CLKCON_GPIO
+#define S3C2410_CLKCON_ADC     S3C24A0_CLKCON_ADC
+#define S3C2410_CLKCON_IIC     S3C24A0_CLKCON_IIC
+#define S3C2410_CLKCON_IIS     S3C24A0_CLKCON_IIS
+#define S3C2410_CLKCON_SPI     S3C24A0_CLKCON_SPI
+
+#define S3C2410_CLKSLOW_UCLK_OFF       S3C24A0_CLKSRC_UPLL
+#define S3C2410_CLKSLOW_MPLL_OFF       S3C24A0_CLKSRC_MPLL
+#define S3C2410_CLKSLOW_SLOW           (0xFF)
+#define S3C2410_CLKSLOW_GET_SLOWVAL(x) (0x1)
+
+#endif /* __ASM_ARCH_24A0_REGS_CLOCK_H */
diff --git a/arch/arm/mach-s3c24a0/include/mach/regs-irq.h b/arch/arm/mach-s3c24a0/include/mach/regs-irq.h
new file mode 100644 (file)
index 0000000..6086f6f
--- /dev/null
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/regs-irq.h
+ *
+ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
+ *                   http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * This program is free software; you can 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_24A0_REGS_IRQ_H
+#define ___ASM_ARCH_24A0_REGS_IRQ_H __FILE__
+
+
+#define S3C2410_EINTMASK       S3C2410_EINTREG(0x034)
+#define S3C2410_EINTPEND       S3C2410_EINTREG(0X038)
+
+#define S3C24XX_EINTMASK       S3C24XX_EINTREG(0x034)
+#define S3C24XX_EINTPEND       S3C24XX_EINTREG(0X038)
+
+#endif /* __ASM_ARCH_24A0_REGS_IRQ_H */
+
+
+
diff --git a/arch/arm/mach-s3c24a0/include/mach/system.h b/arch/arm/mach-s3c24a0/include/mach/system.h
new file mode 100644 (file)
index 0000000..bd1bd19
--- /dev/null
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/system.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24A0 - System function defines and includes
+ *
+ * This program is free software; you can 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 <mach/hardware.h>
+#include <asm/io.h>
+
+#include <mach/map.h>
+
+static void arch_idle(void)
+{
+       /* currently no specific idle support. */
+}
+
+void (*s3c24xx_reset_hook)(void);
+
+#include <asm/plat-s3c24xx/system-reset.h>
diff --git a/arch/arm/mach-s3c24a0/include/mach/tick.h b/arch/arm/mach-s3c24a0/include/mach/tick.h
new file mode 100644 (file)
index 0000000..9dea8ba
--- /dev/null
@@ -0,0 +1,15 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/tick.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C24A0 - timer tick support
+ */
+
+#define SUBSRC_TIMER4  (1 << (IRQ_TIMER4 - IRQ_S3CUART_RX0))
+
+static inline int s3c24xx_ostimer_pending(void)
+{
+       return __raw_readl(S3C2410_SUBSRCPND) & SUBSRC_TIMER4;
+}
diff --git a/arch/arm/mach-s3c24a0/include/mach/timex.h b/arch/arm/mach-s3c24a0/include/mach/timex.h
new file mode 100644 (file)
index 0000000..9857342
--- /dev/null
@@ -0,0 +1,18 @@
+/* linux/arch/arm/mach-s3c24a0/include/mach/timex.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 - time parameters
+ *
+ * This program is free software; you can 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_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+#define CLOCK_TICK_RATE 12000000
+
+#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-s3c24a0/include/mach/vmalloc.h b/arch/arm/mach-s3c24a0/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..4d4fe48
--- /dev/null
@@ -0,0 +1,17 @@
+/* linux/include/asm-arm/arch-s3c24ao/vmalloc.h
+ *
+ * Copyright 2008 Simtec Electronics <linux@simtec.co.uk>
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C24A0 vmalloc definition
+*/
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END      (0xE0000000)
+
+#endif /* __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/mach-s3c6400/Kconfig b/arch/arm/mach-s3c6400/Kconfig
new file mode 100644 (file)
index 0000000..6da82b5
--- /dev/null
@@ -0,0 +1,8 @@
+# arch/arm/mach-s3c6400/Kconfig
+#
+# Copyright 2008 Openmoko, Inc.
+#      Simtec Electronics, Ben Dooks <ben@simtec.co.uk>
+#
+# Licensed under GPLv2
+
+# Currently nothing here, this will be added later
diff --git a/arch/arm/mach-s3c6400/Makefile b/arch/arm/mach-s3c6400/Makefile
new file mode 100644 (file)
index 0000000..8f397db
--- /dev/null
@@ -0,0 +1,15 @@
+# arch/arm/mach-s3c6400/Makefile
+#
+# Copyright 2008 Openmoko, Inc.
+# Copyright 2008 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y                          :=
+obj-m                          :=
+obj-n                          :=
+obj-                           :=
+
+# Core support for S3C6400 system
+
+obj-n                          += blank.o
diff --git a/arch/arm/mach-s3c6400/Makefile.boot b/arch/arm/mach-s3c6400/Makefile.boot
new file mode 100644 (file)
index 0000000..ba41fdc
--- /dev/null
@@ -0,0 +1,2 @@
+   zreladdr-y  := 0x50008000
+params_phys-y  := 0x50000100
diff --git a/arch/arm/mach-s3c6400/include/mach/debug-macro.S b/arch/arm/mach-s3c6400/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..b18ac52
--- /dev/null
@@ -0,0 +1,39 @@
+/* arch/arm/mach-s3c6400/include/mach/debug-macro.S
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* pull in the relevant register and map files. */
+
+#include <mach/map.h>
+#include <plat/regs-serial.h>
+
+       /* note, for the boot process to work we have to keep the UART
+        * virtual address aligned to an 1MiB boundary for the L1
+        * mapping the head code makes. We keep the UART virtual address
+        * aligned and add in the offset when we load the value here.
+        */
+
+       .macro addruart, rx
+               mrc     p15, 0, \rx, c1, c0
+               tst     \rx, #1
+               ldreq   \rx, = S3C_PA_UART
+               ldrne   \rx, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
+#if CONFIG_DEBUG_S3C_UART != 0
+               add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+#endif
+       .endm
+
+/* include the reset of the code which will do the work, we're only
+ * compiling for a single cpu processor type so the default of s3c2440
+ * will be fine with us.
+ */
+
+#include <plat/debug-macro.S>
diff --git a/arch/arm/mach-s3c6400/include/mach/dma.h b/arch/arm/mach-s3c6400/include/mach/dma.h
new file mode 100644 (file)
index 0000000..9771ac2
--- /dev/null
@@ -0,0 +1,16 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/dma.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C6400 - DMA support
+ */
+
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H __FILE__
+
+/* currently nothing here, placeholder */
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/entry-macro.S b/arch/arm/mach-s3c6400/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..fbd90d2
--- /dev/null
@@ -0,0 +1,44 @@
+/* arch/arm/mach-s3c6400/include/mach/entry-macro.S
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Low-level IRQ helper macros for the Samsung S3C64XX series
+ *
+ * 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 <asm/hardware/vic.h>
+#include <mach/map.h>
+#include <plat/irqs.h>
+
+       .macro  disable_fiq
+       .endm
+
+       .macro  get_irqnr_preamble, base, tmp
+       ldr     \base, =S3C_VA_VIC0
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+       @ check the vic0
+       mov     \irqnr, # S3C_IRQ_OFFSET + 31
+       ldr     \irqstat, [ \base, # VIC_IRQ_STATUS ]
+       teq     \irqstat, #0
+
+       @ otherwise try vic1
+       addeq   \tmp, \base, #(S3C_VA_VIC1 - S3C_VA_VIC0)
+       addeq   \irqnr, \irqnr, #32
+       ldreq   \irqstat, [ \tmp, # VIC_IRQ_STATUS ]
+       teqeq   \irqstat, #0
+
+       clzne   \irqstat, \irqstat
+       subne   \irqnr, \irqnr, \irqstat
+       .endm
diff --git a/arch/arm/mach-s3c6400/include/mach/gpio-core.h b/arch/arm/mach-s3c6400/include/mach/gpio-core.h
new file mode 100644 (file)
index 0000000..d89aae6
--- /dev/null
@@ -0,0 +1,21 @@
+/* arch/arm/mach-s3c6400/include/mach/gpio-core.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - GPIO core support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_GPIO_CORE_H
+#define __ASM_ARCH_GPIO_CORE_H __FILE__
+
+/* currently we just include the platform support */
+#include <plat/gpio-core.h>
+
+#endif /* __ASM_ARCH_GPIO_CORE_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/gpio.h b/arch/arm/mach-s3c6400/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..e8e35e8
--- /dev/null
@@ -0,0 +1,96 @@
+/* arch/arm/mach-s3c6400/include/mach/gpio.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C6400 - GPIO lib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep  __gpio_cansleep
+#define gpio_to_irq    __gpio_to_irq
+
+/* GPIO bank sizes */
+#define S3C64XX_GPIO_A_NR      (8)
+#define S3C64XX_GPIO_B_NR      (7)
+#define S3C64XX_GPIO_C_NR      (8)
+#define S3C64XX_GPIO_D_NR      (5)
+#define S3C64XX_GPIO_E_NR      (5)
+#define S3C64XX_GPIO_F_NR      (16)
+#define S3C64XX_GPIO_G_NR      (7)
+#define S3C64XX_GPIO_H_NR      (10)
+#define S3C64XX_GPIO_I_NR      (16)
+#define S3C64XX_GPIO_J_NR      (12)
+#define S3C64XX_GPIO_K_NR      (16)
+#define S3C64XX_GPIO_L_NR      (15)
+#define S3C64XX_GPIO_M_NR      (6)
+#define S3C64XX_GPIO_N_NR      (16)
+#define S3C64XX_GPIO_O_NR      (16)
+#define S3C64XX_GPIO_P_NR      (15)
+#define S3C64XX_GPIO_Q_NR      (9)
+
+/* GPIO bank numbes */
+
+/* CONFIG_S3C_GPIO_SPACE allows the user to select extra
+ * space for debugging purposes so that any accidental
+ * change from one gpio bank to another can be caught.
+*/
+
+#define S3C64XX_GPIO_NEXT(__gpio) \
+       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+
+enum s3c_gpio_number {
+       S3C64XX_GPIO_A_START = 0,
+       S3C64XX_GPIO_B_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_A),
+       S3C64XX_GPIO_C_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_B),
+       S3C64XX_GPIO_D_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_C),
+       S3C64XX_GPIO_E_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_D),
+       S3C64XX_GPIO_F_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_E),
+       S3C64XX_GPIO_G_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_F),
+       S3C64XX_GPIO_H_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_G),
+       S3C64XX_GPIO_I_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_H),
+       S3C64XX_GPIO_J_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_I),
+       S3C64XX_GPIO_K_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_J),
+       S3C64XX_GPIO_L_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_K),
+       S3C64XX_GPIO_M_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_L),
+       S3C64XX_GPIO_N_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_M),
+       S3C64XX_GPIO_O_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_N),
+       S3C64XX_GPIO_P_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_O),
+       S3C64XX_GPIO_Q_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_P),
+};
+
+/* S3C64XX GPIO number definitions. */
+
+#define S3C64XX_GPA(_nr)       (S3C64XX_GPIO_A_START + (_nr))
+#define S3C64XX_GPB(_nr)       (S3C64XX_GPIO_B_START + (_nr))
+#define S3C64XX_GPC(_nr)       (S3C64XX_GPIO_C_START + (_nr))
+#define S3C64XX_GPD(_nr)       (S3C64XX_GPIO_D_START + (_nr))
+#define S3C64XX_GPE(_nr)       (S3C64XX_GPIO_E_START + (_nr))
+#define S3C64XX_GPF(_nr)       (S3C64XX_GPIO_F_START + (_nr))
+#define S3C64XX_GPG(_nr)       (S3C64XX_GPIO_G_START + (_nr))
+#define S3C64XX_GPH(_nr)       (S3C64XX_GPIO_H_START + (_nr))
+#define S3C64XX_GPI(_nr)       (S3C64XX_GPIO_I_START + (_nr))
+#define S3C64XX_GPJ(_nr)       (S3C64XX_GPIO_J_START + (_nr))
+#define S3C64XX_GPK(_nr)       (S3C64XX_GPIO_K_START + (_nr))
+#define S3C64XX_GPL(_nr)       (S3C64XX_GPIO_L_START + (_nr))
+#define S3C64XX_GPM(_nr)       (S3C64XX_GPIO_M_START + (_nr))
+#define S3C64XX_GPN(_nr)       (S3C64XX_GPIO_N_START + (_nr))
+#define S3C64XX_GPO(_nr)       (S3C64XX_GPIO_O_START + (_nr))
+#define S3C64XX_GPP(_nr)       (S3C64XX_GPIO_P_START + (_nr))
+#define S3C64XX_GPQ(_nr)       (S3C64XX_GPIO_Q_START + (_nr))
+
+/* the end of the S3C64XX specific gpios */
+#define S3C64XX_GPIO_END       (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1)
+#define S3C_GPIO_END           S3C64XX_GPIO_END
+
+/* define the number of gpios we need to the one after the GPQ() range */
+#define ARCH_NR_GPIOS  (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1)
+
+#include <asm-generic/gpio.h>
diff --git a/arch/arm/mach-s3c6400/include/mach/hardware.h b/arch/arm/mach-s3c6400/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..862d033
--- /dev/null
@@ -0,0 +1,16 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/hardware.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C6400 - Hardware support
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H __FILE__
+
+/* currently nothing here, placeholder */
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/irqs.h b/arch/arm/mach-s3c6400/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..b38c47c
--- /dev/null
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/irqs.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C6400 - IRQ definitions
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H __FILE__
+
+#ifndef __ASM_ARM_IRQ_H
+#error "Do not include this directly, instead #include <asm/irq.h>"
+#endif
+
+#include <plat/irqs.h>
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/map.h b/arch/arm/mach-s3c6400/include/mach/map.h
new file mode 100644 (file)
index 0000000..cff27d8
--- /dev/null
@@ -0,0 +1,68 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/map.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - Memory map definitions
+ *
+ * This program is free software; you can 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_MAP_H
+#define __ASM_ARCH_MAP_H __FILE__
+
+#include <plat/map-base.h>
+
+/* HSMMC units */
+#define S3C64XX_PA_HSMMC(x)    (0x7C200000 + ((x) * 0x100000))
+#define S3C64XX_PA_HSMMC0      S3C64XX_PA_HSMMC(0)
+#define S3C64XX_PA_HSMMC1      S3C64XX_PA_HSMMC(1)
+#define S3C64XX_PA_HSMMC2      S3C64XX_PA_HSMMC(2)
+
+#define S3C_PA_UART            (0x7F005000)
+#define S3C_PA_UART0           (S3C_PA_UART + 0x00)
+#define S3C_PA_UART1           (S3C_PA_UART + 0x400)
+#define S3C_PA_UART2           (S3C_PA_UART + 0x800)
+#define S3C_PA_UART3           (S3C_PA_UART + 0xC00)
+#define S3C_UART_OFFSET                (0x400)
+
+/* See notes on UART VA mapping in debug-macro.S */
+#define S3C_VA_UARTx(x)        (S3C_VA_UART + (S3C_PA_UART & 0xfffff) + ((x) * S3C_UART_OFFSET))
+
+#define S3C_VA_UART0           S3C_VA_UARTx(0)
+#define S3C_VA_UART1           S3C_VA_UARTx(1)
+#define S3C_VA_UART2           S3C_VA_UARTx(2)
+#define S3C_VA_UART3           S3C_VA_UARTx(3)
+
+#define S3C64XX_PA_FB          (0x77100000)
+#define S3C64XX_PA_SYSCON      (0x7E00F000)
+#define S3C64XX_PA_TIMER       (0x7F006000)
+#define S3C64XX_PA_IIC0                (0x7F004000)
+#define S3C64XX_PA_IIC1                (0x7F00F000)
+
+#define S3C64XX_PA_GPIO                (0x7F008000)
+#define S3C64XX_VA_GPIO                S3C_ADDR(0x00500000)
+#define S3C64XX_SZ_GPIO                SZ_4K
+
+#define S3C64XX_PA_SDRAM       (0x50000000)
+#define S3C64XX_PA_VIC0                (0x71200000)
+#define S3C64XX_PA_VIC1                (0x71300000)
+
+/* place VICs close together */
+#define S3C_VA_VIC0            (S3C_VA_IRQ + 0x00)
+#define S3C_VA_VIC1            (S3C_VA_IRQ + 0x10000)
+
+/* compatibiltiy defines. */
+#define S3C_PA_TIMER           S3C64XX_PA_TIMER
+#define S3C_PA_HSMMC0          S3C64XX_PA_HSMMC0
+#define S3C_PA_HSMMC1          S3C64XX_PA_HSMMC1
+#define S3C_PA_HSMMC2          S3C64XX_PA_HSMMC2
+#define S3C_PA_IIC             S3C64XX_PA_IIC0
+#define S3C_PA_IIC1            S3C64XX_PA_IIC1
+#define S3C_PA_FB              S3C64XX_PA_FB
+
+#endif /* __ASM_ARCH_6400_MAP_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/memory.h b/arch/arm/mach-s3c6400/include/mach/memory.h
new file mode 100644 (file)
index 0000000..a3ac84a
--- /dev/null
@@ -0,0 +1,18 @@
+/* arch/arm/mach-s3c6400/include/mach/memory.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can 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_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET     UL(0x50000000)
+
+#endif
diff --git a/arch/arm/mach-s3c6400/include/mach/pwm-clock.h b/arch/arm/mach-s3c6400/include/mach/pwm-clock.h
new file mode 100644 (file)
index 0000000..b25bede
--- /dev/null
@@ -0,0 +1,56 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/pwm-clock.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64xx - pwm clock and timer support
+ */
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+       return tcfg >= S3C64XX_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+       return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+       return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+       return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C64XX_TCFG1_MUX_TCLK
diff --git a/arch/arm/mach-s3c6400/include/mach/regs-fb.h b/arch/arm/mach-s3c6400/include/mach/regs-fb.h
new file mode 100644 (file)
index 0000000..4701979
--- /dev/null
@@ -0,0 +1,259 @@
+/* arch/arm/mach-s3c6400/include/mach/regs-fb.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - new-style framebuffer register definitions
+ *
+ * This is the register set for the new style framebuffer interface
+ * found from the S3C2443 onwards and specifically the S3C64XX series
+ * S3C6400 and S3C6410.
+ *
+ * The file contains the cpu specific items which change between whichever
+ * architecture is selected. See <plat/regs-fb.h> for the core definitions
+ * that are the same.
+ *
+ * This program is free software; you can 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 the core definitions here, in case we really do need to
+ * override them at a later date.
+*/
+
+#include <plat/regs-fb.h>
+
+#define S3C_FB_MAX_WIN (5)  /* number of hardware windows available. */
+#define VIDCON1_FSTATUS_EVEN   (1 << 15)
+
+/* Video timing controls */
+#define VIDTCON0                               (0x10)
+#define VIDTCON1                               (0x14)
+#define VIDTCON2                               (0x18)
+
+/* Window position controls */
+
+#define WINCON(_win)                           (0x20 + ((_win) * 4))
+
+/* OSD1 and OSD4 do not have register D */
+
+#define VIDOSD_A(_win)                         (0x40 + ((_win) * 16))
+#define VIDOSD_B(_win)                         (0x44 + ((_win) * 16))
+#define VIDOSD_C(_win)                         (0x48 + ((_win) * 16))
+#define VIDOSD_D(_win)                         (0x4C + ((_win) * 16))
+
+/* Video buffer addresses */
+
+#define VIDW_BUF_START(_buff)                  (0xA0 + ((_buff) * 8))
+#define VIDW_BUF_START1(_buff)                 (0xA4 + ((_buff) * 8))
+#define VIDW_BUF_END(_buff)                    (0xD0 + ((_buff) * 8))
+#define VIDW_BUF_END1(_buff)                   (0xD4 + ((_buff) * 8))
+#define VIDW_BUF_SIZE(_buff)                   (0x100 + ((_buff) * 4))
+
+#define VIDINTCON0                             (0x130)
+
+#define WxKEYCONy(_win, _con)                  ((0x140 + ((_win) * 8)) + ((_con) * 4))
+
+/* WINCONx */
+
+#define WINCONx_CSCWIDTH_MASK                  (0x3 << 26)
+#define WINCONx_CSCWIDTH_SHIFT                 (26)
+#define WINCONx_CSCWIDTH_WIDE                  (0x0 << 26)
+#define WINCONx_CSCWIDTH_NARROW                        (0x3 << 26)
+
+#define WINCONx_ENLOCAL                                (1 << 22)
+#define WINCONx_BUFSTATUS                      (1 << 21)
+#define WINCONx_BUFSEL                         (1 << 20)
+#define WINCONx_BUFAUTOEN                      (1 << 19)
+#define WINCONx_YCbCr                          (1 << 13)
+
+#define WINCON1_LOCALSEL_CAMIF                 (1 << 23)
+
+#define WINCON2_LOCALSEL_CAMIF                 (1 << 23)
+#define WINCON2_BLD_PIX                                (1 << 6)
+
+#define WINCON2_ALPHA_SEL                      (1 << 1)
+#define WINCON2_BPPMODE_MASK                   (0xf << 2)
+#define WINCON2_BPPMODE_SHIFT                  (2)
+#define WINCON2_BPPMODE_1BPP                   (0x0 << 2)
+#define WINCON2_BPPMODE_2BPP                   (0x1 << 2)
+#define WINCON2_BPPMODE_4BPP                   (0x2 << 2)
+#define WINCON2_BPPMODE_8BPP_1232              (0x4 << 2)
+#define WINCON2_BPPMODE_16BPP_565              (0x5 << 2)
+#define WINCON2_BPPMODE_16BPP_A1555            (0x6 << 2)
+#define WINCON2_BPPMODE_16BPP_I1555            (0x7 << 2)
+#define WINCON2_BPPMODE_18BPP_666              (0x8 << 2)
+#define WINCON2_BPPMODE_18BPP_A1665            (0x9 << 2)
+#define WINCON2_BPPMODE_19BPP_A1666            (0xa << 2)
+#define WINCON2_BPPMODE_24BPP_888              (0xb << 2)
+#define WINCON2_BPPMODE_24BPP_A1887            (0xc << 2)
+#define WINCON2_BPPMODE_25BPP_A1888            (0xd << 2)
+#define WINCON2_BPPMODE_28BPP_A4888            (0xd << 2)
+
+#define WINCON3_BLD_PIX                                (1 << 6)
+
+#define WINCON3_ALPHA_SEL                      (1 << 1)
+#define WINCON3_BPPMODE_MASK                   (0xf << 2)
+#define WINCON3_BPPMODE_SHIFT                  (2)
+#define WINCON3_BPPMODE_1BPP                   (0x0 << 2)
+#define WINCON3_BPPMODE_2BPP                   (0x1 << 2)
+#define WINCON3_BPPMODE_4BPP                   (0x2 << 2)
+#define WINCON3_BPPMODE_16BPP_565              (0x5 << 2)
+#define WINCON3_BPPMODE_16BPP_A1555            (0x6 << 2)
+#define WINCON3_BPPMODE_16BPP_I1555            (0x7 << 2)
+#define WINCON3_BPPMODE_18BPP_666              (0x8 << 2)
+#define WINCON3_BPPMODE_18BPP_A1665            (0x9 << 2)
+#define WINCON3_BPPMODE_19BPP_A1666            (0xa << 2)
+#define WINCON3_BPPMODE_24BPP_888              (0xb << 2)
+#define WINCON3_BPPMODE_24BPP_A1887            (0xc << 2)
+#define WINCON3_BPPMODE_25BPP_A1888            (0xd << 2)
+#define WINCON3_BPPMODE_28BPP_A4888            (0xd << 2)
+
+#define VIDINTCON0_FIFIOSEL_WINDOW2            (0x10 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW3            (0x20 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW4            (0x40 << 5)
+
+#define DITHMODE                               (0x170)
+#define WINxMAP(_win)                          (0x180 + ((_win) * 4))
+
+
+#define DITHMODE_R_POS_MASK                    (0x3 << 5)
+#define DITHMODE_R_POS_SHIFT                   (5)
+#define DITHMODE_R_POS_8BIT                    (0x0 << 5)
+#define DITHMODE_R_POS_6BIT                    (0x1 << 5)
+#define DITHMODE_R_POS_5BIT                    (0x2 << 5)
+
+#define DITHMODE_G_POS_MASK                    (0x3 << 3)
+#define DITHMODE_G_POS_SHIFT                   (3)
+#define DITHMODE_G_POS_8BIT                    (0x0 << 3)
+#define DITHMODE_G_POS_6BIT                    (0x1 << 3)
+#define DITHMODE_G_POS_5BIT                    (0x2 << 3)
+
+#define DITHMODE_B_POS_MASK                    (0x3 << 1)
+#define DITHMODE_B_POS_SHIFT                   (1)
+#define DITHMODE_B_POS_8BIT                    (0x0 << 1)
+#define DITHMODE_B_POS_6BIT                    (0x1 << 1)
+#define DITHMODE_B_POS_5BIT                    (0x2 << 1)
+
+#define DITHMODE_DITH_EN                       (1 << 0)
+
+#define WPALCON                                        (0x1A0)
+
+#define WPALCON_W4PAL_16BPP_A555               (1 << 8)
+#define WPALCON_W3PAL_16BPP_A555               (1 << 7)
+#define WPALCON_W2PAL_16BPP_A555               (1 << 6)
+
+/* Palette registers */
+
+#define WIN2_PAL(_entry)                       (0x300 + ((_entry) * 2))
+#define WIN3_PAL(_entry)                       (0x320 + ((_entry) * 2))
+#define WIN4_PAL(_entry)                       (0x340 + ((_entry) * 2))
+#define WIN0_PAL(_entry)                       (0x400 + ((_entry) * 4))
+#define WIN1_PAL(_entry)                       (0x800 + ((_entry) * 4))
+
+/* system specific implementation code for palette sizes, and other
+ * information that changes depending on which architecture is being
+ * compiled.
+*/
+
+/* return true if window _win has OSD register D */
+#define s3c_fb_has_osd_d(_win) ((_win) != 4 && (_win) != 0)
+
+static inline unsigned int s3c_fb_win_pal_size(unsigned int win)
+{
+       if (win < 2)
+               return 256;
+       if (win < 4)
+               return 16;
+       if (win == 4)
+               return 4;
+
+       BUG();  /* shouldn't get here */
+}
+
+static inline int s3c_fb_validate_win_bpp(unsigned int win, unsigned int bpp)
+{
+       /* all windows can do 1/2 bpp */
+
+       if ((bpp == 25 || bpp == 19) && win == 0)
+               return 0;       /* win 0 does not have 19 or 25bpp modes */
+
+       if (bpp == 4 && win == 4)
+               return 0;
+
+       if (bpp == 8 && (win >= 3))
+               return 0;       /* win 3/4 cannot do 8bpp in any mode */
+
+       return 1;
+}
+
+static inline unsigned int s3c_fb_pal_reg(unsigned int window, int reg)
+{
+       switch (window) {
+       case 0: return WIN0_PAL(reg);
+       case 1: return WIN1_PAL(reg);
+       case 2: return WIN2_PAL(reg);
+       case 3: return WIN3_PAL(reg);
+       case 4: return WIN4_PAL(reg);
+       }
+
+       BUG();
+}
+
+static inline int s3c_fb_pal_is16(unsigned int window)
+{
+       return window > 1;
+}
+
+struct s3c_fb_palette {
+       struct fb_bitfield      r;
+       struct fb_bitfield      g;
+       struct fb_bitfield      b;
+       struct fb_bitfield      a;
+};
+
+static inline void s3c_fb_init_palette(unsigned int window,
+                                      struct s3c_fb_palette *palette)
+{
+       if (window < 2) {
+               /* Windows 0/1 are 8/8/8 or A/8/8/8 */
+               palette->r.offset = 16;
+               palette->r.length = 8;
+               palette->g.offset = 8;
+               palette->g.length = 8;
+               palette->b.offset = 0;
+               palette->b.length = 8;
+       } else {
+               /* currently we assume RGB 5/6/5 */
+               palette->r.offset = 11;
+               palette->r.length = 5;
+               palette->g.offset = 5;
+               palette->g.length = 6;
+               palette->b.offset = 0;
+               palette->b.length = 5;
+       }
+}
+
+/* Notes on per-window bpp settings
+ *
+ * Value       Win0     Win1     Win2     Win3     Win 4
+ * 0000                1(P)     1(P)     1(P)     1(P)     1(P)
+ * 0001                2(P)     2(P)     2(P)     2(P)     2(P)
+ * 0010                4(P)     4(P)     4(P)     4(P)     -none-
+ * 0011                8(P)     8(P)     -none-   -none-   -none-
+ * 0100                -none-   8(A232)  8(A232)  -none-   -none-
+ * 0101                16(565)  16(565)  16(565)  16(565)   16(565)
+ * 0110                -none-   16(A555) 16(A555) 16(A555)  16(A555)
+ * 0111                16(I555) 16(I565) 16(I555) 16(I555)  16(I555)
+ * 1000                18(666)  18(666)  18(666)  18(666)   18(666)
+ * 1001                -none-   18(A665) 18(A665) 18(A665)  16(A665)
+ * 1010                -none-   19(A666) 19(A666) 19(A666)  19(A666)
+ * 1011                24(888)  24(888)  24(888)  24(888)   24(888)
+ * 1100                -none-   24(A887) 24(A887) 24(A887)  24(A887)
+ * 1101                -none-   25(A888) 25(A888) 25(A888)  25(A888)
+ * 1110                -none-   -none-   -none-   -none-    -none-
+ * 1111                -none-   -none-   -none-   -none-    -none-
+*/
diff --git a/arch/arm/mach-s3c6400/include/mach/regs-irq.h b/arch/arm/mach-s3c6400/include/mach/regs-irq.h
new file mode 100644 (file)
index 0000000..bcce68a
--- /dev/null
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/regs-irq.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - IRQ register definitions
+ *
+ * This program is free software; you can 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_REGS_IRQ_H
+#define __ASM_ARCH_REGS_IRQ_H __FILE__
+
+#include <asm/hardware/vic.h>
+
+#endif /* __ASM_ARCH_6400_REGS_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/system.h b/arch/arm/mach-s3c6400/include/mach/system.h
new file mode 100644 (file)
index 0000000..652bbc4
--- /dev/null
@@ -0,0 +1,24 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/system.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C6400 - system implementation
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H __FILE__
+
+static void arch_idle(void)
+{
+       /* nothing here yet */
+}
+
+static void arch_reset(char mode)
+{
+       /* nothing here yet */
+}
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/tick.h b/arch/arm/mach-s3c6400/include/mach/tick.h
new file mode 100644 (file)
index 0000000..d9c0dc7
--- /dev/null
@@ -0,0 +1,29 @@
+/* linux/arch/arm/mach-s3c6400/include/mach/tick.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C64XX - Timer tick support definitions
+ *
+ * This program is free software; you can 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_TICK_H
+#define __ASM_ARCH_TICK_H __FILE__
+
+/* note, the timer interrutps turn up in 2 places, the vic and then
+ * the timer block. We take the VIC as the base at the moment.
+ */
+static inline u32 s3c24xx_ostimer_pending(void)
+{
+       u32 pend = __raw_readl(S3C_VA_VIC0 + VIC_RAW_STATUS);
+       return pend & 1 << (IRQ_TIMER4_VIC - S3C64XX_IRQ_VIC0(0));
+}
+
+#define TICK_MAX       (0xffffffff)
+
+#endif /* __ASM_ARCH_6400_TICK_H */
diff --git a/arch/arm/mach-s3c6400/include/mach/uncompress.h b/arch/arm/mach-s3c6400/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..c6a82a2
--- /dev/null
@@ -0,0 +1,28 @@
+/* arch/arm/mach-s3c6400/include/mach/uncompress.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C6400 - uncompress code
+ *
+ * This program is free software; you can 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_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <mach/map.h>
+#include <plat/uncompress.h>
+
+static void arch_detect_cpu(void)
+{
+       /* we do not need to do any cpu detection here at the moment. */
+       fifo_mask = S3C2440_UFSTAT_TXMASK;
+       fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT;
+}
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s3c6410/Kconfig b/arch/arm/mach-s3c6410/Kconfig
new file mode 100644 (file)
index 0000000..1d50100
--- /dev/null
@@ -0,0 +1,62 @@
+# arch/arm/mach-s3c6410/Kconfig
+#
+# Copyright 2008 Openmoko, Inc.
+# Copyright 2008 Simtec Electronics
+#
+# Licensed under GPLv2
+
+# Configuration options for the S3C6410 CPU
+
+config CPU_S3C6410
+       bool
+       select CPU_S3C6400_INIT
+       select CPU_S3C6400_CLOCK
+       help
+         Enable S3C6410 CPU support
+
+config S3C6410_SETUP_SDHCI
+       bool
+       help
+         Internal helper functions for S3C6410 based SDHCI systems
+
+config MACH_SMDK6410
+       bool "SMDK6410"
+       select CPU_S3C6410
+       select S3C_DEV_HSMMC
+       select S3C_DEV_HSMMC1
+       select S3C_DEV_I2C1
+       select S3C_DEV_FB
+       select S3C6410_SETUP_SDHCI
+       select S3C64XX_SETUP_I2C1
+       select S3C64XX_SETUP_FB_24BPP
+       help
+         Machine support for the Samsung SMDK6410
+
+# At least some of the SMDK6410s were shipped with the card detect
+# for the MMC/SD slots connected to the same input. This means that
+# either the boards need to be altered to have channel0 to an alternate
+# configuration or that only one slot can be used.
+
+choice
+       prompt "SMDK6410 MMC/SD slot setup"
+       depends on MACH_SMDK6410
+
+config SMDK6410_SD_CH0
+       bool "Use channel 0 only"
+       depends on MACH_SMDK6410
+       help
+          Select CON7 (channel 0) as the MMC/SD slot, as
+         at least some SMDK6410 boards come with the
+         resistors fitted so that the card detects for
+         channels 0 and 1 are the same.
+       
+config SMDK6410_SD_CH1
+       bool "Use channel 1 only"
+       depends on MACH_SMDK6410
+       help
+          Select CON6 (channel 1) as the MMC/SD slot, as
+         at least some SMDK6410 boards come with the
+         resistors fitted so that the card detects for
+         channels 0 and 1 are the same.
+
+endchoice
diff --git a/arch/arm/mach-s3c6410/Makefile b/arch/arm/mach-s3c6410/Makefile
new file mode 100644 (file)
index 0000000..2cd4f18
--- /dev/null
@@ -0,0 +1,23 @@
+# arch/arm/plat-s3c6410/Makefile
+#
+# Copyright 2008 Openmoko, Inc.
+# Copyright 2008 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y                          :=
+obj-m                          :=
+obj-n                          :=
+obj-                           :=
+
+# Core support for S3C6410 system
+
+obj-$(CONFIG_CPU_S3C6410)      += cpu.o
+
+# Helper and device support
+
+obj-$(CONFIG_S3C6410_SETUP_SDHCI)      += setup-sdhci.o
+
+# machine support
+
+obj-$(CONFIG_MACH_SMDK6410)    += mach-smdk6410.o
diff --git a/arch/arm/mach-s3c6410/cpu.c b/arch/arm/mach-s3c6410/cpu.c
new file mode 100644 (file)
index 0000000..6a73ca6
--- /dev/null
@@ -0,0 +1,101 @@
+/* linux/arch/arm/mach-s3c6410/cpu.c
+ *
+ * Copyright 2008 Simtec Electronics
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/regs-serial.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/sdhci.h>
+#include <plat/iic-core.h>
+#include <plat/s3c6400.h>
+#include <plat/s3c6410.h>
+
+/* Initial IO mappings */
+
+static struct map_desc s3c6410_iodesc[] __initdata = {
+};
+
+/* s3c6410_map_io
+ *
+ * register the standard cpu IO areas
+*/
+
+void __init s3c6410_map_io(void)
+{
+       iotable_init(s3c6410_iodesc, ARRAY_SIZE(s3c6410_iodesc));
+
+       /* initialise device information early */
+       s3c6410_default_sdhci0();
+       s3c6410_default_sdhci1();
+
+       /* the i2c devices are directly compatible with s3c2440 */
+       s3c_i2c0_setname("s3c2440-i2c");
+       s3c_i2c1_setname("s3c2440-i2c");
+}
+
+void __init s3c6410_init_clocks(int xtal)
+{
+       printk(KERN_DEBUG "%s: initialising clocks\n", __func__);
+       s3c24xx_register_baseclocks(xtal);
+       s3c64xx_register_clocks();
+       s3c6400_register_clocks();
+       s3c6400_setup_clocks();
+}
+
+void __init s3c6410_init_irq(void)
+{
+       /* VIC0 is missing IRQ7, VIC1 is fully populated. */
+       s3c64xx_init_irq(~0 & ~(1 << 7), ~0);
+}
+
+struct sysdev_class s3c6410_sysclass = {
+       .name   = "s3c6410-core",
+};
+
+static struct sys_device s3c6410_sysdev = {
+       .cls    = &s3c6410_sysclass,
+};
+
+static int __init s3c6410_core_init(void)
+{
+       return sysdev_class_register(&s3c6410_sysclass);
+}
+
+core_initcall(s3c6410_core_init);
+
+int __init s3c6410_init(void)
+{
+       printk("S3C6410: Initialising architecture\n");
+
+       return sysdev_register(&s3c6410_sysdev);
+}
diff --git a/arch/arm/mach-s3c6410/mach-smdk6410.c b/arch/arm/mach-s3c6410/mach-smdk6410.c
new file mode 100644 (file)
index 0000000..3c4d471
--- /dev/null
@@ -0,0 +1,185 @@
+/* linux/arch/arm/mach-s3c6410/mach-smdk6410.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-fb.h>
+#include <mach/map.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/iic.h>
+#include <plat/fb.h>
+
+#include <plat/s3c6410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk6410_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport      = 0,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+       [1] = {
+               .hwport      = 1,
+               .flags       = 0,
+               .ucon        = 0x3c5,
+               .ulcon       = 0x03,
+               .ufcon       = 0x51,
+       },
+};
+
+/* framebuffer and LCD setup. */
+
+/* GPF15 = LCD backlight control
+ * GPF13 => Panel power
+ * GPN5 = LCD nRESET signal
+ * PWM_TOUT1 => backlight brightness
+ */
+
+static void smdk6410_lcd_power_set(struct plat_lcd_data *pd,
+                                  unsigned int power)
+{
+       if (power) {
+               gpio_direction_output(S3C64XX_GPF(13), 1);
+               gpio_direction_output(S3C64XX_GPF(15), 1);
+
+               /* fire nRESET on power up */
+               gpio_direction_output(S3C64XX_GPN(5), 0);
+               msleep(10);
+               gpio_direction_output(S3C64XX_GPN(5), 1);
+               msleep(1);
+       } else {
+               gpio_direction_output(S3C64XX_GPF(15), 0);
+               gpio_direction_output(S3C64XX_GPF(13), 0);
+       }
+}
+
+static struct plat_lcd_data smdk6410_lcd_power_data = {
+       .set_power      = smdk6410_lcd_power_set,
+};
+
+static struct platform_device smdk6410_lcd_powerdev = {
+       .name                   = "platform-lcd",
+       .dev.parent             = &s3c_device_fb.dev,
+       .dev.platform_data      = &smdk6410_lcd_power_data,
+};
+
+static struct s3c_fb_pd_win smdk6410_fb_win0 = {
+       /* this is to ensure we use win0 */
+       .win_mode       = {
+               .pixclock       = 41094,
+               .left_margin    = 8,
+               .right_margin   = 13,
+               .upper_margin   = 7,
+               .lower_margin   = 5,
+               .hsync_len      = 3,
+               .vsync_len      = 1,
+               .xres           = 800,
+               .yres           = 480,
+       },
+       .max_bpp        = 32,
+       .default_bpp    = 16,
+};
+
+/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
+static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = {
+       .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
+       .win[0]         = &smdk6410_fb_win0,
+       .vidcon0        = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+       .vidcon1        = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+struct map_desc smdk6410_iodesc[] = {};
+
+static struct platform_device *smdk6410_devices[] __initdata = {
+#ifdef CONFIG_SMDK6410_SD_CH0
+       &s3c_device_hsmmc0,
+#endif
+#ifdef CONFIG_SMDK6410_SD_CH1
+       &s3c_device_hsmmc1,
+#endif
+       &s3c_device_i2c0,
+       &s3c_device_i2c1,
+       &s3c_device_fb,
+       &smdk6410_lcd_powerdev,
+};
+
+static struct i2c_board_info i2c_devs0[] __initdata = {
+       { I2C_BOARD_INFO("24c08", 0x50), },
+       { I2C_BOARD_INFO("WM8580", 0X1b), },
+};
+
+static struct i2c_board_info i2c_devs1[] __initdata = {
+       { I2C_BOARD_INFO("24c128", 0x57), },    /* Samsung S524AD0XD1 */
+};
+
+static void __init smdk6410_map_io(void)
+{
+       s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc));
+       s3c24xx_init_clocks(12000000);
+       s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs));
+}
+
+static void __init smdk6410_machine_init(void)
+{
+       s3c_i2c0_set_platdata(NULL);
+       s3c_i2c1_set_platdata(NULL);
+       s3c_fb_set_platdata(&smdk6410_lcd_pdata);
+
+       i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
+       i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
+
+       platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
+}
+
+MACHINE_START(SMDK6410, "SMDK6410")
+       /* Maintainer: Ben Dooks <ben@fluff.org> */
+       .phys_io        = S3C_PA_UART & 0xfff00000,
+       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = S3C64XX_PA_SDRAM + 0x100,
+
+       .init_irq       = s3c6410_init_irq,
+       .map_io         = smdk6410_map_io,
+       .init_machine   = smdk6410_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c6410/setup-sdhci.c b/arch/arm/mach-s3c6410/setup-sdhci.c
new file mode 100644 (file)
index 0000000..0b5788b
--- /dev/null
@@ -0,0 +1,102 @@
+/* linux/arch/arm/mach-s3c6410/setup-sdhci.c
+ *
+ * Copyright 2008 Simtec Electronics
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C6410 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <mach/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <plat/regs-sdhci.h>
+#include <plat/sdhci.h>
+
+/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
+
+char *s3c6410_hsmmc_clksrcs[4] = {
+       [0] = "hsmmc",
+       [1] = "hsmmc",
+       [2] = "mmc_bus",
+       /* [3] = "48m", - note not succesfully used yet */
+};
+
+void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S3C64XX_GPG(2 + width);
+
+       /* Set all the necessary GPG pins to special-function 0 */
+       for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2));
+}
+
+void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
+                                   void __iomem *r,
+                                   struct mmc_ios *ios,
+                                   struct mmc_card *card)
+{
+       u32 ctrl2, ctrl3;
+
+       /* don't need to alter anything acording to card-type */
+
+       writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, r + S3C64XX_SDHCI_CONTROL4);
+
+       ctrl2 = readl(r + S3C_SDHCI_CONTROL2);
+       ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+       ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
+                 S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
+                 S3C_SDHCI_CTRL2_ENFBCLKRX |
+                 S3C_SDHCI_CTRL2_DFCNT_NONE |
+                 S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
+
+       if (ios->clock < 25 * 1000000)
+               ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 |
+                        S3C_SDHCI_CTRL3_FCSEL2 |
+                        S3C_SDHCI_CTRL3_FCSEL1 |
+                        S3C_SDHCI_CTRL3_FCSEL0);
+       else
+               ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
+
+       printk(KERN_INFO "%s: CTRL 2=%08x, 3=%08x\n", __func__, ctrl2, ctrl3);
+       writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+       writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
+
+void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+       unsigned int gpio;
+       unsigned int end;
+
+       end = S3C64XX_GPH(2 + width);
+
+       /* Set all the necessary GPG pins to special-function 0 */
+       for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3));
+}
index 43c30f84abf2b05c6a6212948bb4069d0f5904ea..dab3c6347a8f2d8e80bafba18b6916f8f97161f9 100644 (file)
@@ -3,6 +3,7 @@
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <mach/hardware.h>
 
 /*
- * Very simple clock implementation - we only have one clock to
- * deal with at the moment, so we only match using the "name".
+ * Very simple clock implementation - we only have one clock to deal with.
  */
 struct clk {
-       struct list_head        node;
-       unsigned long           rate;
-       const char              *name;
        unsigned int            enabled;
-       void                    (*enable)(void);
-       void                    (*disable)(void);
 };
 
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
+static void clk_gpio27_enable(void)
+{
+       /*
+        * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+        * (SA-1110 Developer's Manual, section 9.1.2.1)
+        */
+       GAFR |= GPIO_32_768kHz;
+       GPDR |= GPIO_32_768kHz;
+       TUCR = TUCR_3_6864MHz;
+}
+
+static void clk_gpio27_disable(void)
+{
+       TUCR = 0;
+       GPDR &= ~GPIO_32_768kHz;
+       GAFR &= ~GPIO_32_768kHz;
+}
+
+static struct clk clk_gpio27;
+
 static DEFINE_SPINLOCK(clocks_lock);
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               if (strcmp(id, p->name) == 0) {
-                       clk = p;
-                       break;
-               }
-       }
-       mutex_unlock(&clocks_mutex);
+       const char *devname = dev_name(dev);
 
-       return clk;
+       return strcmp(devname, "sa1111.0") ? ERR_PTR(-ENOENT) : &clk_gpio27;
 }
 EXPORT_SYMBOL(clk_get);
 
@@ -58,7 +62,7 @@ int clk_enable(struct clk *clk)
 
        spin_lock_irqsave(&clocks_lock, flags);
        if (clk->enabled++ == 0)
-               clk->enable();
+               clk_gpio27_enable();
        spin_unlock_irqrestore(&clocks_lock, flags);
        return 0;
 }
@@ -72,63 +76,13 @@ void clk_disable(struct clk *clk)
 
        spin_lock_irqsave(&clocks_lock, flags);
        if (--clk->enabled == 0)
-               clk->disable();
+               clk_gpio27_disable();
        spin_unlock_irqrestore(&clocks_lock, flags);
 }
 EXPORT_SYMBOL(clk_disable);
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-       return clk->rate;
+       return 3686400;
 }
 EXPORT_SYMBOL(clk_get_rate);
-
-
-static void clk_gpio27_enable(void)
-{
-       /*
-        * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
-        * (SA-1110 Developer's Manual, section 9.1.2.1)
-        */
-       GAFR |= GPIO_32_768kHz;
-       GPDR |= GPIO_32_768kHz;
-       TUCR = TUCR_3_6864MHz;
-}
-
-static void clk_gpio27_disable(void)
-{
-       TUCR = 0;
-       GPDR &= ~GPIO_32_768kHz;
-       GAFR &= ~GPIO_32_768kHz;
-}
-
-static struct clk clk_gpio27 = {
-       .name           = "SA1111_CLK",
-       .rate           = 3686400,
-       .enable         = clk_gpio27_enable,
-       .disable        = clk_gpio27_disable,
-};
-
-int clk_register(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_del(&clk->node);
-       mutex_unlock(&clocks_mutex);
-}
-EXPORT_SYMBOL(clk_unregister);
-
-static int __init clk_init(void)
-{
-       clk_register(&clk_gpio27);
-       return 0;
-}
-arch_initcall(clk_init);
index fe289997cfaf5942fade071d26b92574001ff95b..2052eb88c961356fe3417fcce4ea6d8e4c9c9f78 100644 (file)
@@ -68,23 +68,22 @@ struct platform_device colliescoop_device = {
 };
 
 static struct scoop_pcmcia_dev collie_pcmcia_scoop[] = {
-{
-       .dev        = &colliescoop_device.dev,
-       .irq        = COLLIE_IRQ_GPIO_CF_IRQ,
-       .cd_irq     = COLLIE_IRQ_GPIO_CF_CD,
-       .cd_irq_str = "PCMCIA0 CD",
-},
+       {
+       .dev            = &colliescoop_device.dev,
+       .irq            = COLLIE_IRQ_GPIO_CF_IRQ,
+       .cd_irq         = COLLIE_IRQ_GPIO_CF_CD,
+       .cd_irq_str     = "PCMCIA0 CD",
+       },
 };
 
 static struct scoop_pcmcia_config collie_pcmcia_config = {
-       .devs         = &collie_pcmcia_scoop[0],
-       .num_devs     = 1,
+       .devs           = &collie_pcmcia_scoop[0],
+       .num_devs       = 1,
 };
 
-
 static struct mcp_plat_data collie_mcp_data = {
-       .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
-       .sclk_rate      = 9216000,
+       .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
+       .sclk_rate      = 9216000,
 };
 
 #ifdef CONFIG_SHARP_LOCOMO
@@ -95,14 +94,14 @@ struct platform_device collie_locomo_device;
 
 static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
 {
-       if (mctrl & TIOCM_RTS)
+       if (mctrl & TIOCM_RTS)
                locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0);
-       else
+       else
                locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1);
 
-       if (mctrl & TIOCM_DTR)
+       if (mctrl & TIOCM_DTR)
                locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0);
-       else
+       else
                locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1);
 }
 
index b1161fc80602121fdf0530f2c0fa6678200e12a6..b39307f26b5209b6e43bb1592e311f1cf6df9be7 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/hardware/scoop.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach/sharpsl_param.h>
 #include <asm/hardware/sharpsl_pm.h>
@@ -263,24 +263,24 @@ static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev)
 }
 
 static struct ucb1x00_driver collie_pm_ucb_driver = {
-       .add            = collie_pm_ucb_add,
+       .add    = collie_pm_ucb_add,
 };
 
 static struct platform_device *collie_pm_device;
 
 static int __init collie_pm_init(void)
 {
-        int ret;
+       int ret;
 
-        collie_pm_device = platform_device_alloc("sharpsl-pm", -1);
-        if (!collie_pm_device)
-                return -ENOMEM;
+       collie_pm_device = platform_device_alloc("sharpsl-pm", -1);
+       if (!collie_pm_device)
+               return -ENOMEM;
 
-        collie_pm_device->dev.platform_data = &collie_pm_machinfo;
-        ret = platform_device_add(collie_pm_device);
+       collie_pm_device->dev.platform_data = &collie_pm_machinfo;
+       ret = platform_device_add(collie_pm_device);
 
-        if (ret)
-                platform_device_put(collie_pm_device);
+       if (ret)
+               platform_device_put(collie_pm_device);
 
        if (!ret)
                ret = ucb1x00_register_driver(&collie_pm_ucb_driver);
@@ -291,7 +291,7 @@ static int __init collie_pm_init(void)
 static void __exit collie_pm_exit(void)
 {
        ucb1x00_unregister_driver(&collie_pm_ucb_driver);
-        platform_device_unregister(collie_pm_device);
+       platform_device_unregister(collie_pm_device);
 }
 
 module_init(collie_pm_init);
index 244d5956312cfb106cf90e39a4863ba082943ac0..ef817876a5d68d6597d42cefd2135c0e8769bbe2 100644 (file)
@@ -3,17 +3,17 @@
  *
  * Copyright (C) 2000 2001, The Delft University of Technology
  *
- * Authors: 
+ * Authors:
  * - Johan Pouwelse (J.A.Pouwelse@its.tudelft.nl): initial version
  * - Erik Mouw (J.A.K.Mouw@its.tudelft.nl):
  *   - major rewrite for linux-2.3.99
- *   - rewritten for the more generic power management scheme in 
+ *   - rewritten for the more generic power management scheme in
  *     linux-2.4.5-rmk1
  *
  * This software has been developed while working on the LART
  * computing board (http://www.lartmaker.nl/), which is
  * sponsored by the Mobile Multi-media Communications
- * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications 
+ * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
  * (http://www.ubicom.tudelft.nl/) projects.
  *
  * The authors can be reached at:
@@ -36,7 +36,7 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You 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
@@ -44,7 +44,7 @@
  *
  * Theory of operations
  * ====================
- * 
+ *
  * Clock scaling can be used to lower the power consumption of the CPU
  * core. This will give you a somewhat longer running time.
  *
  *   MDCNFG    0xA0000000    DRAM config
  *   MDCAS0    0xA0000004    Access waveform
  *   MDCAS1    0xA0000008    Access waveform
- *   MDCAS2    0xA000000C    Access waveform 
+ *   MDCAS2    0xA000000C    Access waveform
  *
  * Care must be taken to change the DRAM parameters the correct way,
  * because otherwise the DRAM becomes unusable and the kernel will
- * crash. 
+ * crash.
  *
  * The simple solution to avoid a kernel crash is to put the actual
  * clock change in ROM and jump to that code from the kernel. The main
@@ -75,7 +75,7 @@
  * as long as all re-configuration steps yield a valid DRAM
  * configuration. The advantages are clear: it will run on all SA-1100
  * platforms, and the code is very simple.
- * 
+ *
  * If you really want to understand what is going on in
  * sa1100_update_dram_timings(), you'll have to read sections 8.2,
  * 9.5.7.3, and 10.2 from the "Intel StrongARM SA-1100 Microprocessor
@@ -97,7 +97,7 @@
 typedef struct {
        int speed;
        u32 mdcnfg;
-       u32 mdcas0; 
+       u32 mdcas0;
        u32 mdcas1;
        u32 mdcas2;
 } sa1100_dram_regs_t;
@@ -147,7 +147,7 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
        /* No risk, no fun: run with interrupts on! */
        if (new_speed > current_speed) {
                /* We're going FASTER, so first relax the memory
-                * timings before changing the core frequency 
+                * timings before changing the core frequency
                 */
                
                /* Half the memory access clock */
index 3e4fb214eada2d541cf148468f8951de2be457b5..63b32b68b296969e73638e2e370bcc7322049ac7 100644 (file)
@@ -81,14 +81,14 @@ static struct sdram_params sdram_tbl[] __initdata = {
                .twr            = 9,
                .refresh        = 64000,
                .cas_latency    = 3,
-       }, {    /* Samsung K4S281632B-1H */
-               .name           = "K4S281632B-1H",
-               .rows           = 12,
-               .tck            = 10,
-               .trp            = 20,
-               .twr            = 10,
-               .refresh        = 64000,
-               .cas_latency    = 3,
+       }, {    /* Samsung K4S281632B-1H */
+               .name           = "K4S281632B-1H",
+               .rows           = 12,
+               .tck            = 10,
+               .trp            = 20,
+               .twr            = 10,
+               .refresh        = 64000,
+               .cas_latency    = 3,
        }, {    /* Samsung KM416S4030CT */
                .name           = "KM416S4030CT",
                .rows           = 13,
@@ -220,7 +220,7 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
 }
 
 /*
- * Ok, set the CPU frequency.  
+ * Ok, set the CPU frequency.
  */
 static int sa1110_target(struct cpufreq_policy *policy,
                         unsigned int target_freq,
index f990a3e858462d6324d85e469e50ea2d66604c1c..95f9c5a6d6d5dda9a237272af11bf633d340f4be 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 
 #undef DEBUG
@@ -113,10 +113,10 @@ int sa1100_request_dma (dma_device_t device, const char *device_id,
                }
        }
        if (!err) {
-              if (dma)
-                      dma->device = device;
-              else
-                      err = -ENOSR;
+               if (dma)
+                       dma->device = device;
+               else
+                       err = -ENOSR;
        }
        spin_unlock(&dma_list_lock);
        if (err)
index 3ca0ecf095e67c9153d845e2cdad49d37093532d..9cc47fddb3358de80fc50fe8f6146eabe5e86993 100644 (file)
@@ -32,14 +32,14 @@ typedef int __bitwise pm_request_t;
 #define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600() || machine_is_h3800())
 
 /* Physical memory regions corresponding to chip selects */
-#define H3600_EGPIO_PHYS     (SA1100_CS5_PHYS + 0x01000000)
-#define H3600_BANK_2_PHYS    SA1100_CS2_PHYS
-#define H3600_BANK_4_PHYS    SA1100_CS4_PHYS
+#define H3600_EGPIO_PHYS       (SA1100_CS5_PHYS + 0x01000000)
+#define H3600_BANK_2_PHYS      SA1100_CS2_PHYS
+#define H3600_BANK_4_PHYS      SA1100_CS4_PHYS
 
 /* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
-#define H3600_EGPIO_VIRT     0xf0000000
-#define H3600_BANK_2_VIRT    0xf1000000
-#define H3600_BANK_4_VIRT    0xf3800000
+#define H3600_EGPIO_VIRT       0xf0000000
+#define H3600_BANK_2_VIRT      0xf1000000
+#define H3600_BANK_4_VIRT      0xf3800000
 
 /*
    Machine-independent GPIO definitions
index b70846c096aa0f1755290fa1b5cdb2b4f837e5e4..60711822b1258dafee21d535b9255d2f583ea27c 100644 (file)
 # define __REG(x)      (*((volatile unsigned long *)io_p2v(x)))
 # define __PREG(x)     (io_v2p((unsigned long)&(x)))
 
+static inline unsigned long get_clock_tick_rate(void)
+{
+       return 3686400;
+}
 #else
 
 # define __REG(x)      io_p2v(x)
index 0c070a6149bcb4a845c8b35360d9eecefdff76c6..d8b43f3dcd2d92d6b6e72a59ed05f6d028b12622 100644 (file)
  * We don't actually have real ISA nor PCI buses, but there is so many 
  * drivers out there that might just work if we fake them...
  */
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-#define __io(a)                        __io(a)
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 1c127b68581d6e2ef2ec2be79792d0f4e63a1785..e9f8eed900f5171f0ecdda0d625cf7399159086b 100644 (file)
@@ -23,22 +23,11 @@ void sa1111_adjust_zones(int node, unsigned long *size, unsigned long *holes);
        sa1111_adjust_zones(node, size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_1M - 1)
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_1M)
 
 #endif
 #endif
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *             address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *             to an address that the kernel can use.
- *
- * On the SA1100, bus addresses are equivalent to physical addresses.
- */
-#define __virt_to_bus(x)        __virt_to_phys(x)
-#define __bus_to_virt(x)        __phys_to_virt(x)
-
 /*
  * Because of the wide memory address space between physical RAM banks on the
  * SA1100, it's much convenient to use Linux's SparseMEM support to implement
index eaa09e86ad16befdc834ba870435fc7917736f49..b3d684098fbf545c033e56793935cee7da3e2bf0 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __ARCH_SA1100_MTD_XIP_H__
 #define __ARCH_SA1100_MTD_XIP_H__
 
+#include <mach/hardware.h>
+
 #define xip_irqpending()       (ICIP & ICMR)
 
 /* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
index e45d3a1890bcee7faaf6d23f406aa055726e4c10..e1458bc1868ef8907b1ca8bb878d467c67764ecf 100644 (file)
@@ -122,12 +122,12 @@ static void __init pleb_map_io(void)
        sa1100_map_io();
 
        sa1100_register_uart(0, 3);
-        sa1100_register_uart(1, 1);
+       sa1100_register_uart(1, 1);
 
-        GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
-        GPDR |= GPIO_UART_TXD;
-        GPDR &= ~GPIO_UART_RXD;
-        PPAR |= PPAR_UPR;
+       GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
+       GPDR |= GPIO_UART_TXD;
+       GPDR &= ~GPIO_UART_RXD;
+       PPAR |= PPAR_UPR;
 
        /*
         * Fix expansion memory timing for network card
index 9ccdd09cf69f4d1276536331edf9473aee0a9f2b..ddd917d1083d79c4d04da6d2ced5248322672e3b 100644 (file)
@@ -33,7 +33,7 @@ static struct mtd_partition shannon_partitions[] = {
                .offset         = MTDPART_OFS_APPEND,
                .size           = 0xe0000
        },
-       { 
+       {
                .name           = "initrd",
                .offset         = MTDPART_OFS_APPEND,   
                .size           = MTDPART_SIZ_FULL
index 171441f967100ce76d11f766e995bb37f28e1140..80f31bad707cae69ac80246c44a887eb248b5f4f 100644 (file)
@@ -100,36 +100,36 @@ ENTRY(sa1100_cpu_suspend)
        ldr     r1, =MSC1
        ldr     r2, =MSC2
 
-        ldr     r3, [r0]
-        bic     r3, r3, #FMsk(MSC_RT)
-        bic     r3, r3, #FMsk(MSC_RT)<<16
+       ldr     r3, [r0]
+       bic     r3, r3, #FMsk(MSC_RT)
+       bic     r3, r3, #FMsk(MSC_RT)<<16
 
-        ldr     r4, [r1]
-        bic     r4, r4, #FMsk(MSC_RT)
-        bic     r4, r4, #FMsk(MSC_RT)<<16
+       ldr     r4, [r1]
+       bic     r4, r4, #FMsk(MSC_RT)
+       bic     r4, r4, #FMsk(MSC_RT)<<16
 
-        ldr     r5, [r2]
-        bic     r5, r5, #FMsk(MSC_RT)
-        bic     r5, r5, #FMsk(MSC_RT)<<16
+       ldr     r5, [r2]
+       bic     r5, r5, #FMsk(MSC_RT)
+       bic     r5, r5, #FMsk(MSC_RT)<<16
 
-        ldr     r6, =MDREFR
+       ldr     r6, =MDREFR
 
-        ldr     r7, [r6]
-        bic     r7, r7, #0x0000FF00
-        bic     r7, r7, #0x000000F0
-        orr     r8, r7, #MDREFR_SLFRSH
+       ldr     r7, [r6]
+bic    r7, r7, #0x0000FF00
+bic    r7, r7, #0x000000F0
+orr    r8, r7, #MDREFR_SLFRSH
 
-        ldr     r9, =MDCNFG
-        ldr     r10, [r9]
-        bic     r10, r10, #(MDCNFG_DE0+MDCNFG_DE1)
-        bic     r10, r10, #(MDCNFG_DE2+MDCNFG_DE3)
+       ldr     r9, =MDCNFG
+       ldr     r10, [r9]
+       bic     r10, r10, #(MDCNFG_DE0+MDCNFG_DE1)
+       bic     r10, r10, #(MDCNFG_DE2+MDCNFG_DE3)
 
-        bic     r11, r8, #MDREFR_SLFRSH
-        bic     r11, r11, #MDREFR_E1PIN
+       bic     r11, r8, #MDREFR_SLFRSH
+       bic     r11, r11, #MDREFR_E1PIN
 
-        ldr     r12, =PMCR
+       ldr     r12, =PMCR
 
-        mov     r13, #PMCR_SF
+       mov     r13, #PMCR_SF
 
        b       sa1110_sdram_controller_fix
 
@@ -188,10 +188,10 @@ ENTRY(sa1100_cpu_resume)
        mcr     p15, 0, r1, c8, c7, 0           @ flush I+D TLBs
        mcr     p15, 0, r1, c7, c7, 0           @ flush I&D cache
        mcr     p15, 0, r1, c9, c0, 0           @ invalidate RB
-       mcr     p15, 0, r1, c9, c0, 5           @ allow user space to use RB
+       mcr     p15, 0, r1, c9, c0, 5           @ allow user space to use RB
 
-       mcr     p15, 0, r4, c3, c0, 0           @ domain ID
-       mcr     p15, 0, r5, c2, c0, 0           @ translation table base addr
+       mcr     p15, 0, r4, c3, c0, 0           @ domain ID
+       mcr     p15, 0, r5, c2, c0, 0           @ translation table base addr
        mcr     p15, 0, r6, c13, c0, 0          @ PID
        b       resume_turn_on_mmu              @ cache align execution
 
@@ -209,7 +209,7 @@ sleep_save_sp:
 
        .text
 resume_after_mmu:
-       mcr     p15, 0, r1, c15, c1, 2          @ enable clock switching
+       mcr     p15, 0, r1, c15, c1, 2          @ enable clock switching
        ldmfd   sp!, {r4 - r12, pc}             @ return to caller
 
 
index 24c0a4bae850ec273854557d50891bfe6a2ee46b..8c5e727f3b751ffb0e87b176402ae75adb276cfc 100644 (file)
@@ -2,8 +2,8 @@
  * linux/arch/arm/mach-sa1100/time.c
  *
  * Copyright (C) 1998 Deborah Wallach.
- * Twiddles  (C) 1999  Hugo Fiennes <hugo@empeg.com>
- * 
+ * Twiddles  (C) 1999 Hugo Fiennes <hugo@empeg.com>
+ *
  * 2000/03/29 (C) Nicolas Pitre <nico@cam.org>
  *     Rewritten: big cleanup, much simpler, better HZ accuracy.
  *
index a9400d98445160e9f6b61f9d6efd852373cfe404..a23fd3d0163ac973c360f2875140602b7decd3c6 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm/leds.h>
 #include <asm/param.h>
 
+#include <mach/hardware.h>
+
 #include <asm/mach/map.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
index cb0ee2943c1acb13bbc44cbeefe6303a47e1e998..01bf76099ce5f65525d0ed99ad95227f1d17f94f 100644 (file)
@@ -28,8 +28,6 @@
 #define ROMCARD_SIZE           0x08000000
 #define ROMCARD_START          0x10000000
 
-#define PCIO_BASE              0xe0000000
-
 
 /* defines for the Framebuffer */
 #define FB_START               0x06000000
index 92475922c068fc7bdd20e8a79b2ed4feba4deecc..c5cee829fc87e59dd402e797f1242451b248c9a0 100644 (file)
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#include <mach/hardware.h>
+#define PCIO_BASE      0xe0000000
+#define IO_SPACE_LIMIT 0xffffffff
 
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses.  PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1.  ARM addresses are 0x80000000+
- * and are translated to the start of IO.
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-#define __io(a)                 ((void __iomem *)(PCIO_BASE + (a)))
-
-
-static inline unsigned int __ioaddr (unsigned int port)                        \
-{                                                                              \
-       if (__PORT_PCIO(port))                                                  \
-               return (unsigned int)(PCIO_BASE + (port));                      \
-       else                                                                    \
-               return (unsigned int)(IO_BASE + (port));                        \
-}
-
-#define __mem_pci(addr) (addr)
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)                                                            \
-       (*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)                                                               \
-       (*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)                                                            \
-       (*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)                                                               \
-       (*(volatile unsigned long *)(p))
+#define __io(a)                ((void __iomem *)(PCIO_BASE + (a)))
+#define __mem_pci(addr)        (addr)
 
 #endif
similarity index 79%
rename from arch/arm/mach-shark/include/mach/dma.h
rename to arch/arm/mach-shark/include/mach/isa-dma.h
index c0a29bd2a74fba1fcb26cf182bb68978fd33855c..864298ff39274d0a1294284ba606e111cefb4220 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/mach-shark/include/mach/dma.h
+ * arch/arm/mach-shark/include/mach/isa-dma.h
  *
  * by Alexander Schulz
  */
@@ -10,7 +10,6 @@
  * The rest is not DMAable. See dev /  .properties
  * in OpenFirmware.
  */
-#define MAX_DMA_ADDRESS                0xC0400000
 #define MAX_DMA_CHANNELS       8
 #define DMA_ISA_CASCADE         4
 
index b7874ad9f9f6dd66357e4292710ec8014dcd77af..c5ab038925d63a62f9dd1704f840387631d50636 100644 (file)
@@ -33,12 +33,10 @@ static inline void __arch_adjust_zones(int node, unsigned long *zone_size, unsig
        __arch_adjust_zones(node, size, holes)
 
 #define ISA_DMA_THRESHOLD      (PHYS_OFFSET + SZ_4M - 1)
+#define MAX_DMA_ADDRESS                (PAGE_OFFSET + SZ_4M)
 
 #endif
 
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
 /*
  * Cache flushing area
  */
index 95096afd527154665468168c5cf3928375cff085..c781f30c8368a0d9dc4f33f271f91121f08c29fc 100644 (file)
@@ -3,12 +3,14 @@ menu "Versatile platform type"
 
 config ARCH_VERSATILE_PB
        bool "Support Versatile/PB platform"
+       select CPU_ARM926T
        default y
        help
          Include support for the ARM(R) Versatile/PB platform.
 
 config MACH_VERSATILE_AB
        bool "Support Versatile/AB platform"
+       select CPU_ARM926T
        help
          Include support for the ARM(R) Versatile/AP platform.
 
index 58937f1fb38ce7b4d805f86771d1ccdac9383457..c50a44ea7ee6d4c3fa947f53062373092d417455 100644 (file)
@@ -10,6 +10,7 @@
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/list.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/mutex.h>
 
+#include <asm/clkdev.h>
 #include <asm/hardware/icst307.h>
 
 #include "clock.h"
 
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-       mutex_unlock(&clocks_mutex);
-
-       return clk;
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-       module_put(clk->owner);
-}
-EXPORT_SYMBOL(clk_put);
-
 int clk_enable(struct clk *clk)
 {
        return 0;
@@ -66,7 +42,9 @@ EXPORT_SYMBOL(clk_get_rate);
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       return rate;
+       struct icst307_vco vco;
+       vco = icst307_khz_to_vco(clk->params, rate / 1000);
+       return icst307_khz(clk->params, vco) * 1000;
 }
 EXPORT_SYMBOL(clk_round_rate);
 
@@ -79,57 +57,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 
                vco = icst307_khz_to_vco(clk->params, rate / 1000);
                clk->rate = icst307_khz(clk->params, vco) * 1000;
-
-               printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n",
-                       clk->name, vco.s, vco.r, vco.v);
-
                clk->setvco(clk, vco);
                ret = 0;
        }
        return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
-
-/*
- * These are fixed clocks.
- */
-static struct clk kmi_clk = {
-       .name   = "KMIREFCLK",
-       .rate   = 24000000,
-};
-
-static struct clk uart_clk = {
-       .name   = "UARTCLK",
-       .rate   = 24000000,
-};
-
-static struct clk mmci_clk = {
-       .name   = "MCLK",
-       .rate   = 24000000,
-};
-
-int clk_register(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(clk_register);
-
-void clk_unregister(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_del(&clk->node);
-       mutex_unlock(&clocks_mutex);
-}
-EXPORT_SYMBOL(clk_unregister);
-
-static int __init clk_init(void)
-{
-       clk_register(&kmi_clk);
-       clk_register(&uart_clk);
-       clk_register(&mmci_clk);
-       return 0;
-}
-arch_initcall(clk_init);
index 8b0b61dd17e43389b587c6e118e72812ebc16b30..03468fdc3e58f7b1fc4a8071d5cd1234678ebbb8 100644 (file)
@@ -12,14 +12,9 @@ struct module;
 struct icst307_params;
 
 struct clk {
-       struct list_head        node;
        unsigned long           rate;
-       struct module           *owner;
-       const char              *name;
        const struct icst307_params *params;
+       u32                     oscoff;
        void                    *data;
        void                    (*setvco)(struct clk *, struct icst307_vco vco);
 };
-
-int clk_register(struct clk *clk);
-void clk_unregister(struct clk *clk);
index 565e0ba0d67e082b9481f6008d065302a5b0042f..df25aa138509c95aec6dfcb391f8409de5b182a8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/cnt32_to_63.h>
 #include <linux/io.h>
 
+#include <asm/clkdev.h>
 #include <asm/system.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
@@ -373,22 +374,60 @@ static const struct icst307_params versatile_oscvco_params = {
 
 static void versatile_oscvco_set(struct clk *clk, struct icst307_vco vco)
 {
-       void __iomem *sys_lock = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LOCK_OFFSET;
-       void __iomem *sys_osc = __io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_OSCCLCD_OFFSET;
+       void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
+       void __iomem *sys_lock = sys + VERSATILE_SYS_LOCK_OFFSET;
        u32 val;
 
-       val = readl(sys_osc) & ~0x7ffff;
+       val = readl(sys + clk->oscoff) & ~0x7ffff;
        val |= vco.v | (vco.r << 9) | (vco.s << 16);
 
        writel(0xa05f, sys_lock);
-       writel(val, sys_osc);
+       writel(val, sys + clk->oscoff);
        writel(0, sys_lock);
 }
 
-static struct clk versatile_clcd_clk = {
-       .name   = "CLCDCLK",
+static struct clk osc4_clk = {
        .params = &versatile_oscvco_params,
-       .setvco = versatile_oscvco_set,
+       .oscoff = VERSATILE_SYS_OSCCLCD_OFFSET,
+       .setvco = versatile_oscvco_set,
+};
+
+/*
+ * These are fixed clocks.
+ */
+static struct clk ref24_clk = {
+       .rate   = 24000000,
+};
+
+static struct clk_lookup lookups[] __initdata = {
+       {       /* UART0 */
+               .dev_id         = "dev:f1",
+               .clk            = &ref24_clk,
+       }, {    /* UART1 */
+               .dev_id         = "dev:f2",
+               .clk            = &ref24_clk,
+       }, {    /* UART2 */
+               .dev_id         = "dev:f3",
+               .clk            = &ref24_clk,
+       }, {    /* UART3 */
+               .dev_id         = "fpga:09",
+               .clk            = &ref24_clk,
+       }, {    /* KMI0 */
+               .dev_id         = "fpga:06",
+               .clk            = &ref24_clk,
+       }, {    /* KMI1 */
+               .dev_id         = "fpga:07",
+               .clk            = &ref24_clk,
+       }, {    /* MMC0 */
+               .dev_id         = "fpga:05",
+               .clk            = &ref24_clk,
+       }, {    /* MMC1 */
+               .dev_id         = "fpga:0b",
+               .clk            = &ref24_clk,
+       }, {    /* CLCD */
+               .dev_id         = "dev:20",
+               .clk            = &osc4_clk,
+       }
 };
 
 /*
@@ -786,7 +825,8 @@ void __init versatile_init(void)
 {
        int i;
 
-       clk_register(&versatile_clcd_clk);
+       for (i = 0; i < ARRAY_SIZE(lookups); i++)
+               clkdev_add(&lookups[i]);
 
        platform_device_register(&versatile_flash_device);
        platform_device_register(&versatile_i2c_device);
diff --git a/arch/arm/mach-versatile/include/mach/clkdev.h b/arch/arm/mach-versatile/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-versatile/include/mach/dma.h b/arch/arm/mach-versatile/include/mach/dma.h
deleted file mode 100644 (file)
index 0aabf12..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/dma.h
- *
- *  Copyright (C) 2003 ARM Limited.
- *  Copyright (C) 1997,1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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
- */
index c0b9dd1d025759a4d893fefc9ac73c065aa57523..f067c14c7182982850e2179adc94b4298185d866 100644 (file)
 
 #define IO_SPACE_LIMIT 0xffffffff
 
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-#define __io(a)        __io(a)
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 #endif
index 216a1312e62ed890034a913018f64d2b26c93197..9bfdb30e1f3f3e91694464857b4e5c561752f3f1 100644 (file)
 #define IRQ_VICSOURCE31                (IRQ_VIC_START + INT_VICSOURCE31)
 #define IRQ_VIC_END            (IRQ_VIC_START + 31)
 
-#define IRQMASK_WDOGINT                INTMASK_WDOGINT
-#define IRQMASK_SOFTINT                INTMASK_SOFTINT
-#define IRQMASK_COMMRx                 INTMASK_COMMRx
-#define IRQMASK_COMMTx                 INTMASK_COMMTx
-#define IRQMASK_TIMERINT0_1    INTMASK_TIMERINT0_1
-#define IRQMASK_TIMERINT2_3    INTMASK_TIMERINT2_3
-#define IRQMASK_GPIOINT0       INTMASK_GPIOINT0
-#define IRQMASK_GPIOINT1       INTMASK_GPIOINT1
-#define IRQMASK_GPIOINT2       INTMASK_GPIOINT2
-#define IRQMASK_GPIOINT3       INTMASK_GPIOINT3
-#define IRQMASK_RTCINT                 INTMASK_RTCINT
-#define IRQMASK_SSPINT                 INTMASK_SSPINT
-#define IRQMASK_UARTINT0       INTMASK_UARTINT0
-#define IRQMASK_UARTINT1       INTMASK_UARTINT1
-#define IRQMASK_UARTINT2       INTMASK_UARTINT2
-#define IRQMASK_SCIINT                 INTMASK_SCIINT
-#define IRQMASK_CLCDINT                INTMASK_CLCDINT
-#define IRQMASK_DMAINT                 INTMASK_DMAINT
-#define IRQMASK_PWRFAILINT     INTMASK_PWRFAILINT
-#define IRQMASK_MBXINT                 INTMASK_MBXINT
-#define IRQMASK_GNDINT                 INTMASK_GNDINT
-#define IRQMASK_VICSOURCE21    INTMASK_VICSOURCE21
-#define IRQMASK_VICSOURCE22    INTMASK_VICSOURCE22
-#define IRQMASK_VICSOURCE23    INTMASK_VICSOURCE23
-#define IRQMASK_VICSOURCE24    INTMASK_VICSOURCE24
-#define IRQMASK_VICSOURCE25    INTMASK_VICSOURCE25
-#define IRQMASK_VICSOURCE26    INTMASK_VICSOURCE26
-#define IRQMASK_VICSOURCE27    INTMASK_VICSOURCE27
-#define IRQMASK_VICSOURCE28    INTMASK_VICSOURCE28
-#define IRQMASK_VICSOURCE29    INTMASK_VICSOURCE29
-#define IRQMASK_VICSOURCE30    INTMASK_VICSOURCE30
-#define IRQMASK_VICSOURCE31    INTMASK_VICSOURCE31
-
 /* 
  *  FIQ interrupts definitions are the same as the INT definitions.
  */
 #define FIQ_VICSOURCE31                INT_VICSOURCE31
 
 
-#define FIQMASK_WDOGINT                INTMASK_WDOGINT
-#define FIQMASK_SOFTINT                INTMASK_SOFTINT
-#define FIQMASK_COMMRx                 INTMASK_COMMRx
-#define FIQMASK_COMMTx                 INTMASK_COMMTx
-#define FIQMASK_TIMERINT0_1    INTMASK_TIMERINT0_1
-#define FIQMASK_TIMERINT2_3    INTMASK_TIMERINT2_3
-#define FIQMASK_GPIOINT0       INTMASK_GPIOINT0
-#define FIQMASK_GPIOINT1       INTMASK_GPIOINT1
-#define FIQMASK_GPIOINT2       INTMASK_GPIOINT2
-#define FIQMASK_GPIOINT3       INTMASK_GPIOINT3
-#define FIQMASK_RTCINT                 INTMASK_RTCINT
-#define FIQMASK_SSPINT                 INTMASK_SSPINT
-#define FIQMASK_UARTINT0       INTMASK_UARTINT0
-#define FIQMASK_UARTINT1       INTMASK_UARTINT1
-#define FIQMASK_UARTINT2       INTMASK_UARTINT2
-#define FIQMASK_SCIINT                 INTMASK_SCIINT
-#define FIQMASK_CLCDINT                INTMASK_CLCDINT
-#define FIQMASK_DMAINT                 INTMASK_DMAINT
-#define FIQMASK_PWRFAILINT     INTMASK_PWRFAILINT
-#define FIQMASK_MBXINT                 INTMASK_MBXINT
-#define FIQMASK_GNDINT                 INTMASK_GNDINT
-#define FIQMASK_VICSOURCE21    INTMASK_VICSOURCE21
-#define FIQMASK_VICSOURCE22    INTMASK_VICSOURCE22
-#define FIQMASK_VICSOURCE23    INTMASK_VICSOURCE23
-#define FIQMASK_VICSOURCE24    INTMASK_VICSOURCE24
-#define FIQMASK_VICSOURCE25    INTMASK_VICSOURCE25
-#define FIQMASK_VICSOURCE26    INTMASK_VICSOURCE26
-#define FIQMASK_VICSOURCE27    INTMASK_VICSOURCE27
-#define FIQMASK_VICSOURCE28    INTMASK_VICSOURCE28
-#define FIQMASK_VICSOURCE29    INTMASK_VICSOURCE29
-#define FIQMASK_VICSOURCE30    INTMASK_VICSOURCE30
-#define FIQMASK_VICSOURCE31    INTMASK_VICSOURCE31
-
 /*
  * Secondary interrupt controller
  */
 #define IRQ_SIC_PCI3           (IRQ_SIC_START + SIC_INT_PCI3)
 #define IRQ_SIC_END            63
 
-#define SIC_IRQMASK_MMCI0B     SIC_INTMASK_MMCI0B
-#define SIC_IRQMASK_MMCI1B     SIC_INTMASK_MMCI1B
-#define SIC_IRQMASK_KMI0       SIC_INTMASK_KMI0
-#define SIC_IRQMASK_KMI1       SIC_INTMASK_KMI1
-#define SIC_IRQMASK_SCI3       SIC_INTMASK_SCI3
-#define SIC_IRQMASK_UART3      SIC_INTMASK_UART3
-#define SIC_IRQMASK_CLCD       SIC_INTMASK_CLCD
-#define SIC_IRQMASK_TOUCH      SIC_INTMASK_TOUCH
-#define SIC_IRQMASK_KEYPAD     SIC_INTMASK_KEYPAD
-#define SIC_IRQMASK_DoC                SIC_INTMASK_DoC
-#define SIC_IRQMASK_MMCI0A     SIC_INTMASK_MMCI0A
-#define SIC_IRQMASK_MMCI1A     SIC_INTMASK_MMCI1A
-#define SIC_IRQMASK_AACI       SIC_INTMASK_AACI
-#define SIC_IRQMASK_ETH                SIC_INTMASK_ETH
-#define SIC_IRQMASK_USB                SIC_INTMASK_USB
-#define SIC_IRQMASK_PCI0       SIC_INTMASK_PCI0
-#define SIC_IRQMASK_PCI1       SIC_INTMASK_PCI1
-#define SIC_IRQMASK_PCI2       SIC_INTMASK_PCI2
-#define SIC_IRQMASK_PCI3       SIC_INTMASK_PCI3
-
 #define NR_IRQS                        64
index b6315c0602ac5f6d0860ff5c6b1f4c86adcb189a..79aeab86b903b2df970fb2ecc96776319773ba2c 100644 (file)
  */
 #define PHYS_OFFSET    UL(0x00000000)
 
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus(x)       ((x) - PAGE_OFFSET)
-#define __bus_to_virt(x)       ((x) + PAGE_OFFSET)
-
 #endif
index f91ba930ca8a45221b8cb60074ec9bd186731eab..83207395191a70cd60e8e168987496d8187c1c36 100644 (file)
 #define INT_VICSOURCE30                 30     /* PCI 3 */
 #define INT_VICSOURCE31                 31     /* SIC source */
 
-/* 
- *  Interrupt bit positions
- * 
- */
-#define INTMASK_WDOGINT                 (1 << INT_WDOGINT)
-#define INTMASK_SOFTINT                 (1 << INT_SOFTINT)
-#define INTMASK_COMMRx                  (1 << INT_COMMRx)
-#define INTMASK_COMMTx                  (1 << INT_COMMTx)
-#define INTMASK_TIMERINT0_1             (1 << INT_TIMERINT0_1)
-#define INTMASK_TIMERINT2_3             (1 << INT_TIMERINT2_3)
-#define INTMASK_GPIOINT0                (1 << INT_GPIOINT0)
-#define INTMASK_GPIOINT1                (1 << INT_GPIOINT1)
-#define INTMASK_GPIOINT2                (1 << INT_GPIOINT2)
-#define INTMASK_GPIOINT3                (1 << INT_GPIOINT3)
-#define INTMASK_RTCINT                  (1 << INT_RTCINT)
-#define INTMASK_SSPINT                  (1 << INT_SSPINT)
-#define INTMASK_UARTINT0                (1 << INT_UARTINT0)
-#define INTMASK_UARTINT1                (1 << INT_UARTINT1)
-#define INTMASK_UARTINT2                (1 << INT_UARTINT2)
-#define INTMASK_SCIINT                  (1 << INT_SCIINT)
-#define INTMASK_CLCDINT                 (1 << INT_CLCDINT)
-#define INTMASK_DMAINT                  (1 << INT_DMAINT)
-#define INTMASK_PWRFAILINT              (1 << INT_PWRFAILINT)
-#define INTMASK_MBXINT                  (1 << INT_MBXINT)
-#define INTMASK_GNDINT                  (1 << INT_GNDINT)
-#define INTMASK_VICSOURCE21             (1 << INT_VICSOURCE21)
-#define INTMASK_VICSOURCE22             (1 << INT_VICSOURCE22)
-#define INTMASK_VICSOURCE23             (1 << INT_VICSOURCE23)
-#define INTMASK_VICSOURCE24             (1 << INT_VICSOURCE24)
-#define INTMASK_VICSOURCE25             (1 << INT_VICSOURCE25)
-#define INTMASK_VICSOURCE26             (1 << INT_VICSOURCE26)
-#define INTMASK_VICSOURCE27             (1 << INT_VICSOURCE27)
-#define INTMASK_VICSOURCE28             (1 << INT_VICSOURCE28)
-#define INTMASK_VICSOURCE29             (1 << INT_VICSOURCE29)
-#define INTMASK_VICSOURCE30             (1 << INT_VICSOURCE30)
-#define INTMASK_VICSOURCE31             (1 << INT_VICSOURCE31)
-
-
 #define VERSATILE_SC_VALID_INT               0x003FFFFF
 
 #define MAXIRQNUM                       31
 #define SIC_INT_PCI3                    30
 
 
-#define SIC_INTMASK_MMCI0B              (1 << SIC_INT_MMCI0B)
-#define SIC_INTMASK_MMCI1B              (1 << SIC_INT_MMCI1B)
-#define SIC_INTMASK_KMI0                (1 << SIC_INT_KMI0)
-#define SIC_INTMASK_KMI1                (1 << SIC_INT_KMI1)
-#define SIC_INTMASK_SCI3                (1 << SIC_INT_SCI3)
-#define SIC_INTMASK_UART3               (1 << SIC_INT_UART3)
-#define SIC_INTMASK_CLCD                (1 << SIC_INT_CLCD)
-#define SIC_INTMASK_TOUCH               (1 << SIC_INT_TOUCH)
-#define SIC_INTMASK_KEYPAD              (1 << SIC_INT_KEYPAD)
-#define SIC_INTMASK_DoC                 (1 << SIC_INT_DoC)
-#define SIC_INTMASK_MMCI0A              (1 << SIC_INT_MMCI0A)
-#define SIC_INTMASK_MMCI1A              (1 << SIC_INT_MMCI1A)
-#define SIC_INTMASK_AACI                (1 << SIC_INT_AACI)
-#define SIC_INTMASK_ETH                 (1 << SIC_INT_ETH)
-#define SIC_INTMASK_USB                 (1 << SIC_INT_USB)
-#define SIC_INTMASK_PCI0                (1 << SIC_INT_PCI0)
-#define SIC_INTMASK_PCI1                (1 << SIC_INT_PCI1)
-#define SIC_INTMASK_PCI2                (1 << SIC_INT_PCI2)
-#define SIC_INTMASK_PCI3                (1 << SIC_INT_PCI3)
-
 /* 
  *  Clean base - dummy
  * 
diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig
new file mode 100644 (file)
index 0000000..8e4178f
--- /dev/null
@@ -0,0 +1,19 @@
+if ARCH_W90X900
+
+config CPU_W90P910
+       bool
+       help
+         Support for W90P910 of Nuvoton W90X900 CPUs.
+
+menu "W90P910 Machines"
+
+config MACH_W90P910EVB
+       bool "Nuvoton W90P910 Evaluation Board"
+       default y
+       select CPU_W90P910
+       help
+          Say Y here if you are using the Nuvoton W90P910EVB
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile
new file mode 100644 (file)
index 0000000..0c0c1d6
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y                          := irq.o time.o
+
+# W90X900 CPU support files
+
+obj-$(CONFIG_CPU_W90P910)      += w90p910.o
+
+# machine support
+
+obj-$(CONFIG_MACH_W90P910EVB)  += mach-w90p910evb.o
diff --git a/arch/arm/mach-w90x900/Makefile.boot b/arch/arm/mach-w90x900/Makefile.boot
new file mode 100644 (file)
index 0000000..a057b54
--- /dev/null
@@ -0,0 +1,3 @@
+zreladdr-y     := 0x00008000
+params_phys-y  := 0x00000100
+
diff --git a/arch/arm/mach-w90x900/cpu.h b/arch/arm/mach-w90x900/cpu.h
new file mode 100644 (file)
index 0000000..40ff408
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * arch/arm/mach-w90x900/cpu.h
+ *
+ * Based on linux/include/asm-arm/plat-s3c24xx/cpu.h by Ben Dooks
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Header file for W90X900 CPU support
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define IODESC_ENT(y)                                  \
+{                                                      \
+       .virtual = (unsigned long)W90X900_VA_##y,       \
+       .pfn     = __phys_to_pfn(W90X900_PA_##y),       \
+       .length  = W90X900_SZ_##y,                      \
+       .type    = MT_DEVICE,                           \
+}
+
+/*Cpu identifier register*/
+
+#define W90X900PDID    W90X900_VA_GCR
+#define W90P910_CPUID  0x02900910
+#define W90P920_CPUID  0x02900920
+#define W90P950_CPUID  0x02900950
+#define W90N960_CPUID  0x02900960
+
+struct w90x900_uartcfg;
+struct map_desc;
+struct sys_timer;
+
+/* core initialisation functions */
+
+extern void w90x900_init_irq(void);
+extern void w90p910_init_io(struct map_desc *mach_desc, int size);
+extern void w90p910_init_uarts(struct w90x900_uartcfg *cfg, int no);
+extern void w90p910_init_clocks(int xtal);
+extern void w90p910_map_io(struct map_desc *mach_desc, int size);
+extern struct sys_timer w90x900_timer;
+
+#define W90X900_RES(name)                              \
+struct resource w90x900_##name##_resource[] = {                \
+       [0] = {                                         \
+               .start = name##_PA,                     \
+               .end   = name##_PA + 0x0ff,             \
+               .flags = IORESOURCE_MEM,                \
+       },                                              \
+       [1] = {                                         \
+               .start = IRQ_##name,                    \
+               .end   = IRQ_##name,                    \
+               .flags = IORESOURCE_IRQ,                \
+       }                                               \
+}
+
+#define W90X900_DEVICE(devname, regname, devid, platdevname)           \
+struct platform_device w90x900_##devname = {                           \
+       .name           = platdevname,                                  \
+       .id             = devid,                                        \
+       .num_resources  = ARRAY_SIZE(w90x900_##regname##_resource),     \
+       .resource       = w90x900_##regname##_resource,                 \
+}
+
+#define W90X900_UARTCFG(port, flag, uc, ulc, ufc)      \
+{                                                      \
+               .hwport = port,                         \
+               .flags  = flag,                         \
+               .ucon   = uc,                           \
+               .ulcon  = ulc,                          \
+               .ufcon  = ufc,                          \
+}
diff --git a/arch/arm/mach-w90x900/include/mach/entry-macro.S b/arch/arm/mach-w90x900/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..d39aca5
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for W90P910-based platforms
+ *
+ * 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 <mach/hardware.h>
+#include <mach/regs-irq.h>
+
+       .macro  get_irqnr_preamble, base, tmp
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+               mov     \base, #AIC_BA
+
+               ldr     \irqnr, [ \base, #AIC_IPER]
+               ldr     \irqnr, [ \base, #AIC_ISNR]
+               cmp     \irqnr, #0
+
+       .endm
+
+       /* currently don't need an disable_fiq macro */
+
+       .macro  disable_fiq
+       .endm
diff --git a/arch/arm/mach-w90x900/include/mach/hardware.h b/arch/arm/mach-w90x900/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..fe3c626
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/hardware.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/hardware.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#include <mach/map.h>
+
+#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-w90x900/include/mach/io.h b/arch/arm/mach-w90x900/include/mach/io.h
new file mode 100644 (file)
index 0000000..d96ab99
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/io.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/io.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.
+ *
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * 1:1 mapping for ioremapped regions.
+ */
+
+#define __mem_pci(a)   (a)
+#define __io(a)                __typesafe_io(a)
+
+#endif
diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..1c583f9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/irqs.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/irqs.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H
+
+/*
+ * we keep the first set of CPU IRQs out of the range of
+ * the ISA space, so that the PC104 has them to itself
+ * and we don't end up having to do horrible things to the
+ * standard ISA drivers....
+ *
+ */
+
+#define W90X900_IRQ(x) (x)
+
+/* Main cpu interrupts */
+
+#define IRQ_WDT                W90X900_IRQ(1)
+#define IRQ_UART0      W90X900_IRQ(7)
+#define IRQ_UART1      W90X900_IRQ(8)
+#define IRQ_UART2      W90X900_IRQ(9)
+#define IRQ_UART3      W90X900_IRQ(10)
+#define IRQ_UART4      W90X900_IRQ(11)
+#define IRQ_TIMER0     W90X900_IRQ(12)
+#define IRQ_TIMER1     W90X900_IRQ(13)
+#define IRQ_T_INT_GROUP        W90X900_IRQ(14)
+#define IRQ_ADC                W90X900_IRQ(31)
+#define NR_IRQS                (IRQ_ADC+1)
+
+#endif /* __ASM_ARCH_IRQ_H */
diff --git a/arch/arm/mach-w90x900/include/mach/map.h b/arch/arm/mach-w90x900/include/mach/map.h
new file mode 100644 (file)
index 0000000..79320eb
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/map.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/map.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MAP_H
+#define __ASM_ARCH_MAP_H
+
+#ifndef __ASSEMBLY__
+#define W90X900_ADDR(x)                ((void __iomem *)(0xF0000000 + (x)))
+#else
+#define W90X900_ADDR(x)                (0xF0000000 + (x))
+#endif
+
+#define AHB_IO_BASE            0xB0000000
+#define APB_IO_BASE            0xB8000000
+#define CLOCKPW_BASE           (APB_IO_BASE+0x200)
+#define AIC_IO_BASE            (APB_IO_BASE+0x2000)
+#define TIMER_IO_BASE          (APB_IO_BASE+0x1000)
+
+/*
+ * interrupt controller is the first thing we put in, to make
+ * the assembly code for the irq detection easier
+ */
+
+#define W90X900_VA_IRQ         W90X900_ADDR(0x00000000)
+#define W90X900_PA_IRQ         (0xB8002000)
+#define W90X900_SZ_IRQ         SZ_4K
+
+#define W90X900_VA_GCR         W90X900_ADDR(0x08002000)
+#define W90X900_PA_GCR         (0xB0000000)
+#define W90X900_SZ_GCR         SZ_4K
+
+/* Clock and Power management */
+
+#define W90X900_VA_CLKPWR      (W90X900_VA_GCR+0x200)
+#define W90X900_PA_CLKPWR      (0xB0000200)
+#define W90X900_SZ_CLKPWR      SZ_4K
+
+/* EBI management */
+
+#define W90X900_VA_EBI         W90X900_ADDR(0x00001000)
+#define W90X900_PA_EBI         (0xB0001000)
+#define W90X900_SZ_EBI         SZ_4K
+
+/* UARTs */
+
+#define W90X900_VA_UART                W90X900_ADDR(0x08000000)
+#define W90X900_PA_UART                (0xB8000000)
+#define W90X900_SZ_UART                SZ_4K
+
+/* Timers */
+
+#define W90X900_VA_TIMER       W90X900_ADDR(0x08001000)
+#define W90X900_PA_TIMER       (0xB8001000)
+#define W90X900_SZ_TIMER       SZ_4K
+
+/* GPIO ports */
+
+#define W90X900_VA_GPIO                W90X900_ADDR(0x08003000)
+#define W90X900_PA_GPIO                (0xB8003000)
+#define W90X900_SZ_GPIO                SZ_4K
+
+#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-w90x900/include/mach/memory.h b/arch/arm/mach-w90x900/include/mach/memory.h
new file mode 100644 (file)
index 0000000..971b807
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/memory.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/memory.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET    UL(0x00000000)
+
+#endif
diff --git a/arch/arm/mach-w90x900/include/mach/regs-irq.h b/arch/arm/mach-w90x900/include/mach/regs-irq.h
new file mode 100644 (file)
index 0000000..8a3185f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-irq.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/regs-irq.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.
+ *
+ */
+
+#ifndef ___ASM_ARCH_REGS_IRQ_H
+#define ___ASM_ARCH_REGS_IRQ_H
+
+/* Advance Interrupt Controller (AIC) Registers */
+
+#define AIC_BA                 W90X900_VA_IRQ
+
+#define REG_AIC_IRQSC          (AIC_BA+0x80)
+#define REG_AIC_GEN            (AIC_BA+0x84)
+#define REG_AIC_GASR           (AIC_BA+0x88)
+#define REG_AIC_GSCR           (AIC_BA+0x8C)
+#define REG_AIC_IRSR           (AIC_BA+0x100)
+#define REG_AIC_IASR           (AIC_BA+0x104)
+#define REG_AIC_ISR            (AIC_BA+0x108)
+#define REG_AIC_IPER           (AIC_BA+0x10C)
+#define REG_AIC_ISNR           (AIC_BA+0x110)
+#define REG_AIC_IMR            (AIC_BA+0x114)
+#define REG_AIC_OISR           (AIC_BA+0x118)
+#define REG_AIC_MECR           (AIC_BA+0x120)
+#define REG_AIC_MDCR           (AIC_BA+0x124)
+#define REG_AIC_SSCR           (AIC_BA+0x128)
+#define REG_AIC_SCCR           (AIC_BA+0x12C)
+#define REG_AIC_EOSCR          (AIC_BA+0x130)
+#define AIC_IPER               (0x10C)
+#define AIC_ISNR               (0x110)
+
+/*16-18 bits of REG_AIC_GEN define irq(2-4) group*/
+
+#define TIMER2_IRQ             (1 << 16)
+#define TIMER3_IRQ             (1 << 17)
+#define TIMER4_IRQ             (1 << 18)
+#define TIME_GROUP_IRQ         (TIMER2_IRQ|TIMER3_IRQ|TIMER4_IRQ)
+
+#endif /* ___ASM_ARCH_REGS_IRQ_H */
diff --git a/arch/arm/mach-w90x900/include/mach/regs-serial.h b/arch/arm/mach-w90x900/include/mach/regs-serial.h
new file mode 100644 (file)
index 0000000..f08fa0d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-serial.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/regs-serial.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.
+ *
+ */
+
+#ifndef __ASM_ARM_REGS_SERIAL_H
+#define __ASM_ARM_REGS_SERIAL_H
+
+#define UART0_BA       W90X900_VA_UART
+#define UART1_BA       (W90X900_VA_UART+0x100)
+#define UART2_BA       (W90X900_VA_UART+0x200)
+#define UART3_BA       (W90X900_VA_UART+0x300)
+#define UART4_BA       (W90X900_VA_UART+0x400)
+
+#define UART0_PA       W90X900_PA_UART
+#define UART1_PA       (W90X900_PA_UART+0x100)
+#define UART2_PA       (W90X900_PA_UART+0x200)
+#define UART3_PA       (W90X900_PA_UART+0x300)
+#define UART4_PA       (W90X900_PA_UART+0x400)
+
+#ifndef __ASSEMBLY__
+
+struct w90x900_uart_clksrc {
+       const char      *name;
+       unsigned int    divisor;
+       unsigned int    min_baud;
+       unsigned int    max_baud;
+};
+
+struct w90x900_uartcfg {
+       unsigned char   hwport;
+       unsigned char   unused;
+       unsigned short  flags;
+       unsigned long   uart_flags;
+
+       unsigned long   ucon;
+       unsigned long   ulcon;
+       unsigned long   ufcon;
+
+       struct w90x900_uart_clksrc *clocks;
+       unsigned int    clocks_size;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ARM_REGS_SERIAL_H */
+
diff --git a/arch/arm/mach-w90x900/include/mach/regs-timer.h b/arch/arm/mach-w90x900/include/mach/regs-timer.h
new file mode 100644 (file)
index 0000000..8f39062
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/regs-timer.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/regs-timer.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_REGS_TIMER_H
+#define __ASM_ARCH_REGS_TIMER_H
+
+/* Timer Registers */
+
+#define TMR_BA                 W90X900_VA_TIMER
+#define REG_TCSR0              (TMR_BA+0x00)
+#define REG_TCSR1              (TMR_BA+0x04)
+#define REG_TICR0              (TMR_BA+0x08)
+#define REG_TICR1              (TMR_BA+0x0C)
+#define REG_TDR0               (TMR_BA+0x10)
+#define REG_TDR1               (TMR_BA+0x14)
+#define REG_TISR               (TMR_BA+0x18)
+#define REG_WTCR               (TMR_BA+0x1C)
+#define REG_TCSR2              (TMR_BA+0x20)
+#define REG_TCSR3              (TMR_BA+0x24)
+#define REG_TICR2              (TMR_BA+0x28)
+#define REG_TICR3              (TMR_BA+0x2C)
+#define REG_TDR2               (TMR_BA+0x30)
+#define REG_TDR3               (TMR_BA+0x34)
+#define REG_TCSR4              (TMR_BA+0x40)
+#define REG_TICR4              (TMR_BA+0x48)
+#define REG_TDR4               (TMR_BA+0x50)
+
+#endif /*  __ASM_ARCH_REGS_TIMER_H */
diff --git a/arch/arm/mach-w90x900/include/mach/system.h b/arch/arm/mach-w90x900/include/mach/system.h
new file mode 100644 (file)
index 0000000..93753f9
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/system.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/system.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.
+ *
+ */
+
+#include <asm/proc-fns.h>
+
+static void arch_idle(void)
+{
+}
+
+static void arch_reset(char mode)
+{
+       cpu_reset(0);
+}
+
diff --git a/arch/arm/mach-w90x900/include/mach/timex.h b/arch/arm/mach-w90x900/include/mach/timex.h
new file mode 100644 (file)
index 0000000..164dce0
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/timex.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/timex.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/* CLOCK_TICK_RATE Now, I don't use it. */
+
+#define CLOCK_TICK_RATE 15000000
+
+#endif /* __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-w90x900/include/mach/uncompress.h b/arch/arm/mach-w90x900/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..050d9fe
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/uncompress.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/uncompress.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+/* Defines for UART registers */
+
+#include <mach/regs-serial.h>
+#include <mach/map.h>
+
+#define arch_decomp_wdog()
+
+static void putc(int ch)
+{
+}
+
+static inline void flush(void)
+{
+}
+
+static void arch_decomp_setup(void)
+{
+}
+
+#endif/* __ASM_W90X900_UNCOMPRESS_H */
diff --git a/arch/arm/mach-w90x900/include/mach/vmalloc.h b/arch/arm/mach-w90x900/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..2f9dfb9
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/arm/mach-w90x900/include/mach/vmalloc.h
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/vmalloc.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.
+ *
+ */
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END      (0xE0000000)
+
+#endif /* __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/mach-w90x900/irq.c b/arch/arm/mach-w90x900/irq.c
new file mode 100644 (file)
index 0000000..0b4fc19
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * linux/arch/arm/mach-w90x900/irq.c
+ *
+ * based on linux/arch/arm/plat-s3c24xx/irq.c by Ben Dooks
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-irq.h>
+
+static void w90x900_irq_mask(unsigned int irq)
+{
+       __raw_writel(1 << irq, REG_AIC_MDCR);
+}
+
+/*
+ * By the w90p910 spec,any irq,only write 1
+ * to REG_AIC_EOSCR for ACK
+ */
+
+static void w90x900_irq_ack(unsigned int irq)
+{
+       __raw_writel(0x01, REG_AIC_EOSCR);
+}
+
+static void w90x900_irq_unmask(unsigned int irq)
+{
+       unsigned long mask;
+
+       if (irq == IRQ_T_INT_GROUP) {
+               mask = __raw_readl(REG_AIC_GEN);
+               __raw_writel(TIME_GROUP_IRQ | mask, REG_AIC_GEN);
+               __raw_writel(1 << IRQ_T_INT_GROUP, REG_AIC_MECR);
+       }
+       __raw_writel(1 << irq, REG_AIC_MECR);
+}
+
+static struct irq_chip w90x900_irq_chip = {
+       .ack       = w90x900_irq_ack,
+       .mask      = w90x900_irq_mask,
+       .unmask    = w90x900_irq_unmask,
+};
+
+void __init w90x900_init_irq(void)
+{
+       int irqno;
+
+       __raw_writel(0xFFFFFFFE, REG_AIC_MDCR);
+
+       for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) {
+               set_irq_chip(irqno, &w90x900_irq_chip);
+               set_irq_handler(irqno, handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+}
diff --git a/arch/arm/mach-w90x900/mach-w90p910evb.c b/arch/arm/mach-w90x900/mach-w90p910evb.c
new file mode 100644 (file)
index 0000000..9307a24
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/arm/mach-w90x900/mach-w90p910evb.c
+ *
+ * Based on mach-s3c2410/mach-smdk2410.c by Jonas Dietsche
+ *
+ * Copyright (C) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/regs-serial.h>
+
+#include "cpu.h"
+
+static struct map_desc w90p910_iodesc[] __initdata = {
+};
+
+static struct w90x900_uartcfg w90p910_uartcfgs[] = {
+       W90X900_UARTCFG(0, 0, 0, 0, 0),
+       W90X900_UARTCFG(1, 0, 0, 0, 0),
+       W90X900_UARTCFG(2, 0, 0, 0, 0),
+       W90X900_UARTCFG(3, 0, 0, 0, 0),
+       W90X900_UARTCFG(4, 0, 0, 0, 0),
+};
+
+/*Here should be your evb resourse,such as LCD*/
+
+static struct platform_device *w90p910evb_dev[] __initdata = {
+};
+
+static void __init w90p910evb_map_io(void)
+{
+       w90p910_map_io(w90p910_iodesc, ARRAY_SIZE(w90p910_iodesc));
+       w90p910_init_clocks(0);
+       w90p910_init_uarts(w90p910_uartcfgs, ARRAY_SIZE(w90p910_uartcfgs));
+}
+
+static void __init w90p910evb_init(void)
+{
+       platform_add_devices(w90p910evb_dev, ARRAY_SIZE(w90p910evb_dev));
+}
+
+MACHINE_START(W90P910EVB, "W90P910EVB")
+       /* Maintainer: Wan ZongShun */
+       .phys_io        = W90X900_PA_UART,
+       .io_pg_offst    = (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
+       .boot_params    = 0,
+       .map_io         = w90p910evb_map_io,
+       .init_irq       = w90x900_init_irq,
+       .init_machine   = w90p910evb_init,
+       .timer          = &w90x900_timer,
+MACHINE_END
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
new file mode 100644 (file)
index 0000000..3a69e38
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * linux/arch/arm/mach-w90x900/time.c
+ *
+ * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@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/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include <mach/system.h>
+#include <mach/map.h>
+#include <mach/regs-timer.h>
+
+static unsigned long w90x900_gettimeoffset(void)
+{
+       return 0;
+}
+
+/*IRQ handler for the timer*/
+
+static irqreturn_t
+w90x900_timer_interrupt(int irq, void *dev_id)
+{
+       timer_tick();
+       __raw_writel(0x01, REG_TISR); /* clear TIF0 */
+       return IRQ_HANDLED;
+}
+
+static struct irqaction w90x900_timer_irq = {
+       .name           = "w90x900 Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = w90x900_timer_interrupt,
+};
+
+/*Set up timer reg.*/
+
+static void w90x900_timer_setup(void)
+{
+       __raw_writel(0, REG_TCSR0);
+       __raw_writel(0, REG_TCSR1);
+       __raw_writel(0, REG_TCSR2);
+       __raw_writel(0, REG_TCSR3);
+       __raw_writel(0, REG_TCSR4);
+       __raw_writel(0x1F, REG_TISR);
+       __raw_writel(15000000/(100 * 100), REG_TICR0);
+       __raw_writel(0x68000063, REG_TCSR0);
+}
+
+static void __init w90x900_timer_init(void)
+{
+       w90x900_timer_setup();
+       setup_irq(IRQ_TIMER0, &w90x900_timer_irq);
+}
+
+struct sys_timer w90x900_timer = {
+       .init           = w90x900_timer_init,
+       .offset         = w90x900_gettimeoffset,
+       .resume         = w90x900_timer_setup
+};
diff --git a/arch/arm/mach-w90x900/w90p910.c b/arch/arm/mach-w90x900/w90p910.c
new file mode 100644 (file)
index 0000000..aa783bc
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * linux/arch/arm/mach-w90x900/w90p910.c
+ *
+ * Based on linux/arch/arm/plat-s3c24xx/s3c244x.c by Ben Dooks
+ *
+ * Copyright (c) 2008 Nuvoton technology corporation
+ * All rights reserved.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * W90P910 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-serial.h>
+
+#include "cpu.h"
+
+/*W90P910 has five uarts*/
+
+#define MAX_UART_COUNT 5
+static int uart_count;
+static struct platform_device *uart_devs[MAX_UART_COUNT-1];
+
+/* Initial IO mappings */
+
+static struct map_desc w90p910_iodesc[] __initdata = {
+       IODESC_ENT(IRQ),
+       IODESC_ENT(GCR),
+       IODESC_ENT(UART),
+       IODESC_ENT(TIMER),
+       IODESC_ENT(EBI),
+       /*IODESC_ENT(LCD),*/
+};
+
+/*Init the dev resource*/
+
+static W90X900_RES(UART0);
+static W90X900_RES(UART1);
+static W90X900_RES(UART2);
+static W90X900_RES(UART3);
+static W90X900_RES(UART4);
+static W90X900_DEVICE(uart0, UART0, 0, "w90x900-uart");
+static W90X900_DEVICE(uart1, UART1, 1, "w90x900-uart");
+static W90X900_DEVICE(uart2, UART2, 2, "w90x900-uart");
+static W90X900_DEVICE(uart3, UART3, 3, "w90x900-uart");
+static W90X900_DEVICE(uart4, UART4, 4, "w90x900-uart");
+
+static struct platform_device *uart_devices[] __initdata = {
+       &w90x900_uart0,
+       &w90x900_uart1,
+       &w90x900_uart2,
+       &w90x900_uart3,
+       &w90x900_uart4
+};
+
+/*Init W90P910 uart device*/
+
+void __init w90p910_init_uarts(struct w90x900_uartcfg *cfg, int no)
+{
+       struct platform_device *platdev;
+       int uart, uartdev;
+
+       /*By min() to judge count of uart be used indeed*/
+
+       uartdev = ARRAY_SIZE(uart_devices);
+       no = min(uartdev, no);
+
+       for (uart = 0; uart < no; uart++, cfg++) {
+               if (cfg->hwport != uart)
+                       printk(KERN_ERR "w90x900_uartcfg[%d] error\n", uart);
+               platdev = uart_devices[cfg->hwport];
+               uart_devs[uart] = platdev;
+               platdev->dev.platform_data = cfg;
+       }
+       uart_count = uart;
+}
+
+/*Init W90P910 evb io*/
+
+void __init w90p910_map_io(struct map_desc *mach_desc, int mach_size)
+{
+       unsigned long idcode = 0x0;
+
+       iotable_init(w90p910_iodesc, ARRAY_SIZE(w90p910_iodesc));
+
+       idcode = __raw_readl(W90X900PDID);
+       if (idcode != W90P910_CPUID)
+               printk(KERN_ERR "CPU type 0x%08lx is not W90P910\n", idcode);
+}
+
+/*Init W90P910 clock*/
+
+void __init w90p910_init_clocks(int xtal)
+{
+}
+
+static int __init w90p910_init_cpu(void)
+{
+       return 0;
+}
+
+static int __init w90x900_arch_init(void)
+{
+       int ret;
+
+       ret = w90p910_init_cpu();
+       if (ret != 0)
+               return ret;
+
+       return platform_add_devices(uart_devs, uart_count);
+
+}
+arch_initcall(w90x900_arch_init);
index ab5f7a21350b3af41bd6a227d1920f09c8091ed1..d490f3773c01c12aec0b1266d55aa8b92193649b 100644 (file)
@@ -10,8 +10,7 @@ config CPU_32
 
 # ARM610
 config CPU_ARM610
-       bool "Support ARM610 processor"
-       depends on ARCH_RPC
+       bool "Support ARM610 processor" if ARCH_RPC
        select CPU_32v3
        select CPU_CACHE_V3
        select CPU_CACHE_VIVT
@@ -43,8 +42,7 @@ config CPU_ARM7TDMI
 
 # ARM710
 config CPU_ARM710
-       bool "Support ARM710 processor" if !ARCH_CLPS7500 && ARCH_RPC
-       default y if ARCH_CLPS7500
+       bool "Support ARM710 processor" if ARCH_RPC
        select CPU_32v3
        select CPU_CACHE_V3
        select CPU_CACHE_VIVT
@@ -63,8 +61,7 @@ config CPU_ARM710
 
 # ARM720T
 config CPU_ARM720T
-       bool "Support ARM720T processor" if !ARCH_CLPS711X && !ARCH_L7200 && !ARCH_CDB89712 && ARCH_INTEGRATOR
-       default y if ARCH_CLPS711X || ARCH_L7200 || ARCH_CDB89712 || ARCH_H720X
+       bool "Support ARM720T processor" if ARCH_INTEGRATOR
        select CPU_32v4T
        select CPU_ABRT_LV4T
        select CPU_PABRT_NOIFAR
@@ -114,9 +111,7 @@ config CPU_ARM9TDMI
 
 # ARM920T
 config CPU_ARM920T
-       bool "Support ARM920T processor"
-       depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200
-       default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200
+       bool "Support ARM920T processor" if ARCH_INTEGRATOR
        select CPU_32v4T
        select CPU_ABRT_EV4T
        select CPU_PABRT_NOIFAR
@@ -138,8 +133,6 @@ config CPU_ARM920T
 # ARM922T
 config CPU_ARM922T
        bool "Support ARM922T processor" if ARCH_INTEGRATOR
-       depends on ARCH_LH7A40X || ARCH_INTEGRATOR || ARCH_KS8695
-       default y if ARCH_LH7A40X || ARCH_KS8695
        select CPU_32v4T
        select CPU_ABRT_EV4T
        select CPU_PABRT_NOIFAR
@@ -159,8 +152,6 @@ config CPU_ARM922T
 # ARM925T
 config CPU_ARM925T
        bool "Support ARM925T processor" if ARCH_OMAP1
-       depends on ARCH_OMAP15XX
-       default y if ARCH_OMAP15XX
        select CPU_32v4T
        select CPU_ABRT_EV4T
        select CPU_PABRT_NOIFAR
@@ -179,22 +170,7 @@ config CPU_ARM925T
 
 # ARM926T
 config CPU_ARM926T
-       bool "Support ARM926T processor"
-       depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || \
-               MACH_VERSATILE_AB || ARCH_OMAP730 || \
-               ARCH_OMAP16XX || MACH_REALVIEW_EB || \
-               ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || \
-               ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \
-               ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \
-               ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \
-               ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2
-       default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || \
-               ARCH_OMAP730 || ARCH_OMAP16XX || \
-               ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || \
-               ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || \
-               ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || \
-               ARCH_AT91SAM9G20 || ARCH_AT91CAP9 || \
-               ARCH_NS9XXX || ARCH_DAVINCI || ARCH_MX2
+       bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
        select CPU_32v5
        select CPU_ABRT_EV5TJ
        select CPU_PABRT_NOIFAR
@@ -247,8 +223,7 @@ config CPU_ARM946E
 
 # ARM1020 - needs validating
 config CPU_ARM1020
-       bool "Support ARM1020T (rev 0) processor"
-       depends on ARCH_INTEGRATOR
+       bool "Support ARM1020T (rev 0) processor" if ARCH_INTEGRATOR
        select CPU_32v5
        select CPU_ABRT_EV4T
        select CPU_PABRT_NOIFAR
@@ -266,8 +241,7 @@ config CPU_ARM1020
 
 # ARM1020E - needs validating
 config CPU_ARM1020E
-       bool "Support ARM1020E processor"
-       depends on ARCH_INTEGRATOR
+       bool "Support ARM1020E processor" if ARCH_INTEGRATOR
        select CPU_32v5
        select CPU_ABRT_EV4T
        select CPU_PABRT_NOIFAR
@@ -280,8 +254,7 @@ config CPU_ARM1020E
 
 # ARM1022E
 config CPU_ARM1022
-       bool "Support ARM1022E processor"
-       depends on ARCH_INTEGRATOR
+       bool "Support ARM1022E processor" if ARCH_INTEGRATOR
        select CPU_32v5
        select CPU_ABRT_EV4T
        select CPU_PABRT_NOIFAR
@@ -299,8 +272,7 @@ config CPU_ARM1022
 
 # ARM1026EJ-S
 config CPU_ARM1026
-       bool "Support ARM1026EJ-S processor"
-       depends on ARCH_INTEGRATOR
+       bool "Support ARM1026EJ-S processor" if ARCH_INTEGRATOR
        select CPU_32v5
        select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
        select CPU_PABRT_NOIFAR
@@ -317,8 +289,7 @@ config CPU_ARM1026
 
 # SA110
 config CPU_SA110
-       bool "Support StrongARM(R) SA-110 processor" if !ARCH_EBSA110 && !FOOTBRIDGE && !ARCH_TBOX && !ARCH_SHARK && !ARCH_NEXUSPCI && ARCH_RPC
-       default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_TBOX || ARCH_SHARK || ARCH_NEXUSPCI
+       bool "Support StrongARM(R) SA-110 processor" if ARCH_RPC
        select CPU_32v3 if ARCH_RPC
        select CPU_32v4 if !ARCH_RPC
        select CPU_ABRT_EV4
@@ -340,8 +311,6 @@ config CPU_SA110
 # SA1100
 config CPU_SA1100
        bool
-       depends on ARCH_SA1100
-       default y
        select CPU_32v4
        select CPU_ABRT_EV4
        select CPU_PABRT_NOIFAR
@@ -353,8 +322,6 @@ config CPU_SA1100
 # XScale
 config CPU_XSCALE
        bool
-       depends on ARCH_IOP32X || ARCH_IOP33X || PXA25x || PXA27x || ARCH_IXP4XX || ARCH_IXP2000
-       default y
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_PABRT_NOIFAR
@@ -365,8 +332,6 @@ config CPU_XSCALE
 # XScale Core Version 3
 config CPU_XSC3
        bool
-       depends on ARCH_IXP23XX || ARCH_IOP13XX || PXA3xx
-       default y
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_PABRT_NOIFAR
@@ -378,8 +343,6 @@ config CPU_XSC3
 # Feroceon
 config CPU_FEROCEON
        bool
-       depends on ARCH_ORION5X || ARCH_LOKI || ARCH_KIRKWOOD || ARCH_MV78XX0
-       default y
        select CPU_32v5
        select CPU_ABRT_EV5T
        select CPU_PABRT_NOIFAR
@@ -399,10 +362,7 @@ config CPU_FEROCEON_OLD_ID
 
 # ARMv6
 config CPU_V6
-       bool "Support ARM V6 processor"
-       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3 || ARCH_MSM || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176
-       default y if ARCH_MX3
-       default y if ARCH_MSM
+       bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
        select CPU_32v6
        select CPU_ABRT_EV6
        select CPU_PABRT_NOIFAR
@@ -427,8 +387,7 @@ config CPU_32v6K
 
 # ARMv7
 config CPU_V7
-       bool "Support ARM V7 processor"
-       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP3
+       bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
        select CPU_32v6K
        select CPU_32v7
        select CPU_ABRT_EV7
@@ -745,7 +704,7 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
 
 config CACHE_L2X0
        bool "Enable the L2x0 outer cache controller"
-       depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176
+       depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || REALVIEW_EB_A9MP
        default y
        select OUTER_CACHE
        help
index 2d5884ce0435fb436a57bee6d314284b9101e87e..3a398befed41422cb7f130e5667cd632104235eb 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/uaccess.h>
 
 #include <asm/unaligned.h>
index 3b3639eb7ca53c86e82184db943e29a06038dbc7..8a4abebc478a29617a55efeabd871480ca4ab9c2 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
-#include <mach/hardware.h>
 #include <asm/page.h>
 #include "proc-macros.S"
 
index 5786adf100407c7c6eca30013656be2a7e49e68e..3668611cb400325d9368e2707f41a25d0da93c50 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
-#include <mach/hardware.h>
 #include <asm/page.h>
 #include "proc-macros.S"
 
index 51a9b0b273b6f47ac7261591964e7463a6fbcbf1..c54fa2cc40e6e2f8ebfa2c60c7849ea94682bd70 100644 (file)
@@ -13,7 +13,6 @@
  */
 #include <linux/linkage.h>
 #include <linux/init.h>
-#include <mach/hardware.h>
 #include <asm/page.h>
 #include "proc-macros.S"
 
index d19c2bec2b1fe55da9ea7b114a67a2e942a24fa4..be93ff02a98d11e7dc1a76cb30746c2f24c7d8dc 100644 (file)
@@ -26,6 +26,7 @@
  *     - mm    - mm_struct describing address space
  */
 ENTRY(v7_flush_dcache_all)
+       dmb                                     @ ensure ordering with previous memory accesses
        mrc     p15, 1, r0, c0, c0, 1           @ read clidr
        ands    r3, r0, #0x7000000              @ extract loc from clidr
        mov     r3, r3, lsr #23                 @ left align loc bit field
@@ -64,6 +65,7 @@ skip:
 finished:
        mov     r10, #0                         @ swith back to cache level 0
        mcr     p15, 2, r10, c0, c0, 0          @ select current cache level in cssr
+       dsb
        isb
        mov     pc, lr
 ENDPROC(v7_flush_dcache_all)
diff --git a/arch/arm/mm/copypage-feroceon.S b/arch/arm/mm/copypage-feroceon.S
deleted file mode 100644 (file)
index 7eb0d32..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-feroceon.S
- *
- *  Copyright (C) 2008 Marvell Semiconductors
- *
- * This program is free software; you can 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 handles copy_user_page and clear_user_page on Feroceon
- * more optimally than the generic implementations.
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-
-       .text
-       .align  5
-
-ENTRY(feroceon_copy_user_page)
-       stmfd   sp!, {r4-r9, lr}
-       mov     ip, #PAGE_SZ
-1:     mov     lr, r1
-       ldmia   r1!, {r2 - r9}
-       pld     [lr, #32]
-       pld     [lr, #64]
-       pld     [lr, #96]
-       pld     [lr, #128]
-       pld     [lr, #160]
-       pld     [lr, #192]
-       pld     [lr, #224]
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       ldmia   r1!, {r2 - r9}
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       stmia   r0, {r2 - r9}
-       subs    ip, ip, #(32 * 8)
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       bne     1b
-       mcr     p15, 0, ip, c7, c10, 4          @ drain WB
-       ldmfd   sp!, {r4-r9, pc}
-
-       .align  5
-
-ENTRY(feroceon_clear_user_page)
-       stmfd   sp!, {r4-r7, lr}
-       mov     r1, #PAGE_SZ/32
-       mov     r2, #0
-       mov     r3, #0
-       mov     r4, #0
-       mov     r5, #0
-       mov     r6, #0
-       mov     r7, #0
-       mov     ip, #0
-       mov     lr, #0
-1:     stmia   r0, {r2-r7, ip, lr}
-       subs    r1, r1, #1
-       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line
-       add     r0, r0, #32
-       bne     1b
-       mcr     p15, 0, r1, c7, c10, 4          @ drain WB
-       ldmfd   sp!, {r4-r7, pc}
-
-       __INITDATA
-
-       .type   feroceon_user_fns, #object
-ENTRY(feroceon_user_fns)
-       .long   feroceon_clear_user_page
-       .long   feroceon_copy_user_page
-       .size   feroceon_user_fns, . - feroceon_user_fns
diff --git a/arch/arm/mm/copypage-feroceon.c b/arch/arm/mm/copypage-feroceon.c
new file mode 100644 (file)
index 0000000..c3ba6a9
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/arch/arm/mm/copypage-feroceon.S
+ *
+ *  Copyright (C) 2008 Marvell Semiconductors
+ *
+ * This program is free software; you can 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 handles copy_user_highpage and clear_user_page on Feroceon
+ * more optimally than the generic implementations.
+ */
+#include <linux/init.h>
+#include <linux/highmem.h>
+
+static void __attribute__((naked))
+feroceon_copy_user_page(void *kto, const void *kfrom)
+{
+       asm("\
+       stmfd   sp!, {r4-r9, lr}                \n\
+       mov     ip, %0                          \n\
+1:     mov     lr, r1                          \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       pld     [lr, #32]                       \n\
+       pld     [lr, #64]                       \n\
+       pld     [lr, #96]                       \n\
+       pld     [lr, #128]                      \n\
+       pld     [lr, #160]                      \n\
+       pld     [lr, #192]                      \n\
+       pld     [lr, #224]                      \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       ldmia   r1!, {r2 - r9}                  \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       stmia   r0, {r2 - r9}                   \n\
+       subs    ip, ip, #(32 * 8)               \n\
+       mcr     p15, 0, r0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     r0, r0, #32                     \n\
+       bne     1b                              \n\
+       mcr     p15, 0, ip, c7, c10, 4          @ drain WB\n\
+       ldmfd   sp!, {r4-r9, pc}"
+       :
+       : "I" (PAGE_SIZE));
+}
+
+void feroceon_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
+{
+       void *kto, *kfrom;
+
+       kto = kmap_atomic(to, KM_USER0);
+       kfrom = kmap_atomic(from, KM_USER1);
+       feroceon_copy_user_page(kto, kfrom);
+       kunmap_atomic(kfrom, KM_USER1);
+       kunmap_atomic(kto, KM_USER0);
+}
+
+void feroceon_clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile ("\
+       mov     r1, %2                          \n\
+       mov     r2, #0                          \n\
+       mov     r3, #0                          \n\
+       mov     r4, #0                          \n\
+       mov     r5, #0                          \n\
+       mov     r6, #0                          \n\
+       mov     r7, #0                          \n\
+       mov     ip, #0                          \n\
+       mov     lr, #0                          \n\
+1:     stmia   %0, {r2-r7, ip, lr}             \n\
+       subs    r1, r1, #1                      \n\
+       mcr     p15, 0, %0, c7, c14, 1          @ clean and invalidate D line\n\
+       add     %0, %0, #32                     \n\
+       bne     1b                              \n\
+       mcr     p15, 0, r1, c7, c10, 4          @ drain WB"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 32)
+       : "r1", "r2", "r3", "r4", "r5", "r6", "r7", "ip", "lr");
+       kunmap_atomic(kaddr, KM_USER0);
+}
+
+struct cpu_user_fns feroceon_user_fns __initdata = {
+       .cpu_clear_user_highpage = feroceon_clear_user_highpage,
+       .cpu_copy_user_highpage = feroceon_copy_user_highpage,
+};
+
diff --git a/arch/arm/mm/copypage-v3.S b/arch/arm/mm/copypage-v3.S
deleted file mode 100644 (file)
index 2ee394b..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage.S
- *
- *  Copyright (C) 1995-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/assembler.h>
-#include <asm/asm-offsets.h>
-
-               .text
-               .align  5
-/*
- * ARMv3 optimised copy_user_page
- *
- * FIXME: do we need to handle cache stuff...
- */
-ENTRY(v3_copy_user_page)
-       stmfd   sp!, {r4, lr}                   @       2
-       mov     r2, #PAGE_SZ/64                 @       1
-       ldmia   r1!, {r3, r4, ip, lr}           @       4+1
-1:     stmia   r0!, {r3, r4, ip, lr}           @       4
-       ldmia   r1!, {r3, r4, ip, lr}           @       4+1
-       stmia   r0!, {r3, r4, ip, lr}           @       4
-       ldmia   r1!, {r3, r4, ip, lr}           @       4+1
-       stmia   r0!, {r3, r4, ip, lr}           @       4
-       ldmia   r1!, {r3, r4, ip, lr}           @       4
-       subs    r2, r2, #1                      @       1
-       stmia   r0!, {r3, r4, ip, lr}           @       4
-       ldmneia r1!, {r3, r4, ip, lr}           @       4
-       bne     1b                              @       1
-       ldmfd   sp!, {r4, pc}                   @       3
-
-       .align  5
-/*
- * ARMv3 optimised clear_user_page
- *
- * FIXME: do we need to handle cache stuff...
- */
-ENTRY(v3_clear_user_page)
-       str     lr, [sp, #-4]!
-       mov     r1, #PAGE_SZ/64                 @ 1
-       mov     r2, #0                          @ 1
-       mov     r3, #0                          @ 1
-       mov     ip, #0                          @ 1
-       mov     lr, #0                          @ 1
-1:     stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       bne     1b                              @ 1
-       ldr     pc, [sp], #4
-
-       __INITDATA
-
-       .type   v3_user_fns, #object
-ENTRY(v3_user_fns)
-       .long   v3_clear_user_page
-       .long   v3_copy_user_page
-       .size   v3_user_fns, . - v3_user_fns
diff --git a/arch/arm/mm/copypage-v3.c b/arch/arm/mm/copypage-v3.c
new file mode 100644 (file)
index 0000000..70ed96c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *  linux/arch/arm/mm/copypage-v3.c
+ *
+ *  Copyright (C) 1995-1999 Russell King
+ *
+ * This program is free software; you can 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/highmem.h>
+
+/*
+ * ARMv3 optimised copy_user_highpage
+ *
+ * FIXME: do we need to handle cache stuff...
+ */
+static void __attribute__((naked))
+v3_copy_user_page(void *kto, const void *kfrom)
+{
+       asm("\n\
+       stmfd   sp!, {r4, lr}                   @       2\n\
+       mov     r2, %2                          @       1\n\
+       ldmia   %0!, {r3, r4, ip, lr}           @       4+1\n\
+1:     stmia   %1!, {r3, r4, ip, lr}           @       4\n\
+       ldmia   %0!, {r3, r4, ip, lr}           @       4+1\n\
+       stmia   %1!, {r3, r4, ip, lr}           @       4\n\
+       ldmia   %0!, {r3, r4, ip, lr}           @       4+1\n\
+       stmia   %1!, {r3, r4, ip, lr}           @       4\n\
+       ldmia   %0!, {r3, r4, ip, lr}           @       4\n\
+       subs    r2, r2, #1                      @       1\n\
+       stmia   %1!, {r3, r4, ip, lr}           @       4\n\
+       ldmneia %0!, {r3, r4, ip, lr}           @       4\n\
+       bne     1b                              @       1\n\
+       ldmfd   sp!, {r4, pc}                   @       3"
+       :
+       : "r" (kfrom), "r" (kto), "I" (PAGE_SIZE / 64));
+}
+
+void v3_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
+{
+       void *kto, *kfrom;
+
+       kto = kmap_atomic(to, KM_USER0);
+       kfrom = kmap_atomic(from, KM_USER1);
+       v3_copy_user_page(kto, kfrom);
+       kunmap_atomic(kfrom, KM_USER1);
+       kunmap_atomic(kto, KM_USER0);
+}
+
+/*
+ * ARMv3 optimised clear_user_page
+ *
+ * FIXME: do we need to handle cache stuff...
+ */
+void v3_clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile("\n\
+       mov     r1, %2                          @ 1\n\
+       mov     r2, #0                          @ 1\n\
+       mov     r3, #0                          @ 1\n\
+       mov     ip, #0                          @ 1\n\
+       mov     lr, #0                          @ 1\n\
+1:     stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r1, r1, #1                      @ 1\n\
+       bne     1b                              @ 1"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 64)
+       : "r1", "r2", "r3", "ip", "lr");
+       kunmap_atomic(kaddr, KM_USER0);
+}
+
+struct cpu_user_fns v3_user_fns __initdata = {
+       .cpu_clear_user_highpage = v3_clear_user_highpage,
+       .cpu_copy_user_highpage = v3_copy_user_highpage,
+};
index 8d33e2549344a1393f16a095b9d3f98e5cbeaa05..bdb5fd983b154a1fca231be95065ef772ec73404 100644 (file)
@@ -15,8 +15,8 @@
  */
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 
-#include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
@@ -33,7 +33,7 @@
 static DEFINE_SPINLOCK(minicache_lock);
 
 /*
- * ARMv4 mini-dcache optimised copy_user_page
+ * ARMv4 mini-dcache optimised copy_user_highpage
  *
  * We flush the destination cache lines just before we write the data into the
  * corresponding address.  Since the Dcache is read-allocate, this removes the
@@ -42,7 +42,7 @@ static DEFINE_SPINLOCK(minicache_lock);
  *
  * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
  * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
+ * own copy_user_highpage that does the right thing.
  */
 static void __attribute__((naked))
 mc_copy_user_page(void *from, void *to)
@@ -68,50 +68,53 @@ mc_copy_user_page(void *from, void *to)
        : "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
 }
 
-void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+void v4_mc_copy_user_highpage(struct page *from, struct page *to,
+       unsigned long vaddr)
 {
-       struct page *page = virt_to_page(kfrom);
+       void *kto = kmap_atomic(to, KM_USER1);
 
-       if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
-               __flush_dcache_page(page_mapping(page), page);
+       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+               __flush_dcache_page(page_mapping(from), from);
 
        spin_lock(&minicache_lock);
 
-       set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
+       set_pte_ext(TOP_PTE(0xffff8000), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
        flush_tlb_kernel_page(0xffff8000);
 
        mc_copy_user_page((void *)0xffff8000, kto);
 
        spin_unlock(&minicache_lock);
+
+       kunmap_atomic(kto, KM_USER1);
 }
 
 /*
  * ARMv4 optimised clear_user_page
  */
-void __attribute__((naked))
-v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
+void v4_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
 {
-       asm volatile(
-       "str    lr, [sp, #-4]!\n\
-       mov     r1, %0                          @ 1\n\
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile("\
+       mov     r1, %2                          @ 1\n\
        mov     r2, #0                          @ 1\n\
        mov     r3, #0                          @ 1\n\
        mov     ip, #0                          @ 1\n\
        mov     lr, #0                          @ 1\n\
-1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
-       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
-       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
-       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
-       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
-       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+1:     mcr     p15, 0, %0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       mcr     p15, 0, %0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
        subs    r1, r1, #1                      @ 1\n\
-       bne     1b                              @ 1\n\
-       ldr     pc, [sp], #4"
-       :
-       : "I" (PAGE_SIZE / 64));
+       bne     1b                              @ 1"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 64)
+       : "r1", "r2", "r3", "ip", "lr");
+       kunmap_atomic(kaddr, KM_USER0);
 }
 
 struct cpu_user_fns v4_mc_user_fns __initdata = {
-       .cpu_clear_user_page    = v4_mc_clear_user_page, 
-       .cpu_copy_user_page     = v4_mc_copy_user_page,
+       .cpu_clear_user_highpage = v4_mc_clear_user_highpage,
+       .cpu_copy_user_highpage = v4_mc_copy_user_highpage,
 };
diff --git a/arch/arm/mm/copypage-v4wb.S b/arch/arm/mm/copypage-v4wb.S
deleted file mode 100644 (file)
index 8311735..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage.S
- *
- *  Copyright (C) 1995-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-
-       .text
-       .align  5
-/*
- * ARMv4 optimised copy_user_page
- *
- * We flush the destination cache lines just before we write the data into the
- * corresponding address.  Since the Dcache is read-allocate, this removes the
- * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
- * and merged as appropriate.
- *
- * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
- * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
- */
-ENTRY(v4wb_copy_user_page)
-       stmfd   sp!, {r4, lr}                   @ 2
-       mov     r2, #PAGE_SZ/64                 @ 1
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4
-1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4+1
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4
-       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4
-       subs    r2, r2, #1                      @ 1
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmneia r1!, {r3, r4, ip, lr}           @ 4
-       bne     1b                              @ 1
-       mcr     p15, 0, r1, c7, c10, 4          @ 1   drain WB
-       ldmfd    sp!, {r4, pc}                  @ 3
-
-       .align  5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(v4wb_clear_user_page)
-       str     lr, [sp, #-4]!
-       mov     r1, #PAGE_SZ/64                 @ 1
-       mov     r2, #0                          @ 1
-       mov     r3, #0                          @ 1
-       mov     ip, #0                          @ 1
-       mov     lr, #0                          @ 1
-1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       bne     1b                              @ 1
-       mcr     p15, 0, r1, c7, c10, 4          @ 1   drain WB
-       ldr     pc, [sp], #4
-
-       __INITDATA
-
-       .type   v4wb_user_fns, #object
-ENTRY(v4wb_user_fns)
-       .long   v4wb_clear_user_page
-       .long   v4wb_copy_user_page
-       .size   v4wb_user_fns, . - v4wb_user_fns
diff --git a/arch/arm/mm/copypage-v4wb.c b/arch/arm/mm/copypage-v4wb.c
new file mode 100644 (file)
index 0000000..3ec93da
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  linux/arch/arm/mm/copypage-v4wb.c
+ *
+ *  Copyright (C) 1995-1999 Russell King
+ *
+ * This program is free software; you can 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/highmem.h>
+
+/*
+ * ARMv4 optimised copy_user_highpage
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ *
+ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
+ * instruction.  If your processor does not supply this, you have to write your
+ * own copy_user_highpage that does the right thing.
+ */
+static void __attribute__((naked))
+v4wb_copy_user_page(void *kto, const void *kfrom)
+{
+       asm("\
+       stmfd   sp!, {r4, lr}                   @ 2\n\
+       mov     r2, %0                          @ 1\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4+1\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+       subs    r2, r2, #1                      @ 1\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmneia r1!, {r3, r4, ip, lr}           @ 4\n\
+       bne     1b                              @ 1\n\
+       mcr     p15, 0, r1, c7, c10, 4          @ 1   drain WB\n\
+       ldmfd    sp!, {r4, pc}                  @ 3"
+       :
+       : "I" (PAGE_SIZE / 64));
+}
+
+void v4wb_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
+{
+       void *kto, *kfrom;
+
+       kto = kmap_atomic(to, KM_USER0);
+       kfrom = kmap_atomic(from, KM_USER1);
+       v4wb_copy_user_page(kto, kfrom);
+       kunmap_atomic(kfrom, KM_USER1);
+       kunmap_atomic(kto, KM_USER0);
+}
+
+/*
+ * ARMv4 optimised clear_user_page
+ *
+ * Same story as above.
+ */
+void v4wb_clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile("\
+       mov     r1, %2                          @ 1\n\
+       mov     r2, #0                          @ 1\n\
+       mov     r3, #0                          @ 1\n\
+       mov     ip, #0                          @ 1\n\
+       mov     lr, #0                          @ 1\n\
+1:     mcr     p15, 0, %0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       mcr     p15, 0, %0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r1, r1, #1                      @ 1\n\
+       bne     1b                              @ 1\n\
+       mcr     p15, 0, r1, c7, c10, 4          @ 1   drain WB"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 64)
+       : "r1", "r2", "r3", "ip", "lr");
+       kunmap_atomic(kaddr, KM_USER0);
+}
+
+struct cpu_user_fns v4wb_user_fns __initdata = {
+       .cpu_clear_user_highpage = v4wb_clear_user_highpage,
+       .cpu_copy_user_highpage = v4wb_copy_user_highpage,
+};
diff --git a/arch/arm/mm/copypage-v4wt.S b/arch/arm/mm/copypage-v4wt.S
deleted file mode 100644 (file)
index e1f2af2..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-v4.S
- *
- *  Copyright (C) 1995-1999 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  ASM optimised string functions
- *
- *  This is for CPUs with a writethrough cache and 'flush ID cache' is
- *  the only supported cache operation.
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-
-       .text
-       .align  5
-/*
- * ARMv4 optimised copy_user_page
- *
- * Since we have writethrough caches, we don't have to worry about
- * dirty data in the cache.  However, we do have to ensure that
- * subsequent reads are up to date.
- */
-ENTRY(v4wt_copy_user_page)
-       stmfd   sp!, {r4, lr}                   @ 2
-       mov     r2, #PAGE_SZ/64                 @ 1
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4
-1:     stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4+1
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmia   r1!, {r3, r4, ip, lr}           @ 4
-       subs    r2, r2, #1                      @ 1
-       stmia   r0!, {r3, r4, ip, lr}           @ 4
-       ldmneia r1!, {r3, r4, ip, lr}           @ 4
-       bne     1b                              @ 1
-       mcr     p15, 0, r2, c7, c7, 0           @ flush ID cache
-       ldmfd   sp!, {r4, pc}                   @ 3
-
-       .align  5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(v4wt_clear_user_page)
-       str     lr, [sp, #-4]!
-       mov     r1, #PAGE_SZ/64                 @ 1
-       mov     r2, #0                          @ 1
-       mov     r3, #0                          @ 1
-       mov     ip, #0                          @ 1
-       mov     lr, #0                          @ 1
-1:     stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       bne     1b                              @ 1
-       mcr     p15, 0, r2, c7, c7, 0           @ flush ID cache
-       ldr     pc, [sp], #4
-
-       __INITDATA
-
-       .type   v4wt_user_fns, #object
-ENTRY(v4wt_user_fns)
-       .long   v4wt_clear_user_page
-       .long   v4wt_copy_user_page
-       .size   v4wt_user_fns, . - v4wt_user_fns
diff --git a/arch/arm/mm/copypage-v4wt.c b/arch/arm/mm/copypage-v4wt.c
new file mode 100644 (file)
index 0000000..0f1188e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  linux/arch/arm/mm/copypage-v4wt.S
+ *
+ *  Copyright (C) 1995-1999 Russell King
+ *
+ * This program is free software; you can 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 is for CPUs with a writethrough cache and 'flush ID cache' is
+ *  the only supported cache operation.
+ */
+#include <linux/init.h>
+#include <linux/highmem.h>
+
+/*
+ * ARMv4 optimised copy_user_highpage
+ *
+ * Since we have writethrough caches, we don't have to worry about
+ * dirty data in the cache.  However, we do have to ensure that
+ * subsequent reads are up to date.
+ */
+static void __attribute__((naked))
+v4wt_copy_user_page(void *kto, const void *kfrom)
+{
+       asm("\
+       stmfd   sp!, {r4, lr}                   @ 2\n\
+       mov     r2, %0                          @ 1\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+1:     stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4+1\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmia   r1!, {r3, r4, ip, lr}           @ 4\n\
+       subs    r2, r2, #1                      @ 1\n\
+       stmia   r0!, {r3, r4, ip, lr}           @ 4\n\
+       ldmneia r1!, {r3, r4, ip, lr}           @ 4\n\
+       bne     1b                              @ 1\n\
+       mcr     p15, 0, r2, c7, c7, 0           @ flush ID cache\n\
+       ldmfd   sp!, {r4, pc}                   @ 3"
+       :
+       : "I" (PAGE_SIZE / 64));
+}
+
+void v4wt_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
+{
+       void *kto, *kfrom;
+
+       kto = kmap_atomic(to, KM_USER0);
+       kfrom = kmap_atomic(from, KM_USER1);
+       v4wt_copy_user_page(kto, kfrom);
+       kunmap_atomic(kfrom, KM_USER1);
+       kunmap_atomic(kto, KM_USER0);
+}
+
+/*
+ * ARMv4 optimised clear_user_page
+ *
+ * Same story as above.
+ */
+void v4wt_clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile("\
+       mov     r1, %2                          @ 1\n\
+       mov     r2, #0                          @ 1\n\
+       mov     r3, #0                          @ 1\n\
+       mov     ip, #0                          @ 1\n\
+       mov     lr, #0                          @ 1\n\
+1:     stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r1, r1, #1                      @ 1\n\
+       bne     1b                              @ 1\n\
+       mcr     p15, 0, r2, c7, c7, 0           @ flush ID cache"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 64)
+       : "r1", "r2", "r3", "ip", "lr");
+       kunmap_atomic(kaddr, KM_USER0);
+}
+
+struct cpu_user_fns v4wt_user_fns __initdata = {
+       .cpu_clear_user_highpage = v4wt_clear_user_highpage,
+       .cpu_copy_user_highpage = v4wt_copy_user_highpage,
+};
index 0e21c07675806a8be16db392e7568686205ccb1f..4127a7bddfe5cef91f4a340cfe4225e6200330a6 100644 (file)
@@ -10,8 +10,8 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 
-#include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/shmparam.h>
 #include <asm/tlbflush.h>
@@ -33,41 +33,56 @@ static DEFINE_SPINLOCK(v6_lock);
  * Copy the user page.  No aliasing to deal with so we can just
  * attack the kernel's existing mapping of these pages.
  */
-static void v6_copy_user_page_nonaliasing(void *kto, const void *kfrom, unsigned long vaddr)
+static void v6_copy_user_highpage_nonaliasing(struct page *to,
+       struct page *from, unsigned long vaddr)
 {
+       void *kto, *kfrom;
+
+       kfrom = kmap_atomic(from, KM_USER0);
+       kto = kmap_atomic(to, KM_USER1);
        copy_page(kto, kfrom);
+       kunmap_atomic(kto, KM_USER1);
+       kunmap_atomic(kfrom, KM_USER0);
 }
 
 /*
  * Clear the user page.  No aliasing to deal with so we can just
  * attack the kernel's existing mapping of this page.
  */
-static void v6_clear_user_page_nonaliasing(void *kaddr, unsigned long vaddr)
+static void v6_clear_user_highpage_nonaliasing(struct page *page, unsigned long vaddr)
 {
+       void *kaddr = kmap_atomic(page, KM_USER0);
        clear_page(kaddr);
+       kunmap_atomic(kaddr, KM_USER0);
 }
 
 /*
- * Copy the page, taking account of the cache colour.
+ * Discard data in the kernel mapping for the new page.
+ * FIXME: needs this MCRR to be supported.
  */
-static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vaddr)
+static void discard_old_kernel_data(void *kto)
 {
-       unsigned int offset = CACHE_COLOUR(vaddr);
-       unsigned long from, to;
-       struct page *page = virt_to_page(kfrom);
-
-       if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
-               __flush_dcache_page(page_mapping(page), page);
-
-       /*
-        * Discard data in the kernel mapping for the new page.
-        * FIXME: needs this MCRR to be supported.
-        */
        __asm__("mcrr   p15, 0, %1, %0, c6      @ 0xec401f06"
           :
           : "r" (kto),
             "r" ((unsigned long)kto + PAGE_SIZE - L1_CACHE_BYTES)
           : "cc");
+}
+
+/*
+ * Copy the page, taking account of the cache colour.
+ */
+static void v6_copy_user_highpage_aliasing(struct page *to,
+       struct page *from, unsigned long vaddr)
+{
+       unsigned int offset = CACHE_COLOUR(vaddr);
+       unsigned long kfrom, kto;
+
+       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+               __flush_dcache_page(page_mapping(from), from);
+
+       /* FIXME: not highmem safe */
+       discard_old_kernel_data(page_address(to));
 
        /*
         * Now copy the page using the same cache colour as the
@@ -75,16 +90,16 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
         */
        spin_lock(&v6_lock);
 
-       set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, PAGE_KERNEL), 0);
-       set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, PAGE_KERNEL), 0);
+       set_pte_ext(TOP_PTE(from_address) + offset, pfn_pte(page_to_pfn(from), PAGE_KERNEL), 0);
+       set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(to), PAGE_KERNEL), 0);
 
-       from = from_address + (offset << PAGE_SHIFT);
-       to   = to_address + (offset << PAGE_SHIFT);
+       kfrom = from_address + (offset << PAGE_SHIFT);
+       kto   = to_address + (offset << PAGE_SHIFT);
 
-       flush_tlb_kernel_page(from);
-       flush_tlb_kernel_page(to);
+       flush_tlb_kernel_page(kfrom);
+       flush_tlb_kernel_page(kto);
 
-       copy_page((void *)to, (void *)from);
+       copy_page((void *)kto, (void *)kfrom);
 
        spin_unlock(&v6_lock);
 }
@@ -94,20 +109,13 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
  * so remap the kernel page into the same cache colour as the user
  * page.
  */
-static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
+static void v6_clear_user_highpage_aliasing(struct page *page, unsigned long vaddr)
 {
        unsigned int offset = CACHE_COLOUR(vaddr);
        unsigned long to = to_address + (offset << PAGE_SHIFT);
 
-       /*
-        * Discard data in the kernel mapping for the new page
-        * FIXME: needs this MCRR to be supported.
-        */
-       __asm__("mcrr   p15, 0, %1, %0, c6      @ 0xec401f06"
-          :
-          : "r" (kaddr),
-            "r" ((unsigned long)kaddr + PAGE_SIZE - L1_CACHE_BYTES)
-          : "cc");
+       /* FIXME: not highmem safe */
+       discard_old_kernel_data(page_address(page));
 
        /*
         * Now clear the page using the same cache colour as
@@ -115,7 +123,7 @@ static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
         */
        spin_lock(&v6_lock);
 
-       set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, PAGE_KERNEL), 0);
+       set_pte_ext(TOP_PTE(to_address) + offset, pfn_pte(page_to_pfn(page), PAGE_KERNEL), 0);
        flush_tlb_kernel_page(to);
        clear_page((void *)to);
 
@@ -123,15 +131,15 @@ static void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
 }
 
 struct cpu_user_fns v6_user_fns __initdata = {
-       .cpu_clear_user_page    = v6_clear_user_page_nonaliasing,
-       .cpu_copy_user_page     = v6_copy_user_page_nonaliasing,
+       .cpu_clear_user_highpage = v6_clear_user_highpage_nonaliasing,
+       .cpu_copy_user_highpage = v6_copy_user_highpage_nonaliasing,
 };
 
 static int __init v6_userpage_init(void)
 {
        if (cache_is_vipt_aliasing()) {
-               cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
-               cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
+               cpu_user.cpu_clear_user_highpage = v6_clear_user_highpage_aliasing;
+               cpu_user.cpu_copy_user_highpage = v6_copy_user_highpage_aliasing;
        }
 
        return 0;
diff --git a/arch/arm/mm/copypage-xsc3.S b/arch/arm/mm/copypage-xsc3.S
deleted file mode 100644 (file)
index 9a2cb43..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-xsc3.S
- *
- *  Copyright (C) 2004 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Adapted for 3rd gen XScale core, no more mini-dcache
- * Author: Matt Gilbert (matthew.m.gilbert@intel.com)
- */
-
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-
-/*
- * General note:
- *  We don't really want write-allocate cache behaviour for these functions
- *  since that will just eat through 8K of the cache.
- */
-
-       .text
-       .align  5
-/*
- * XSC3 optimised copy_user_page
- *  r0 = destination
- *  r1 = source
- *  r2 = virtual user address of ultimate destination page
- *
- * The source page may have some clean entries in the cache already, but we
- * can safely ignore them - break_cow() will flush them out of the cache
- * if we eventually end up using our copied page.
- *
- */
-ENTRY(xsc3_mc_copy_user_page)
-       stmfd   sp!, {r4, r5, lr}
-       mov     lr, #PAGE_SZ/64-1
-
-       pld     [r1, #0]
-       pld     [r1, #32]
-1:     pld     [r1, #64]
-       pld     [r1, #96]
-
-2:     ldrd    r2, [r1], #8
-       mov     ip, r0
-       ldrd    r4, [r1], #8
-       mcr     p15, 0, ip, c7, c6, 1           @ invalidate
-       strd    r2, [r0], #8
-       ldrd    r2, [r1], #8
-       strd    r4, [r0], #8
-       ldrd    r4, [r1], #8
-       strd    r2, [r0], #8
-       strd    r4, [r0], #8
-       ldrd    r2, [r1], #8
-       mov     ip, r0
-       ldrd    r4, [r1], #8
-       mcr     p15, 0, ip, c7, c6, 1           @ invalidate
-       strd    r2, [r0], #8
-       ldrd    r2, [r1], #8
-       subs    lr, lr, #1
-       strd    r4, [r0], #8
-       ldrd    r4, [r1], #8
-       strd    r2, [r0], #8
-       strd    r4, [r0], #8
-       bgt     1b
-       beq     2b
-
-       ldmfd   sp!, {r4, r5, pc}
-
-       .align  5
-/*
- * XScale optimised clear_user_page
- *  r0 = destination
- *  r1 = virtual user address of ultimate destination page
- */
-ENTRY(xsc3_mc_clear_user_page)
-       mov     r1, #PAGE_SZ/32
-       mov     r2, #0
-       mov     r3, #0
-1:     mcr     p15, 0, r0, c7, c6, 1           @ invalidate line
-       strd    r2, [r0], #8
-       strd    r2, [r0], #8
-       strd    r2, [r0], #8
-       strd    r2, [r0], #8
-       subs    r1, r1, #1
-       bne     1b
-       mov     pc, lr
-
-       __INITDATA
-
-       .type   xsc3_mc_user_fns, #object
-ENTRY(xsc3_mc_user_fns)
-       .long   xsc3_mc_clear_user_page
-       .long   xsc3_mc_copy_user_page
-       .size   xsc3_mc_user_fns, . - xsc3_mc_user_fns
diff --git a/arch/arm/mm/copypage-xsc3.c b/arch/arm/mm/copypage-xsc3.c
new file mode 100644 (file)
index 0000000..39a9945
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *  linux/arch/arm/mm/copypage-xsc3.S
+ *
+ *  Copyright (C) 2004 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Adapted for 3rd gen XScale core, no more mini-dcache
+ * Author: Matt Gilbert (matthew.m.gilbert@intel.com)
+ */
+#include <linux/init.h>
+#include <linux/highmem.h>
+
+/*
+ * General note:
+ *  We don't really want write-allocate cache behaviour for these functions
+ *  since that will just eat through 8K of the cache.
+ */
+
+/*
+ * XSC3 optimised copy_user_highpage
+ *  r0 = destination
+ *  r1 = source
+ *
+ * The source page may have some clean entries in the cache already, but we
+ * can safely ignore them - break_cow() will flush them out of the cache
+ * if we eventually end up using our copied page.
+ *
+ */
+static void __attribute__((naked))
+xsc3_mc_copy_user_page(void *kto, const void *kfrom)
+{
+       asm("\
+       stmfd   sp!, {r4, r5, lr}               \n\
+       mov     lr, %0                          \n\
+                                               \n\
+       pld     [r1, #0]                        \n\
+       pld     [r1, #32]                       \n\
+1:     pld     [r1, #64]                       \n\
+       pld     [r1, #96]                       \n\
+                                               \n\
+2:     ldrd    r2, [r1], #8                    \n\
+       mov     ip, r0                          \n\
+       ldrd    r4, [r1], #8                    \n\
+       mcr     p15, 0, ip, c7, c6, 1           @ invalidate\n\
+       strd    r2, [r0], #8                    \n\
+       ldrd    r2, [r1], #8                    \n\
+       strd    r4, [r0], #8                    \n\
+       ldrd    r4, [r1], #8                    \n\
+       strd    r2, [r0], #8                    \n\
+       strd    r4, [r0], #8                    \n\
+       ldrd    r2, [r1], #8                    \n\
+       mov     ip, r0                          \n\
+       ldrd    r4, [r1], #8                    \n\
+       mcr     p15, 0, ip, c7, c6, 1           @ invalidate\n\
+       strd    r2, [r0], #8                    \n\
+       ldrd    r2, [r1], #8                    \n\
+       subs    lr, lr, #1                      \n\
+       strd    r4, [r0], #8                    \n\
+       ldrd    r4, [r1], #8                    \n\
+       strd    r2, [r0], #8                    \n\
+       strd    r4, [r0], #8                    \n\
+       bgt     1b                              \n\
+       beq     2b                              \n\
+                                               \n\
+       ldmfd   sp!, {r4, r5, pc}"
+       :
+       : "I" (PAGE_SIZE / 64 - 1));
+}
+
+void xsc3_mc_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
+{
+       void *kto, *kfrom;
+
+       kto = kmap_atomic(to, KM_USER0);
+       kfrom = kmap_atomic(from, KM_USER1);
+       xsc3_mc_copy_user_page(kto, kfrom);
+       kunmap_atomic(kfrom, KM_USER1);
+       kunmap_atomic(kto, KM_USER0);
+}
+
+/*
+ * XScale optimised clear_user_page
+ *  r0 = destination
+ *  r1 = virtual user address of ultimate destination page
+ */
+void xsc3_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
+       asm volatile ("\
+       mov     r1, %2                          \n\
+       mov     r2, #0                          \n\
+       mov     r3, #0                          \n\
+1:     mcr     p15, 0, %0, c7, c6, 1           @ invalidate line\n\
+       strd    r2, [%0], #8                    \n\
+       strd    r2, [%0], #8                    \n\
+       strd    r2, [%0], #8                    \n\
+       strd    r2, [%0], #8                    \n\
+       subs    r1, r1, #1                      \n\
+       bne     1b"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 32)
+       : "r1", "r2", "r3");
+       kunmap_atomic(kaddr, KM_USER0);
+}
+
+struct cpu_user_fns xsc3_mc_user_fns __initdata = {
+       .cpu_clear_user_highpage = xsc3_mc_clear_user_highpage,
+       .cpu_copy_user_highpage = xsc3_mc_copy_user_highpage,
+};
index bad49331bbf94a22ded76f9222a15da063bd7846..d18f2397ee2dd7b0903514317466251990a78d7f 100644 (file)
@@ -15,8 +15,8 @@
  */
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/highmem.h>
 
-#include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
@@ -35,7 +35,7 @@
 static DEFINE_SPINLOCK(minicache_lock);
 
 /*
- * XScale mini-dcache optimised copy_user_page
+ * XScale mini-dcache optimised copy_user_highpage
  *
  * We flush the destination cache lines just before we write the data into the
  * corresponding address.  Since the Dcache is read-allocate, this removes the
@@ -90,48 +90,53 @@ mc_copy_user_page(void *from, void *to)
        : "r" (from), "r" (to), "I" (PAGE_SIZE / 64 - 1));
 }
 
-void xscale_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
+       unsigned long vaddr)
 {
-       struct page *page = virt_to_page(kfrom);
+       void *kto = kmap_atomic(to, KM_USER1);
 
-       if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
-               __flush_dcache_page(page_mapping(page), page);
+       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+               __flush_dcache_page(page_mapping(from), from);
 
        spin_lock(&minicache_lock);
 
-       set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
+       set_pte_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(page_to_pfn(from), minicache_pgprot), 0);
        flush_tlb_kernel_page(COPYPAGE_MINICACHE);
 
        mc_copy_user_page((void *)COPYPAGE_MINICACHE, kto);
 
        spin_unlock(&minicache_lock);
+
+       kunmap_atomic(kto, KM_USER1);
 }
 
 /*
  * XScale optimised clear_user_page
  */
-void __attribute__((naked))
-xscale_mc_clear_user_page(void *kaddr, unsigned long vaddr)
+void
+xscale_mc_clear_user_highpage(struct page *page, unsigned long vaddr)
 {
+       void *ptr, *kaddr = kmap_atomic(page, KM_USER0);
        asm volatile(
-       "mov    r1, %0                          \n\
+       "mov    r1, %2                          \n\
        mov     r2, #0                          \n\
        mov     r3, #0                          \n\
-1:     mov     ip, r0                          \n\
-       strd    r2, [r0], #8                    \n\
-       strd    r2, [r0], #8                    \n\
-       strd    r2, [r0], #8                    \n\
-       strd    r2, [r0], #8                    \n\
+1:     mov     ip, %0                          \n\
+       strd    r2, [%0], #8                    \n\
+       strd    r2, [%0], #8                    \n\
+       strd    r2, [%0], #8                    \n\
+       strd    r2, [%0], #8                    \n\
        mcr     p15, 0, ip, c7, c10, 1          @ clean D line\n\
        subs    r1, r1, #1                      \n\
        mcr     p15, 0, ip, c7, c6, 1           @ invalidate D line\n\
-       bne     1b                              \n\
-       mov     pc, lr"
-       :
-       : "I" (PAGE_SIZE / 32));
+       bne     1b"
+       : "=r" (ptr)
+       : "0" (kaddr), "I" (PAGE_SIZE / 32)
+       : "r1", "r2", "r3", "ip");
+       kunmap_atomic(kaddr, KM_USER0);
 }
 
 struct cpu_user_fns xscale_mc_user_fns __initdata = {
-       .cpu_clear_user_page    = xscale_mc_clear_user_page, 
-       .cpu_copy_user_page     = xscale_mc_copy_user_page,
+       .cpu_clear_user_highpage = xscale_mc_clear_user_highpage,
+       .cpu_copy_user_highpage = xscale_mc_copy_user_highpage,
 };
index 22c9530e91e2fd8568fa78e1e5aec95ed7a72a24..0455557a289957e13bab0ef74a37ff0ebe5052d8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
+#include <linux/page-flags.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -84,13 +85,14 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
                        break;
                }
 
-#ifndef CONFIG_HIGHMEM
                /* We must not map this if we have highmem enabled */
+               if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
+                       break;
+
                pte = pte_offset_map(pmd, addr);
                printk(", *pte=%08lx", pte_val(*pte));
                printk(", *ppte=%08lx", pte_val(pte[-PTRS_PER_PTE]));
                pte_unmap(pte);
-#endif
        } while(0);
 
        printk("\n");
index 82c4b4217989b1587a06a7acccd93ba5fc7b0c0e..34df4d9d03a6afb6f7a65627bb86d3da56c05cba 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/initrd.h>
 
 #include <asm/mach-types.h>
+#include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/sizes.h>
 #include <asm/tlb.h>
@@ -64,10 +65,11 @@ static int __init parse_tag_initrd2(const struct tag *tag)
 __tagtable(ATAG_INITRD2, parse_tag_initrd2);
 
 /*
- * This is used to pass memory configuration data from paging_init
- * to mem_init, and by show_mem() to skip holes in the memory map.
+ * This keeps memory configuration data used by a couple memory
+ * initialization functions, as well as show_mem() for the skipping
+ * of holes in the memory map.  It is populated by arm_add_memory().
  */
-static struct meminfo meminfo = { 0, };
+struct meminfo meminfo;
 
 void show_mem(void)
 {
@@ -128,7 +130,7 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
 {
        unsigned int start_pfn, i, bootmap_pfn;
 
-       start_pfn   = PAGE_ALIGN(__pa(&_end)) >> PAGE_SHIFT;
+       start_pfn   = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT;
        bootmap_pfn = 0;
 
        for_each_nodebank(i, mi, node) {
@@ -331,13 +333,12 @@ static void __init bootmem_free_node(int node, struct meminfo *mi)
        free_area_init_node(node, zone_size, start_pfn, zhole_size);
 }
 
-void __init bootmem_init(struct meminfo *mi)
+void __init bootmem_init(void)
 {
+       struct meminfo *mi = &meminfo;
        unsigned long memend_pfn = 0;
        int node, initrd_node;
 
-       memcpy(&meminfo, mi, sizeof(meminfo));
-
        /*
         * Locate which node contains the ramdisk image, if any.
         */
@@ -394,20 +395,22 @@ void __init bootmem_init(struct meminfo *mi)
        max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET;
 }
 
-static inline void free_area(unsigned long addr, unsigned long end, char *s)
+static inline int free_area(unsigned long pfn, unsigned long end, char *s)
 {
-       unsigned int size = (end - addr) >> 10;
+       unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
 
-       for (; addr < end; addr += PAGE_SIZE) {
-               struct page *page = virt_to_page(addr);
+       for (; pfn < end; pfn++) {
+               struct page *page = pfn_to_page(pfn);
                ClearPageReserved(page);
                init_page_count(page);
-               free_page(addr);
-               totalram_pages++;
+               __free_page(page);
+               pages++;
        }
 
        if (size && s)
                printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
+
+       return pages;
 }
 
 static inline void
@@ -478,13 +481,9 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)
  */
 void __init mem_init(void)
 {
-       unsigned int codepages, datapages, initpages;
+       unsigned int codesize, datasize, initsize;
        int i, node;
 
-       codepages = &_etext - &_text;
-       datapages = &_end - &__data_start;
-       initpages = &__init_end - &__init_begin;
-
 #ifndef CONFIG_DISCONTIGMEM
        max_mapnr   = virt_to_page(high_memory) - mem_map;
 #endif
@@ -501,7 +500,8 @@ void __init mem_init(void)
 
 #ifdef CONFIG_SA1111
        /* now that our DMA memory is actually so designated, we can free it */
-       free_area(PAGE_OFFSET, (unsigned long)swapper_pg_dir, NULL);
+       totalram_pages += free_area(PHYS_PFN_OFFSET,
+                                   __phys_to_pfn(__pa(swapper_pg_dir)), NULL);
 #endif
 
        /*
@@ -509,18 +509,21 @@ void __init mem_init(void)
         * real number of pages we have in this system
         */
        printk(KERN_INFO "Memory:");
-
        num_physpages = 0;
        for (i = 0; i < meminfo.nr_banks; i++) {
                num_physpages += bank_pfn_size(&meminfo.bank[i]);
                printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20);
        }
-
        printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
+
+       codesize = _etext - _text;
+       datasize = _end - _data;
+       initsize = __init_end - __init_begin;
+
        printk(KERN_NOTICE "Memory: %luKB available (%dK code, "
                "%dK data, %dK init)\n",
                (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
-               codepages >> 10, datapages >> 10, initpages >> 10);
+               codesize >> 10, datasize >> 10, initsize >> 10);
 
        if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
                extern int sysctl_overcommit_memory;
@@ -535,11 +538,10 @@ void __init mem_init(void)
 
 void free_initmem(void)
 {
-       if (!machine_is_integrator() && !machine_is_cintegrator()) {
-               free_area((unsigned long)(&__init_begin),
-                         (unsigned long)(&__init_end),
-                         "init");
-       }
+       if (!machine_is_integrator() && !machine_is_cintegrator())
+               totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
+                                           __phys_to_pfn(__pa(__init_end)),
+                                           "init");
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -549,7 +551,9 @@ static int keep_initrd;
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (!keep_initrd)
-               free_area(start, end, "initrd");
+               totalram_pages += free_area(__phys_to_pfn(__pa(start)),
+                                           __phys_to_pfn(__pa(end)),
+                                           "initrd");
 }
 
 static int __init keepinitrd_setup(char *__unused)
index 5d9f53907b4eda5eb85741e2330926d96bd57c8f..95bbe112965e1a53953eb2a224c6418805876d7e 100644 (file)
@@ -32,7 +32,5 @@ struct meminfo;
 struct pglist_data;
 
 void __init create_mapping(struct map_desc *md);
-void __init bootmem_init(struct meminfo *mi);
+void __init bootmem_init(void);
 void reserve_node_zero(struct pglist_data *pgdat);
-
-extern void _text, _stext, _etext, __data_start, _end, __init_begin, __init_end;
index 7f36c825718d37e6f424c57d8e81e2547692a0e4..9b36c5cb5e9f68306c017cf63f94ab55ccc1ce3f 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/cputype.h>
 #include <asm/mach-types.h>
+#include <asm/sections.h>
 #include <asm/setup.h>
 #include <asm/sizes.h>
 #include <asm/tlb.h>
@@ -646,61 +647,79 @@ static void __init early_vmalloc(char **arg)
                        "vmalloc area too small, limiting to %luMB\n",
                        vmalloc_reserve >> 20);
        }
+
+       if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {
+               vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);
+               printk(KERN_WARNING
+                       "vmalloc area is too big, limiting to %luMB\n",
+                       vmalloc_reserve >> 20);
+       }
 }
 __early_param("vmalloc=", early_vmalloc);
 
 #define VMALLOC_MIN    (void *)(VMALLOC_END - vmalloc_reserve)
 
-static int __init check_membank_valid(struct membank *mb)
+static void __init sanity_check_meminfo(void)
 {
-       /*
-        * Check whether this memory region has non-zero size or
-        * invalid node number.
-        */
-       if (mb->size == 0 || mb->node >= MAX_NUMNODES)
-               return 0;
-
-       /*
-        * Check whether this memory region would entirely overlap
-        * the vmalloc area.
-        */
-       if (phys_to_virt(mb->start) >= VMALLOC_MIN) {
-               printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
-                       "(vmalloc region overlap).\n",
-                       mb->start, mb->start + mb->size - 1);
-               return 0;
-       }
-
-       /*
-        * Check whether this memory region would partially overlap
-        * the vmalloc area.
-        */
-       if (phys_to_virt(mb->start + mb->size) < phys_to_virt(mb->start) ||
-           phys_to_virt(mb->start + mb->size) > VMALLOC_MIN) {
-               unsigned long newsize = VMALLOC_MIN - phys_to_virt(mb->start);
-
-               printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx "
-                       "to -%.8lx (vmalloc region overlap).\n",
-                       mb->start, mb->start + mb->size - 1,
-                       mb->start + newsize - 1);
-               mb->size = newsize;
-       }
+       int i, j;
 
-       return 1;
-}
+       for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
+               struct membank *bank = &meminfo.bank[j];
+               *bank = meminfo.bank[i];
 
-static void __init sanity_check_meminfo(struct meminfo *mi)
-{
-       int i, j;
+#ifdef CONFIG_HIGHMEM
+               /*
+                * Split those memory banks which are partially overlapping
+                * the vmalloc area greatly simplifying things later.
+                */
+               if (__va(bank->start) < VMALLOC_MIN &&
+                   bank->size > VMALLOC_MIN - __va(bank->start)) {
+                       if (meminfo.nr_banks >= NR_BANKS) {
+                               printk(KERN_CRIT "NR_BANKS too low, "
+                                                "ignoring high memory\n");
+                       } else {
+                               memmove(bank + 1, bank,
+                                       (meminfo.nr_banks - i) * sizeof(*bank));
+                               meminfo.nr_banks++;
+                               i++;
+                               bank[1].size -= VMALLOC_MIN - __va(bank->start);
+                               bank[1].start = __pa(VMALLOC_MIN - 1) + 1;
+                               j++;
+                       }
+                       bank->size = VMALLOC_MIN - __va(bank->start);
+               }
+#else
+               /*
+                * Check whether this memory bank would entirely overlap
+                * the vmalloc area.
+                */
+               if (__va(bank->start) >= VMALLOC_MIN) {
+                       printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
+                              "(vmalloc region overlap).\n",
+                              bank->start, bank->start + bank->size - 1);
+                       continue;
+               }
 
-       for (i = 0, j = 0; i < mi->nr_banks; i++) {
-               if (check_membank_valid(&mi->bank[i]))
-                       mi->bank[j++] = mi->bank[i];
+               /*
+                * Check whether this memory bank would partially overlap
+                * the vmalloc area.
+                */
+               if (__va(bank->start + bank->size) > VMALLOC_MIN ||
+                   __va(bank->start + bank->size) < __va(bank->start)) {
+                       unsigned long newsize = VMALLOC_MIN - __va(bank->start);
+                       printk(KERN_NOTICE "Truncating RAM at %.8lx-%.8lx "
+                              "to -%.8lx (vmalloc region overlap).\n",
+                              bank->start, bank->start + bank->size - 1,
+                              bank->start + newsize - 1);
+                       bank->size = newsize;
+               }
+#endif
+               j++;
        }
-       mi->nr_banks = j;
+       meminfo.nr_banks = j;
 }
 
-static inline void prepare_page_table(struct meminfo *mi)
+static inline void prepare_page_table(void)
 {
        unsigned long addr;
 
@@ -712,7 +731,7 @@ static inline void prepare_page_table(struct meminfo *mi)
 
 #ifdef CONFIG_XIP_KERNEL
        /* The XIP kernel is mapped in the module area -- skip over it */
-       addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
+       addr = ((unsigned long)_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
 #endif
        for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
                pmd_clear(pmd_off_k(addr));
@@ -721,7 +740,7 @@ static inline void prepare_page_table(struct meminfo *mi)
         * Clear out all the kernel space mappings, except for the first
         * memory bank, up to the end of the vmalloc region.
         */
-       for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
+       for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0]));
             addr < VMALLOC_END; addr += PGDIR_SIZE)
                pmd_clear(pmd_off_k(addr));
 }
@@ -738,10 +757,10 @@ void __init reserve_node_zero(pg_data_t *pgdat)
         * Note that this can only be in node 0.
         */
 #ifdef CONFIG_XIP_KERNEL
-       reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start,
+       reserve_bootmem_node(pgdat, __pa(_data), _end - _data,
                        BOOTMEM_DEFAULT);
 #else
-       reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext,
+       reserve_bootmem_node(pgdat, __pa(_stext), _end - _stext,
                        BOOTMEM_DEFAULT);
 #endif
 
@@ -808,7 +827,6 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
         * Allocate the vector page early.
         */
        vectors = alloc_bootmem_low_pages(PAGE_SIZE);
-       BUG_ON(!vectors);
 
        for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
                pmd_clear(pmd_off_k(addr));
@@ -820,7 +838,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
 #ifdef CONFIG_XIP_KERNEL
        map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK);
        map.virtual = MODULES_VADDR;
-       map.length = ((unsigned long)&_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK;
+       map.length = ((unsigned long)_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK;
        map.type = MT_ROM;
        create_mapping(&map);
 #endif
@@ -880,23 +898,23 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
  */
-void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
+void __init paging_init(struct machine_desc *mdesc)
 {
        void *zero_page;
 
        build_mem_type_table();
-       sanity_check_meminfo(mi);
-       prepare_page_table(mi);
-       bootmem_init(mi);
+       sanity_check_meminfo();
+       prepare_page_table();
+       bootmem_init();
        devicemaps_init(mdesc);
 
        top_pmd = pmd_off_k(0xffff0000);
 
        /*
-        * allocate the zero page.  Note that we count on this going ok.
+        * allocate the zero page.  Note that this always succeeds and
+        * returns a zeroed result.
         */
        zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
-       memzero(zero_page, PAGE_SIZE);
        empty_zero_page = virt_to_page(zero_page);
        flush_dcache_page(empty_zero_page);
 }
index 07b62b23897909bca58218aec816e41e7608ab3f..ad7bacc693b2553b3571eee8ee4ec54b1bb44de5 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
+#include <asm/sections.h>
 #include <asm/page.h>
 #include <asm/mach/arch.h>
 
@@ -25,10 +26,10 @@ void __init reserve_node_zero(pg_data_t *pgdat)
         * Note that this can only be in node 0.
         */
 #ifdef CONFIG_XIP_KERNEL
-       reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start,
+       reserve_bootmem_node(pgdat, __pa(_data), _end - _data,
                        BOOTMEM_DEFAULT);
 #else
-       reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext,
+       reserve_bootmem_node(pgdat, __pa(_stext), _end - _stext,
                        BOOTMEM_DEFAULT);
 #endif
 
@@ -41,27 +42,13 @@ void __init reserve_node_zero(pg_data_t *pgdat)
                        BOOTMEM_DEFAULT);
 }
 
-static void __init sanity_check_meminfo(struct meminfo *mi)
-{
-       int i, j;
-
-       for (i = 0, j = 0; i < mi->nr_banks; i++) {
-               struct membank *mb = &mi->bank[i];
-
-               if (mb->size != 0 && mb->node < MAX_NUMNODES)
-                       mi->bank[j++] = mi->bank[i];
-       }
-       mi->nr_banks = j;
-}
-
 /*
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
  */
-void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
+void __init paging_init(struct machine_desc *mdesc)
 {
-       sanity_check_meminfo(mi);
-       bootmem_init(mi);
+       bootmem_init();
 }
 
 /*
index e0f19ab91163e589562d7b070f29d673fc9ef33f..2690146161ba31e01236f6fe6d90d32e7bc76bf4 100644 (file)
@@ -31,7 +31,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
        if (!new_pgd)
                goto no_pgd;
 
-       memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
+       memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 
        /*
         * Copy over the kernel and IO PGD entries
index 2b5ba396e3a63ee455e6b73bfff9176c78aef029..4ad3bf291ad31aa4d4db670a7bda4e3d46e6c3e6 100644 (file)
@@ -33,8 +33,8 @@ EXPORT_SYMBOL(cpu_cache);
 
 #ifdef CONFIG_MMU
 #ifndef MULTI_USER
-EXPORT_SYMBOL(__cpu_clear_user_page);
-EXPORT_SYMBOL(__cpu_copy_user_page);
+EXPORT_SYMBOL(__cpu_clear_user_highpage);
+EXPORT_SYMBOL(__cpu_copy_user_highpage);
 #else
 EXPORT_SYMBOL(cpu_user);
 #endif
index 294943b85973c3df54341885cba4d2470d1af2bc..f0cc599facb747cb5df423242f736cca75f528ab 100644 (file)
@@ -71,6 +71,8 @@ ENTRY(cpu_v6_reset)
  *     IRQs are already disabled.
  */
 ENTRY(cpu_v6_do_idle)
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c10, 4          @ DWB - WFI may enter a low-power mode
        mcr     p15, 0, r1, c7, c0, 4           @ wait for interrupt
        mov     pc, lr
 
index 4d3c0a73e7fb6aea1590f6f9c574521c847e91fe..d1ebec42521df417f97e0bb8d88acae060c17d85 100644 (file)
 
 #define TTB_C          (1 << 0)
 #define TTB_S          (1 << 1)
+#define TTB_RGN_NC     (0 << 3)
+#define TTB_RGN_OC_WBWA        (1 << 3)
 #define TTB_RGN_OC_WT  (2 << 3)
 #define TTB_RGN_OC_WB  (3 << 3)
 
+#ifndef CONFIG_SMP
+#define TTB_FLAGS      TTB_C|TTB_RGN_OC_WB             @ mark PTWs cacheable, outer WB
+#else
+#define TTB_FLAGS      TTB_C|TTB_S|TTB_RGN_OC_WBWA     @ mark PTWs cacheable and shared, outer WBWA
+#endif
+
 ENTRY(cpu_v7_proc_init)
        mov     pc, lr
 ENDPROC(cpu_v7_proc_init)
@@ -55,6 +63,7 @@ ENDPROC(cpu_v7_reset)
  *     IRQs are already disabled.
  */
 ENTRY(cpu_v7_do_idle)
+       dsb                                     @ WFI may enter a low-power mode
        wfi
        mov     pc, lr
 ENDPROC(cpu_v7_do_idle)
@@ -85,7 +94,7 @@ ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_MMU
        mov     r2, #0
        ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
-       orr     r0, r0, #TTB_RGN_OC_WB          @ mark PTWs outer cacheable, WB
+       orr     r0, r0, #TTB_FLAGS
        mcr     p15, 0, r2, c13, c0, 1          @ set reserved context ID
        isb
 1:     mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
@@ -162,6 +171,11 @@ cpu_v7_name:
  *     - cache type register is implemented
  */
 __v7_setup:
+#ifdef CONFIG_SMP
+       mrc     p15, 0, r0, c1, c0, 1           @ Enable SMP/nAMP mode
+       orr     r0, r0, #(0x1 << 6)
+       mcr     p15, 0, r0, c1, c0, 1
+#endif
        adr     r12, __v7_setup_stack           @ the local stack
        stmia   r12, {r0-r5, r7, r9, r11, lr}
        bl      v7_flush_dcache_all
@@ -174,8 +188,7 @@ __v7_setup:
 #ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7, 0          @ invalidate I + D TLBs
        mcr     p15, 0, r10, c2, c0, 2          @ TTB control register
-       orr     r4, r4, #TTB_RGN_OC_WB          @ mark PTWs outer cacheable, WB
-       mcr     p15, 0, r4, c2, c0, 0           @ load TTB0
+       orr     r4, r4, #TTB_FLAGS
        mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
        mov     r10, #0x1f                      @ domains 0, 1 = manager
        mcr     p15, 0, r10, c3, c0, 0          @ load domain access register
index 8f6cf56c11c080fe9027777683bf1f8e39c2d882..33515c214b92d5483e7257adf076be3758332993 100644 (file)
@@ -481,3 +481,28 @@ __xsc3_proc_info:
        .long   xsc3_mc_user_fns
        .long   xsc3_cache_fns
        .size   __xsc3_proc_info, . - __xsc3_proc_info
+
+/* Note: PXA935 changed its implementor ID from Intel to Marvell */
+
+       .type   __xsc3_pxa935_proc_info,#object
+__xsc3_pxa935_proc_info:
+       .long   0x56056000
+       .long   0xffffe000
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_BUFFERABLE | \
+               PMD_SECT_CACHEABLE | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       .long   PMD_TYPE_SECT | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ
+       b       __xsc3_setup
+       .long   cpu_arch_name
+       .long   cpu_elf_name
+       .long   HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+       .long   cpu_xsc3_name
+       .long   xsc3_processor_functions
+       .long   v4wbi_tlb_fns
+       .long   xsc3_mc_user_fns
+       .long   xsc3_cache_fns
+       .size   __xsc3_pxa935_proc_info, . - __xsc3_pxa935_proc_info
index b2a7e3fad117f44c97160c191ab8e34eff66dc0a..9cc2b16fdf793af36302108b4a65588342257e44 100644 (file)
@@ -6,18 +6,27 @@ choice
        prompt "MXC/iMX Base Type"
        default ARCH_MX3
 
+config ARCH_MX1
+       bool "MX1-based"
+       select CPU_ARM920T
+       help
+         This enables support for systems based on the Freescale i.MX1 family
+
 config ARCH_MX2
        bool "MX2-based"
+       select CPU_ARM926T
        help
          This enables support for systems based on the Freescale i.MX2 family
 
 config ARCH_MX3
        bool "MX3-based"
+       select CPU_V6
        help
          This enables support for systems based on the Freescale i.MX3 family
 
 endchoice
 
+source "arch/arm/mach-mx1/Kconfig"
 source "arch/arm/mach-mx2/Kconfig"
 source "arch/arm/mach-mx3/Kconfig"
 
index 067556f7c91f42f4cdd139c82acbbe34346fd7c7..db74a929179d3676b7c82754b72d16136949d974 100644 (file)
@@ -5,4 +5,5 @@
 # Common support
 obj-y := irq.o clock.o gpio.o time.o devices.o
 
+obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o
 obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
index b296f19fd89af0648ab294880b6fb48638583938..2905ec7587589da8bcb599432e1b7b7f19fae5a6 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
 #include <mach/dma-mx1-mx2.h>
 
 #define DMA_DCR     0x00               /* Control Register */
@@ -114,7 +113,7 @@ struct imx_dma_channel {
        void (*err_handler) (int, void *, int errcode);
        void (*prog_handler) (int, void *, struct scatterlist *);
        void *data;
-       dmamode_t  dma_mode;
+       unsigned int  dma_mode;
        struct scatterlist *sg;
        unsigned int resbytes;
        int dma_num;
@@ -193,7 +192,7 @@ static inline int imx_dma_sg_next(int channel, struct scatterlist *sg)
 int
 imx_dma_setup_single(int channel, dma_addr_t dma_address,
                     unsigned int dma_length, unsigned int dev_addr,
-                    dmamode_t dmamode)
+                    unsigned int dmamode)
 {
        struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
 
@@ -288,7 +287,7 @@ int
 imx_dma_setup_sg(int channel,
                 struct scatterlist *sg, unsigned int sgcount,
                 unsigned int dma_length, unsigned int dev_addr,
-                dmamode_t dmamode)
+                unsigned int dmamode)
 {
        struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
 
@@ -512,6 +511,7 @@ void imx_dma_disable(int channel)
 }
 EXPORT_SYMBOL(imx_dma_disable);
 
+#ifdef CONFIG_ARCH_MX2
 static void imx_dma_watchdog(unsigned long chno)
 {
        struct imx_dma_channel *imxdma = &imx_dma_channels[chno];
@@ -523,6 +523,7 @@ static void imx_dma_watchdog(unsigned long chno)
        if (imxdma->err_handler)
                imxdma->err_handler(chno, imxdma->data, IMX_DMA_ERR_TIMEOUT);
 }
+#endif
 
 static irqreturn_t dma_err_handler(int irq, void *dev_id)
 {
@@ -675,7 +676,7 @@ int imx_dma_request(int channel, const char *name)
 {
        struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
        unsigned long flags;
-       int ret;
+       int ret = 0;
 
        /* basic sanity checks */
        if (!name)
@@ -697,6 +698,7 @@ int imx_dma_request(int channel, const char *name)
        ret = request_irq(MXC_INT_DMACH0 + channel, dma_irq_handler, 0, "DMA",
                        NULL);
        if (ret) {
+               local_irq_restore(flags);
                printk(KERN_CRIT "Can't register IRQ %d for DMA channel %d\n",
                                MXC_INT_DMACH0 + channel, channel);
                return ret;
@@ -713,7 +715,7 @@ int imx_dma_request(int channel, const char *name)
        imxdma->sg = NULL;
 
        local_irq_restore(flags);
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(imx_dma_request);
 
index de5c4747453fbedaf476fd3043a857fe8a1ee6c3..ccbd94adc668154ff58dbe19c90f8462d2ce6cca 100644 (file)
@@ -115,8 +115,8 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat)
        }
 }
 
-#ifdef CONFIG_ARCH_MX3
-/* MX3 has one interrupt *per* gpio port */
+#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1)
+/* MX1 and MX3 has one interrupt *per* gpio port */
 static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
 {
        u32 irq_stat;
@@ -237,7 +237,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt)
                /* its a serious configuration bug when it fails */
                BUG_ON( gpiochip_add(&port[i].chip) < 0 );
 
-#ifdef CONFIG_ARCH_MX3
+#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1)
                /* setup one handler for each entry */
                set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler);
                set_irq_data(port[i].irq, &port[i]);
index 61e66dac90efbce6a8c700820b3edebfa082a9f0..8f34a05afc87a6c5717550a9d517716554264672 100644 (file)
@@ -15,7 +15,7 @@
 #define __ASM_ARCH_MXC_BOARD_MX27ADS_H__
 
 /* external interrupt multiplexer */
-#define MXC_EXP_IO_BASE                (MXC_GPIO_BASE + MXC_MAX_GPIO_LINES)
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
 
 #define MXC_VIRTUAL_INTS_BASE  (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES)
 #define MXC_SDIO1_CARD_IRQ     MXC_VIRTUAL_INTS_BASE
 /*
  * MXC UART EVB board level configurations
  */
-
-#define MXC_LL_EXTUART_PADDR   (CS4_BASE_ADDR + 0x20000)
-#define MXC_LL_EXTUART_VADDR   (CS4_BASE_ADDR_VIRT + 0x20000)
-#define MXC_LL_EXTUART_16BIT_BUS
-
 #define MXC_LL_UART_PADDR       UART1_BASE_ADDR
 #define MXC_LL_UART_VADDR       AIPI_IO_ADDRESS(UART1_BASE_ADDR)
 
index 745b48864f930f95b268d1706132fd3cbfbfe0fb..451d510d08c353692b86507f68e55657bb098ec3 100644 (file)
@@ -90,7 +90,7 @@
 #define PBC_INTMASK_CLEAR_REG  (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
 #define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
 
-#define MXC_EXP_IO_BASE                (MXC_MAX_INT_LINES + MXC_MAX_GPIO_LINES)
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
 #define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
 
 #define EXPIO_INT_LOW_BAT      (MXC_EXP_IO_BASE + 0)
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31pdk.h b/arch/arm/plat-mxc/include/mach/board-mx31pdk.h
new file mode 100644 (file)
index 0000000..2b6b316
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can 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_MXC_BOARD_MX31PDK_H__
+#define __ASM_ARCH_MXC_BOARD_MX31PDK_H__
+
+/* mandatory for CONFIG_LL_DEBUG */
+
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      AIPS1_IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX31PDK_H__ */
index b9907bebba3bab9acc3f63693120fda3b6604ff1..602768b427e2444f4f8f12154e12d67a19a0342a 100644 (file)
@@ -27,6 +27,9 @@
 #endif
 #ifdef CONFIG_MACH_PCM038
 #include <mach/board-pcm038.h>
+#endif
+#ifdef CONFIG_MACH_MX31_3DS
+#include <mach/board-mx31pdk.h>
 #endif
                .macro  addruart,rx
                mrc     p15, 0, \rx, c1, c0
index e85fd946116c1cbaf5eb412a0f25d98129c8af68..b3876cc238cadbd27b13f97f0d3ce8f8e879e3f2 100644 (file)
  * MA 02110-1301, USA.
  */
 
-#include <asm/dma.h>
-
 #ifndef __ASM_ARCH_MXC_DMA_H
 #define __ASM_ARCH_MXC_DMA_H
 
 #define IMX_DMA_CHANNELS  16
 
+#define DMA_MODE_READ          0
+#define DMA_MODE_WRITE         1
+#define DMA_MODE_MASK          1
+
 #define DMA_BASE IO_ADDRESS(DMA_BASE_ADDR)
 
 #define IMX_DMA_MEMSIZE_32     (0 << 4)
@@ -54,12 +56,12 @@ imx_dma_config_burstlen(int channel, unsigned int burstlen);
 int
 imx_dma_setup_single(int channel, dma_addr_t dma_address,
                unsigned int dma_length, unsigned int dev_addr,
-               dmamode_t dmamode);
+               unsigned int dmamode);
 
 int
 imx_dma_setup_sg(int channel, struct scatterlist *sg,
                unsigned int sgcount, unsigned int dma_length,
-               unsigned int dev_addr, dmamode_t dmamode);
+               unsigned int dev_addr, unsigned int dmamode);
 
 int
 imx_dma_setup_handlers(int channel,
diff --git a/arch/arm/plat-mxc/include/mach/dma.h b/arch/arm/plat-mxc/include/mach/dma.h
deleted file mode 100644 (file)
index c822d56..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- */
-
-/*
- * This program is free software; you can 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_MXC_DMA_H__
-#define __ASM_ARCH_MXC_DMA_H__
-
-#endif
index 11632028f7d1ba6f44610c373b52b2721ea81cf4..5f01d60da8457920e2db1208f6c249f5ef826412 100644 (file)
@@ -9,6 +9,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <mach/hardware.h>
+
 #define AVIC_NIMASK    0x04
 
        @ this macro disables fast irq (not implemented)
index 65eedc0d196fcfcd0b7c00bc29024b4ffef3c1d0..ea509f1090fb80a608477f4992d238c1b1b0bb84 100644 (file)
@@ -27,8 +27,8 @@
 #define gpio_set_value         __gpio_set_value
 #define gpio_cansleep          __gpio_cansleep
 
-#define gpio_to_irq(gpio)      (MXC_MAX_INT_LINES + (gpio))
-#define irq_to_gpio(irq)       ((irq) - MXC_MAX_INT_LINES)
+#define gpio_to_irq(gpio)      (MXC_GPIO_IRQ_START + (gpio))
+#define irq_to_gpio(irq)       ((irq) - MXC_GPIO_IRQ_START)
 
 struct mxc_gpio_port {
        void __iomem *base;
index 3caadeeda701165b8a693a6bd95f10b6034e34d0..a612d8bb73c80f7a8ab72dccca601bf6c18df0ce 100644 (file)
 # endif
 #endif
 
+#ifdef CONFIG_ARCH_MX1
+# include <mach/mx1.h>
+#endif
+
 #include <mach/mxc.h>
 
 #endif /* __ASM_ARCH_MXC_HARDWARE_H__ */
index 5d4cb11964411ce924cbb44392cd7788f07defe2..b4f2de7694667a9c81158ddedb92f8eda351ed18 100644 (file)
@@ -25,8 +25,8 @@ __mx3_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
                /* Access all peripherals below 0x80000000 as nonshared device
                 * but leave l2cc alone.
                 */
-               if ((phys_addr < 0x80000000) && ((phys_addr < L2CC_BASE_ADDR) ||
-                       (phys_addr >= L2CC_BASE_ADDR + L2CC_SIZE)))
+               if ((phys_addr < 0x80000000) && ((phys_addr < 0x30000000) ||
+                       (phys_addr >= 0x30000000 + SZ_1M)))
                        mtype = MT_DEVICE_NONSHARED;
        }
 
@@ -35,8 +35,8 @@ __mx3_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
 #endif
 
 /* io address mapping macro */
-#define __io(a)                        ((void __iomem *)(a))
+#define __io(a)                __typesafe_io(a)
 
-#define __mem_pci(a)           (a)
+#define __mem_pci(a)   (a)
 
 #endif
index 3d09bfd6c53df8402a6c7033f2ba3b3805afcc3f..95a383be628e97d4508d6beb76a394014508d437 100644 (file)
 
 #include <linux/io.h>
 
-#define MXC_GPIO_ALLOC_MODE_NORMAL     0
-#define MXC_GPIO_ALLOC_MODE_NO_ALLOC   1
-#define MXC_GPIO_ALLOC_MODE_TRY_ALLOC  2
-#define MXC_GPIO_ALLOC_MODE_ALLOC_ONLY 4
-#define MXC_GPIO_ALLOC_MODE_RELEASE    8
-
 /*
  *  GPIO Module and I/O Multiplexer
  *  x = 0..3 for reg_A, reg_B, reg_C, reg_D
 
 extern void mxc_gpio_mode(int gpio_mode);
 extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
-                                       int alloc_mode, const char *label);
+                                       const char *label);
+extern void mxc_gpio_release_multiple_pins(const int *pin_list, int count);
 
 /*-------------------------------------------------------------------------*/
 
@@ -113,9 +108,9 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
  * missing on some (many) pins
  */
 #ifdef CONFIG_ARCH_MX1
-#define PA0_AIN_SPI2_CLK     (GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 0)
+#define PA0_AIN_SPI2_CLK     (GPIO_PORTA | GPIO_OUT | 0)
 #define PA0_AF_ETMTRACESYNC  (GPIO_PORTA | GPIO_AF | 0)
-#define PA1_AOUT_SPI2_RXD    (GPIO_GIUS | GPIO_PORTA | GPIO_IN | 1)
+#define PA1_AOUT_SPI2_RXD    (GPIO_PORTA | GPIO_IN | 1)
 #define PA1_PF_TIN           (GPIO_PORTA | GPIO_PF | 1)
 #define PA2_PF_PWM0          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 2)
 #define PA3_PF_CSI_MCLK      (GPIO_PORTA | GPIO_PF | 3)
@@ -133,7 +128,7 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PA15_PF_I2C_SDA      (GPIO_PORTA | GPIO_OUT | GPIO_PF | 15)
 #define PA16_PF_I2C_SCL      (GPIO_PORTA | GPIO_OUT | GPIO_PF | 16)
 #define PA17_AF_ETMTRACEPKT4 (GPIO_PORTA | GPIO_AF | 17)
-#define PA17_AIN_SPI2_SS     (GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 17)
+#define PA17_AIN_SPI2_SS     (GPIO_PORTA | GPIO_OUT | 17)
 #define PA18_AF_ETMTRACEPKT5 (GPIO_PORTA | GPIO_AF | 18)
 #define PA19_AF_ETMTRACEPKT6 (GPIO_PORTA | GPIO_AF | 19)
 #define PA20_AF_ETMTRACEPKT7 (GPIO_PORTA | GPIO_AF | 20)
@@ -201,27 +196,27 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PC15_PF_SPI1_SS      (GPIO_PORTC | GPIO_PF | 15)
 #define PC16_PF_SPI1_MISO    (GPIO_PORTC | GPIO_PF | 16)
 #define PC17_PF_SPI1_MOSI    (GPIO_PORTC | GPIO_PF | 17)
-#define PC24_BIN_UART3_RI    (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 24)
-#define PC25_BIN_UART3_DSR   (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 25)
-#define PC26_AOUT_UART3_DTR  (GPIO_GIUS | GPIO_PORTC | GPIO_IN | 26)
-#define PC27_BIN_UART3_DCD   (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 27)
-#define PC28_BIN_UART3_CTS   (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 28)
-#define PC29_AOUT_UART3_RTS  (GPIO_GIUS | GPIO_PORTC | GPIO_IN | 29)
-#define PC30_BIN_UART3_TX    (GPIO_GIUS | GPIO_PORTC | GPIO_BIN | 30)
-#define PC31_AOUT_UART3_RX   (GPIO_GIUS | GPIO_PORTC | GPIO_IN | 31)
+#define PC24_BIN_UART3_RI    (GPIO_PORTC | GPIO_OUT | GPIO_BIN | 24)
+#define PC25_BIN_UART3_DSR   (GPIO_PORTC | GPIO_OUT | GPIO_BIN | 25)
+#define PC26_AOUT_UART3_DTR  (GPIO_PORTC | GPIO_IN | 26)
+#define PC27_BIN_UART3_DCD   (GPIO_PORTC | GPIO_OUT | GPIO_BIN | 27)
+#define PC28_BIN_UART3_CTS   (GPIO_PORTC | GPIO_OUT | GPIO_BIN | 28)
+#define PC29_AOUT_UART3_RTS  (GPIO_PORTC | GPIO_IN | 29)
+#define PC30_BIN_UART3_TX    (GPIO_PORTC | GPIO_BIN | 30)
+#define PC31_AOUT_UART3_RX   (GPIO_PORTC | GPIO_IN | 31)
 #define PD6_PF_LSCLK         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 6)
 #define PD7_PF_REV           (GPIO_PORTD | GPIO_PF | 7)
-#define PD7_AF_UART2_DTR     (GPIO_GIUS | GPIO_PORTD | GPIO_IN | GPIO_AF | 7)
-#define PD7_AIN_SPI2_SCLK    (GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 7)
+#define PD7_AF_UART2_DTR     (GPIO_PORTD | GPIO_IN | GPIO_AF | 7)
+#define PD7_AIN_SPI2_SCLK    (GPIO_PORTD | GPIO_AIN | 7)
 #define PD8_PF_CLS           (GPIO_PORTD | GPIO_PF | 8)
 #define PD8_AF_UART2_DCD     (GPIO_PORTD | GPIO_OUT | GPIO_AF | 8)
-#define PD8_AIN_SPI2_SS      (GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 8)
+#define PD8_AIN_SPI2_SS      (GPIO_PORTD | GPIO_AIN | 8)
 #define PD9_PF_PS            (GPIO_PORTD | GPIO_PF | 9)
 #define PD9_AF_UART2_RI      (GPIO_PORTD | GPIO_OUT | GPIO_AF | 9)
-#define PD9_AOUT_SPI2_RXD    (GPIO_GIUS | GPIO_PORTD | GPIO_IN | 9)
+#define PD9_AOUT_SPI2_RXD    (GPIO_PORTD | GPIO_IN | 9)
 #define PD10_PF_SPL_SPR      (GPIO_PORTD | GPIO_OUT | GPIO_PF | 10)
 #define PD10_AF_UART2_DSR    (GPIO_PORTD | GPIO_OUT | GPIO_AF | 10)
-#define PD10_AIN_SPI2_TXD    (GPIO_GIUS | GPIO_PORTD | GPIO_OUT | 10)
+#define PD10_AIN_SPI2_TXD    (GPIO_PORTD | GPIO_OUT | 10)
 #define PD11_PF_CONTRAST     (GPIO_PORTD | GPIO_OUT | GPIO_PF | 11)
 #define PD12_PF_ACD_OE       (GPIO_PORTD | GPIO_OUT | GPIO_PF | 12)
 #define PD13_PF_LP_HSYNC     (GPIO_PORTD | GPIO_OUT | GPIO_PF | 13)
@@ -243,7 +238,7 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PD29_PF_LD14         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 29)
 #define PD30_PF_LD15         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 30)
 #define PD31_PF_TMR2OUT      (GPIO_PORTD | GPIO_PF | 31)
-#define PD31_BIN_SPI2_TXD    (GPIO_GIUS | GPIO_PORTD | GPIO_BIN | 31)
+#define PD31_BIN_SPI2_TXD    (GPIO_PORTD | GPIO_BIN | 31)
 #endif
 
 #ifdef CONFIG_ARCH_MX2
@@ -279,6 +274,12 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PA29_PF_VSYNC          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 29)
 #define PA30_PF_CONTRAST       (GPIO_PORTA | GPIO_OUT | GPIO_PF | 30)
 #define PA31_PF_OE_ACD         (GPIO_PORTA | GPIO_OUT | GPIO_PF | 31)
+#define PB4_PF_SD2_D0          (GPIO_PORTB | GPIO_PF |  4)
+#define PB5_PF_SD2_D1          (GPIO_PORTB | GPIO_PF |  5)
+#define PB6_PF_SD2_D2          (GPIO_PORTB | GPIO_PF |  6)
+#define PB7_PF_SD2_D3          (GPIO_PORTB | GPIO_PF |  7)
+#define PB8_PF_SD2_CMD         (GPIO_PORTB | GPIO_PF |  8)
+#define PB9_PF_SD2_CLK         (GPIO_PORTB | GPIO_PF |  9)
 #define PB10_PF_CSI_D0         (GPIO_PORTB | GPIO_OUT | GPIO_PF | 10)
 #define PB10_AF_UART6_TXD      (GPIO_PORTB | GPIO_OUT | GPIO_AF | 10)
 #define PB11_PF_CSI_D1         (GPIO_PORTB | GPIO_OUT | GPIO_PF | 11)
@@ -315,6 +316,13 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PB31_AF_UART4_RXD      (GPIO_PORTB | GPIO_IN  | GPIO_AF | 31)
 #define PC5_PF_I2C2_SDA                (GPIO_PORTC | GPIO_IN  | GPIO_PF | 5)
 #define PC6_PF_I2C2_SCL                (GPIO_PORTC | GPIO_IN  | GPIO_PF | 6)
+#define PC7_PF_USBOTG_DATA5    (GPIO_PORTC | GPIO_OUT | GPIO_PF | 7)
+#define PC8_PF_USBOTG_DATA6    (GPIO_PORTC | GPIO_OUT | GPIO_PF | 8)
+#define PC9_PF_USBOTG_DATA0    (GPIO_PORTC | GPIO_OUT | GPIO_PF | 9)
+#define PC10_PF_USBOTG_DATA2   (GPIO_PORTC | GPIO_OUT | GPIO_PF | 10)
+#define PC11_PF_USBOTG_DATA1   (GPIO_PORTC | GPIO_OUT | GPIO_PF | 11)
+#define PC12_PF_USBOTG_DATA4   (GPIO_PORTC | GPIO_OUT | GPIO_PF | 12)
+#define PC13_PF_USBOTG_DATA3   (GPIO_PORTC | GPIO_OUT | GPIO_PF | 13)
 #define PC16_PF_SSI4_FS                (GPIO_PORTC | GPIO_IN  | GPIO_PF | 16)
 #define PC17_PF_SSI4_RXD       (GPIO_PORTC | GPIO_IN  | GPIO_PF | 17)
 #define PC18_PF_SSI4_TXD       (GPIO_PORTC | GPIO_IN  | GPIO_PF | 18)
@@ -365,6 +373,9 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PD30_PF_CSPI1_MISO     (GPIO_PORTD | GPIO_IN | GPIO_PF  | 30)
 #define PD31_PF_CSPI1_MOSI     (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 31)
 #define PF23_AIN_FEC_TX_EN     (GPIO_PORTF | GPIO_OUT | GPIO_AIN | 23)
+#define PE0_PF_USBOTG_NXT      (GPIO_PORTE | GPIO_OUT | GPIO_PF | 0)
+#define PE1_PF_USBOTG_STP      (GPIO_PORTE | GPIO_OUT | GPIO_PF | 1)
+#define PE2_PF_USBOTG_DIR      (GPIO_PORTE | GPIO_OUT | GPIO_PF | 2)
 #define PE3_PF_UART2_CTS       (GPIO_PORTE | GPIO_OUT | GPIO_PF | 3)
 #define PE4_PF_UART2_RTS       (GPIO_PORTE | GPIO_IN  | GPIO_PF | 4)
 #define PE6_PF_UART2_TXD       (GPIO_PORTE | GPIO_OUT | GPIO_PF | 6)
@@ -379,18 +390,27 @@ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
 #define PE15_PF_UART1_RTS      (GPIO_PORTE | GPIO_IN  | GPIO_PF | 15)
 #define PE16_AF_RTCK           (GPIO_PORTE | GPIO_OUT | GPIO_AF | 16)
 #define PE16_PF_RTCK           (GPIO_PORTE | GPIO_OUT | GPIO_PF | 16)
+#define PE18_PF_SDHC1_D0       (GPIO_PORTE | GPIO_PF | 18)
 #define PE18_AF_CSPI3_MISO     (GPIO_PORTE | GPIO_IN  | GPIO_AF | 18)
+#define PE19_PF_SDHC1_D1       (GPIO_PORTE | GPIO_PF | 19)
+#define PE20_PF_SDHC1_D2       (GPIO_PORTE | GPIO_PF | 20)
+#define PE21_PF_SDHC1_D3       (GPIO_PORTE | GPIO_PF | 21)
 #define PE21_AF_CSPI3_SS       (GPIO_PORTE | GPIO_OUT | GPIO_AF | 21)
+#define PE22_PF_SDHC1_CMD      (GPIO_PORTE | GPIO_PF | 22)
 #define PE22_AF_CSPI3_MOSI     (GPIO_PORTE | GPIO_OUT | GPIO_AF | 22)
+#define PE22_PF_SDHC1_CLK      (GPIO_PORTE | GPIO_PF | 23)
 #define PE23_AF_CSPI3_SCLK     (GPIO_PORTE | GPIO_OUT | GPIO_AF | 23)
+#define PE24_PF_USBOTG_CLK     (GPIO_PORTE | GPIO_OUT | GPIO_PF | 24)
+#define PE25_PF_USBOTG_DATA7   (GPIO_PORTE | GPIO_OUT | GPIO_PF | 25)
 #endif
 
 /* decode irq number to use with IMR(x), ISR(x) and friends */
-#define IRQ_TO_REG(irq) ((irq - MXC_MAX_INT_LINES) >> 5)
+#define IRQ_TO_REG(irq) ((irq - MXC_INTERNAL_IRQS) >> 5)
 
-#define IRQ_GPIOA(x)  (MXC_MAX_INT_LINES + x)
+#define IRQ_GPIOA(x)  (MXC_GPIO_IRQ_START + x)
 #define IRQ_GPIOB(x)  (IRQ_GPIOA(32) + x)
 #define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
 #define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
+#define IRQ_GPIOE(x)  (IRQ_GPIOD(32) + x)
 
 #endif /* _MXC_GPIO_MX1_MX2_H */
index c9f39c2fb8c64083e437fe91c85f6cbad686a77b..c9198c0aea1827a10580a492512bee7de200f1fe 100644 (file)
@@ -141,7 +141,7 @@ void mxc_iomux_set_gpr(enum iomux_gp_func, bool);
        ((iomux_pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT)
 #define IOMUX_TO_IRQ(iomux_pin) \
        (((iomux_pin & IOMUX_GPIONUM_MASK) >> IOMUX_GPIONUM_SHIFT) + \
-       MXC_GPIO_INT_BASE)
+       MXC_GPIO_IRQ_START)
 
 /*
  * This enumeration is constructed based on the Section
@@ -491,6 +491,14 @@ enum iomux_pins {
 #define MX31_PIN_RTS1__RTS1            IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_TXD1__TXD1            IOMUX_MODE(MX31_PIN_TXD1, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_RXD1__RXD1            IOMUX_MODE(MX31_PIN_RXD1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CTS2__CTS2            IOMUX_MODE(MX31_PIN_CTS2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_RTS2__RTS2            IOMUX_MODE(MX31_PIN_RTS2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_TXD2__TXD2            IOMUX_MODE(MX31_PIN_TXD2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_RXD2__RXD2            IOMUX_MODE(MX31_PIN_RXD2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_PC_RST__CTS5          IOMUX_MODE(MX31_PIN_PC_RST, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_PC_VS2__RTS5          IOMUX_MODE(MX31_PIN_PC_VS2, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_PC_BVD2__TXD5         IOMUX_MODE(MX31_PIN_PC_BVD2, IOMUX_CONFIG_ALT2)
+#define MX31_PIN_PC_BVD1__RXD5         IOMUX_MODE(MX31_PIN_PC_BVD1, IOMUX_CONFIG_ALT2)
 #define MX31_PIN_CSPI1_MOSI__MOSI      IOMUX_MODE(MX31_PIN_CSPI1_MOSI, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CSPI1_MISO__MISO      IOMUX_MODE(MX31_PIN_CSPI1_MISO, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CSPI1_SCLK__SCLK      IOMUX_MODE(MX31_PIN_CSPI1_SCLK, IOMUX_CONFIG_FUNC)
@@ -509,6 +517,15 @@ enum iomux_pins {
 #define MX31_PIN_CSPI3_MISO__MISO      IOMUX_MODE(MX31_PIN_CSPI3_MISO, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CSPI3_SCLK__SCLK      IOMUX_MODE(MX31_PIN_CSPI3_SCLK, IOMUX_CONFIG_FUNC)
 #define MX31_PIN_CSPI3_SPI_RDY__SPI_RDY        IOMUX_MODE(MX31_PIN_CSPI3_SPI_RDY, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_BATT_LINE__OWIRE      IOMUX_MODE(MX31_PIN_BATT_LINE, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_CS4__CS4              IOMUX_MODE(MX31_PIN_CS4, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SD1_DATA3__SD1_DATA3  IOMUX_MODE(MX31_PIN_SD1_DATA3, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SD1_DATA2__SD1_DATA2  IOMUX_MODE(MX31_PIN_SD1_DATA2, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SD1_DATA1__SD1_DATA1  IOMUX_MODE(MX31_PIN_SD1_DATA1, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SD1_DATA0__SD1_DATA0  IOMUX_MODE(MX31_PIN_SD1_DATA0, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SD1_CLK__SD1_CLK      IOMUX_MODE(MX31_PIN_SD1_CLK, IOMUX_CONFIG_FUNC)
+#define MX31_PIN_SD1_CMD__SD1_CMD      IOMUX_MODE(MX31_PIN_SD1_CMD, IOMUX_CONFIG_FUNC)
+
 /*XXX: The SS0, SS1, SS2, SS3 lines of spi3 are multiplexed by cspi2_ss0, cspi2_ss1, cspi1_ss0
  * cspi1_ss1*/
 
index b55bba35e18a83e002bceb3d45835b3aa8ee9f3c..e06d3cb0ee1143ff278771beccd259157ace2c05 100644 (file)
 #ifndef __ASM_ARCH_MXC_IRQS_H__
 #define __ASM_ARCH_MXC_IRQS_H__
 
-#include <mach/hardware.h>
+/*
+ * So far all i.MX SoCs have 64 internal interrupts
+ */
+#define MXC_INTERNAL_IRQS      64
+
+#define MXC_GPIO_IRQ_START     MXC_INTERNAL_IRQS
+
+#if defined CONFIG_ARCH_MX1
+#define MXC_GPIO_IRQS          (32 * 4)
+#elif defined CONFIG_ARCH_MX2
+#define MXC_GPIO_IRQS          (32 * 6)
+#elif defined CONFIG_ARCH_MX3
+#define MXC_GPIO_IRQS          (32 * 3)
+#endif
+
+/*
+ * The next 16 interrupts are for board specific purposes.  Since
+ * the kernel can only run on one machine at a time, we can re-use
+ * these.  If you need more, increase MXC_BOARD_IRQS, but keep it
+ * within sensible limits.
+ */
+#define MXC_BOARD_IRQ_START    (MXC_INTERNAL_IRQS + MXC_GPIO_IRQS)
+#define MXC_BOARD_IRQS 16
+
+#define NR_IRQS                (MXC_BOARD_IRQ_START + MXC_BOARD_IRQS)
+
 extern void imx_irq_set_priority(unsigned char irq, unsigned char prio);
 
+/* all normal IRQs can be FIQs */
+#define FIQ_START      0
+/* switch betwean IRQ and FIQ */
+extern int mxc_set_irq_fiq(unsigned int irq, unsigned int type);
+
 #endif /* __ASM_ARCH_MXC_IRQS_H__ */
index d7a8d3ebed576c8af5a88cdfe5c9ad9e90a7735a..0b808399097fe25459334f037c185e8b62e86d5f 100644 (file)
 #ifndef __ASM_ARCH_MXC_MEMORY_H__
 #define __ASM_ARCH_MXC_MEMORY_H__
 
-#include <mach/hardware.h>
-
-/*
- * Virtual view <-> DMA view memory address translations
- * This macro is used to translate the virtual address to an address
- * suitable to be passed to set_dma_addr()
- */
-#define __virt_to_bus(a)       __virt_to_phys(a)
-
-/*
- * Used to convert an address for DMA operations to an address that the
- * kernel can use.
- */
-#define __bus_to_virt(a)       __phys_to_virt(a)
+#if defined CONFIG_ARCH_MX1
+#define PHYS_OFFSET            UL(0x08000000)
+#elif defined CONFIG_ARCH_MX2
+#define PHYS_OFFSET            UL(0xA0000000)
+#elif defined CONFIG_ARCH_MX3
+#define PHYS_OFFSET            UL(0x80000000)
+#endif
 
 #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mtd-xip.h b/arch/arm/plat-mxc/include/mach/mtd-xip.h
new file mode 100644 (file)
index 0000000..1ab1bba
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * MTD primitives for XIP support. Architecture specific functions
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Copyright (C) 2008 Darius Augulis <augulis.darius@gmail.com>, Teltonika, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <mach/mxc_timer.h>
+
+#ifndef __ARCH_IMX_MTD_XIP_H__
+#define __ARCH_IMX_MTD_XIP_H__
+
+#ifdef CONFIG_ARCH_MX1
+/* AITC registers */
+#define AITC_BASE      IO_ADDRESS(AVIC_BASE_ADDR)
+#define NIPNDH         (AITC_BASE + 0x58)
+#define NIPNDL         (AITC_BASE + 0x5C)
+#define INTENABLEH     (AITC_BASE + 0x10)
+#define INTENABLEL     (AITC_BASE + 0x14)
+/* MTD macros */
+#define xip_irqpending() ((__raw_readl(INTENABLEH) &  __raw_readl(NIPNDH)) \
+                       || (__raw_readl(INTENABLEL) &  __raw_readl(NIPNDL)))
+#define xip_currtime()         (__raw_readl(TIMER_BASE + MXC_TCN))
+#define xip_elapsed_since(x)   (signed)((__raw_readl(TIMER_BASE + MXC_TCN) - (x)) / 96)
+#define xip_cpu_idle()         asm volatile ("mcr p15, 0, %0, c7, c0, 4" :: "r" (0))
+#endif /* CONFIG_ARCH_MX1 */
+
+#endif /* __ARCH_IMX_MTD_XIP_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mx1.h b/arch/arm/plat-mxc/include/mach/mx1.h
new file mode 100644 (file)
index 0000000..b92e023
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 1997,1998 Russell King
+ * Copyright (C) 1999 ARM Limited
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This program is free software; you can 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_MXC_MX1_H__
+#define __ASM_ARCH_MXC_MX1_H__
+
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#error "Do not include directly."
+#endif
+
+#include <mach/vmalloc.h>
+
+/*
+ * Memory map
+ */
+#define IMX_IO_PHYS    0x00200000
+#define IMX_IO_SIZE    0x00100000
+#define IMX_IO_BASE    VMALLOC_END
+
+#define IMX_CS0_PHYS   0x10000000
+#define IMX_CS0_SIZE   0x02000000
+
+#define IMX_CS1_PHYS   0x12000000
+#define IMX_CS1_SIZE   0x01000000
+
+#define IMX_CS2_PHYS   0x13000000
+#define IMX_CS2_SIZE   0x01000000
+
+#define IMX_CS3_PHYS   0x14000000
+#define IMX_CS3_SIZE   0x01000000
+
+#define IMX_CS4_PHYS   0x15000000
+#define IMX_CS4_SIZE   0x01000000
+
+#define IMX_CS5_PHYS   0x16000000
+#define IMX_CS5_SIZE   0x01000000
+
+/*
+ *  Register BASEs, based on OFFSETs
+ */
+#define AIPI1_BASE_ADDR                (0x00000 + IMX_IO_PHYS)
+#define WDT_BASE_ADDR          (0x01000 + IMX_IO_PHYS)
+#define TIM1_BASE_ADDR         (0x02000 + IMX_IO_PHYS)
+#define TIM2_BASE_ADDR         (0x03000 + IMX_IO_PHYS)
+#define RTC_BASE_ADDR          (0x04000 + IMX_IO_PHYS)
+#define LCDC_BASE_ADDR         (0x05000 + IMX_IO_PHYS)
+#define UART1_BASE_ADDR                (0x06000 + IMX_IO_PHYS)
+#define UART2_BASE_ADDR                (0x07000 + IMX_IO_PHYS)
+#define PWM_BASE_ADDR          (0x08000 + IMX_IO_PHYS)
+#define DMA_BASE_ADDR          (0x09000 + IMX_IO_PHYS)
+#define AIPI2_BASE_ADDR                (0x10000 + IMX_IO_PHYS)
+#define SIM_BASE_ADDR          (0x11000 + IMX_IO_PHYS)
+#define USBD_BASE_ADDR         (0x12000 + IMX_IO_PHYS)
+#define SPI1_BASE_ADDR         (0x13000 + IMX_IO_PHYS)
+#define MMC_BASE_ADDR          (0x14000 + IMX_IO_PHYS)
+#define ASP_BASE_ADDR          (0x15000 + IMX_IO_PHYS)
+#define BTA_BASE_ADDR          (0x16000 + IMX_IO_PHYS)
+#define I2C_BASE_ADDR          (0x17000 + IMX_IO_PHYS)
+#define SSI_BASE_ADDR          (0x18000 + IMX_IO_PHYS)
+#define SPI2_BASE_ADDR         (0x19000 + IMX_IO_PHYS)
+#define MSHC_BASE_ADDR         (0x1A000 + IMX_IO_PHYS)
+#define CCM_BASE_ADDR          (0x1B000 + IMX_IO_PHYS)
+#define SCM_BASE_ADDR          (0x1B804 + IMX_IO_PHYS)
+#define GPIO_BASE_ADDR         (0x1C000 + IMX_IO_PHYS)
+#define EIM_BASE_ADDR          (0x20000 + IMX_IO_PHYS)
+#define SDRAMC_BASE_ADDR       (0x21000 + IMX_IO_PHYS)
+#define MMA_BASE_ADDR          (0x22000 + IMX_IO_PHYS)
+#define AVIC_BASE_ADDR         (0x23000 + IMX_IO_PHYS)
+#define CSI_BASE_ADDR          (0x24000 + IMX_IO_PHYS)
+
+/* macro to get at IO space when running virtually */
+#define IO_ADDRESS(x)  ((x) - IMX_IO_PHYS + IMX_IO_BASE)
+
+/* define macros needed for entry-macro.S */
+#define AVIC_IO_ADDRESS(x)     IO_ADDRESS(x)
+
+/* fixed interrput numbers */
+#define INT_SOFTINT            0
+#define CSI_INT                        6
+#define DSPA_MAC_INT           7
+#define DSPA_INT               8
+#define COMP_INT               9
+#define MSHC_XINT              10
+#define GPIO_INT_PORTA         11
+#define GPIO_INT_PORTB         12
+#define GPIO_INT_PORTC         13
+#define LCDC_INT               14
+#define SIM_INT                        15
+#define SIM_DATA_INT           16
+#define RTC_INT                        17
+#define RTC_SAMINT             18
+#define UART2_MINT_PFERR       19
+#define UART2_MINT_RTS         20
+#define UART2_MINT_DTR         21
+#define UART2_MINT_UARTC       22
+#define UART2_MINT_TX          23
+#define UART2_MINT_RX          24
+#define UART1_MINT_PFERR       25
+#define UART1_MINT_RTS         26
+#define UART1_MINT_DTR         27
+#define UART1_MINT_UARTC       28
+#define UART1_MINT_TX          29
+#define UART1_MINT_RX          30
+#define VOICE_DAC_INT          31
+#define VOICE_ADC_INT          32
+#define PEN_DATA_INT           33
+#define PWM_INT                        34
+#define SDHC_INT               35
+#define I2C_INT                        39
+#define CSPI_INT               41
+#define SSI_TX_INT             42
+#define SSI_TX_ERR_INT         43
+#define SSI_RX_INT             44
+#define SSI_RX_ERR_INT         45
+#define TOUCH_INT              46
+#define USBD_INT0              47
+#define USBD_INT1              48
+#define USBD_INT2              49
+#define USBD_INT3              50
+#define USBD_INT4              51
+#define USBD_INT5              52
+#define USBD_INT6              53
+#define BTSYS_INT              55
+#define BTTIM_INT              56
+#define BTWUI_INT              57
+#define TIM2_INT               58
+#define TIM1_INT               59
+#define DMA_ERR                        60
+#define DMA_INT                        61
+#define GPIO_INT_PORTD         62
+#define WDT_INT                        63
+
+/* gpio and gpio based interrupt handling */
+#define GPIO_DR                        0x1C
+#define GPIO_GDIR              0x00
+#define GPIO_PSR               0x24
+#define GPIO_ICR1              0x28
+#define GPIO_ICR2              0x2C
+#define GPIO_IMR               0x30
+#define GPIO_ISR               0x34
+#define GPIO_INT_LOW_LEV       0x3
+#define GPIO_INT_HIGH_LEV      0x2
+#define GPIO_INT_RISE_EDGE     0x0
+#define GPIO_INT_FALL_EDGE     0x1
+#define GPIO_INT_NONE          0x4
+
+/* DMA */
+#define DMA_REQ_UART3_T                2
+#define DMA_REQ_UART3_R                3
+#define DMA_REQ_SSI2_T         4
+#define DMA_REQ_SSI2_R         5
+#define DMA_REQ_CSI_STAT       6
+#define DMA_REQ_CSI_R          7
+#define DMA_REQ_MSHC           8
+#define DMA_REQ_DSPA_DCT_DOUT  9
+#define DMA_REQ_DSPA_DCT_DIN   10
+#define DMA_REQ_DSPA_MAC       11
+#define DMA_REQ_EXT            12
+#define DMA_REQ_SDHC           13
+#define DMA_REQ_SPI1_R         14
+#define DMA_REQ_SPI1_T         15
+#define DMA_REQ_SSI_T          16
+#define DMA_REQ_SSI_R          17
+#define DMA_REQ_ASP_DAC                18
+#define DMA_REQ_ASP_ADC                19
+#define DMA_REQ_USP_EP(x)      (20 + (x))
+#define DMA_REQ_SPI2_R         26
+#define DMA_REQ_SPI2_T         27
+#define DMA_REQ_UART2_T                28
+#define DMA_REQ_UART2_R                29
+#define DMA_REQ_UART1_T                30
+#define DMA_REQ_UART1_R                31
+
+/* mandatory for CONFIG_LL_DEBUG */
+#define MXC_LL_UART_PADDR      UART1_BASE_ADDR
+#define MXC_LL_UART_VADDR      IO_ADDRESS(UART1_BASE_ADDR)
+
+#endif /*  __ASM_ARCH_MXC_MX1_H__ */
index a86db64744a1d56fbdefbf390110076da1b70fef..0313be72055211bed96a7578225b75faa9212309 100644 (file)
@@ -72,7 +72,8 @@
 /* for mx27*/
 #define OTG_BASE_ADDR           USBOTG_BASE_ADDR
 #define SAHARA_BASE_ADDR        (AIPI_BASE_ADDR + 0x25000)
-#define EMMA_BASE_ADDR          (AIPI_BASE_ADDR + 0x26400)
+#define EMMA_PP_BASE_ADDR       (AIPI_BASE_ADDR + 0x26000)
+#define EMMA_PRP_BASE_ADDR      (AIPI_BASE_ADDR + 0x26400)
 #define CCM_BASE_ADDR           (AIPI_BASE_ADDR + 0x27000)
 #define SYSCTRL_BASE_ADDR       (AIPI_BASE_ADDR + 0x27800)
 #define IIM_BASE_ADDR           (AIPI_BASE_ADDR + 0x28000)
@@ -288,16 +289,4 @@ extern int mx27_revision(void);
 /* this CPU supports up to 192 GPIOs (don't forget the baseboard!) */
 #define ARCH_NR_GPIOS          (192 + 16)
 
-/* OS clock tick rate */
-#define CLOCK_TICK_RATE         13300000
-
-/* Start of RAM */
-#define PHYS_OFFSET            SDRAM_BASE_ADDR
-
-/* max interrupt lines count */
-#define NR_IRQS                        256
-
-/* count of internal interrupt sources */
-#define MXC_MAX_INT_LINES      64
-
 #endif /* __ASM_ARCH_MXC_MX27_H__ */
index 0536f8917bc0ee415bb4275ed87862133e67a069..de026654b00e66c3c54d18c1f8f77ed6e3dcc62d 100644 (file)
 #error "Do not include directly."
 #endif
 
-/*!
- * defines the hardware clock tick rate
- */
-#define CLOCK_TICK_RATE                16625000
-
 /*
  * MX31 memory map:
  *
 #define PCMCIA_IO_ADDRESS(x) \
        (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
 
-/* Start of physical RAM - On many MX31 platforms, this is the first SDRAM bank (CSD0) */
-#define PHYS_OFFSET             CSD0_BASE_ADDR
-
 /*
  * Interrupt numbers
  */
 #define MXC_INT_EXT_WDOG       62
 #define MXC_INT_EXT_TV         63
 
-#define MXC_MAX_INT_LINES      64
-
-#define MXC_GPIO_INT_BASE      MXC_MAX_INT_LINES
-#define MXC_MAX_GPIO_LINES      (GPIO_NUM_PIN * GPIO_PORT_NUM)
-#define MXC_MAX_VIRTUAL_INTS   16
-
-#define NR_IRQS (MXC_MAX_INT_LINES + MXC_MAX_GPIO_LINES + MXC_MAX_VIRTUAL_INTS)
-
-/*!
- * Number of GPIO port as defined in the IC Spec
- */
-#define GPIO_PORT_NUM          3
-/*!
- * Number of GPIO pins per port
- */
-#define GPIO_NUM_PIN           32
-
 #define PROD_SIGNATURE         0x1     /* For MX31 */
 
 /* silicon revisions specific to i.MX31 */
index 130aebfbe168024f15851bf302cc49d4ee9eb525..6c19a134744b8db368a3c32dd3437dbf3528db89 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/clk.h>
 #include <mach/hardware.h>
 
-#ifdef CONFIG_ARCH_IMX
+#ifdef CONFIG_ARCH_MX1
 #define TIMER_BASE             IO_ADDRESS(TIM1_BASE_ADDR)
 #define TIMER_INTERRUPT                TIM1_INT
 
@@ -65,7 +65,7 @@ static void gpt_irq_acknowledge(void)
 {
        __raw_writel(0, TIMER_BASE + MXC_TSTAT);
 }
-#endif /* CONFIG_ARCH_IMX */
+#endif /* CONFIG_ARCH_MX1 */
 
 #ifdef CONFIG_ARCH_MX2
 #define TIMER_BASE             IO_ADDRESS(GPT1_BASE_ADDR)
index 0b0af0253e912124d69cb4eacaedf7c1703b2ecf..07b4a73c9d2f3135400e3b6aa8ac889c4a352758 100644 (file)
 #ifndef __ASM_ARCH_MXC_TIMEX_H__
 #define __ASM_ARCH_MXC_TIMEX_H__
 
-#include <mach/hardware.h>     /* for CLOCK_TICK_RATE */
+#if defined CONFIG_ARCH_MX1
+#define CLOCK_TICK_RATE                16000000
+#elif defined CONFIG_ARCH_MX2
+#define CLOCK_TICK_RATE                13300000
+#elif defined CONFIG_ARCH_MX3
+#define CLOCK_TICK_RATE                16625000
+#endif
 
 #endif                         /* __ASM_ARCH_MXC_TIMEX_H__ */
index d97387aa9a42f9e87d756832374cc79cca1efe00..df6f18395686bcfe73d9b3cc40b21bac900aaad3 100644 (file)
@@ -110,12 +110,13 @@ void mxc_gpio_mode(int gpio_mode)
 EXPORT_SYMBOL(mxc_gpio_mode);
 
 int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
-                               int alloc_mode, const char *label)
+               const char *label)
 {
        const int *p = pin_list;
        int i;
        unsigned gpio;
        unsigned mode;
+       int ret = -EINVAL;
 
        for (i = 0; i < count; i++) {
                gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
@@ -124,33 +125,33 @@ int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
                if (gpio >= (GPIO_PORT_MAX + 1) * 32)
                        goto setup_error;
 
-               if (alloc_mode & MXC_GPIO_ALLOC_MODE_RELEASE)
-                       gpio_free(gpio);
-               else if (!(alloc_mode & MXC_GPIO_ALLOC_MODE_NO_ALLOC))
-                       if (gpio_request(gpio, label)
-                          && !(alloc_mode & MXC_GPIO_ALLOC_MODE_TRY_ALLOC))
-                               goto setup_error;
+               ret = gpio_request(gpio, label);
+               if (ret)
+                       goto setup_error;
 
-               if (!(alloc_mode & (MXC_GPIO_ALLOC_MODE_ALLOC_ONLY |
-                                   MXC_GPIO_ALLOC_MODE_RELEASE)))
-                       mxc_gpio_mode(gpio | mode);
+               mxc_gpio_mode(gpio | mode);
 
                p++;
        }
        return 0;
 
 setup_error:
-       if (alloc_mode & (MXC_GPIO_ALLOC_MODE_NO_ALLOC |
-           MXC_GPIO_ALLOC_MODE_TRY_ALLOC))
-               return -EINVAL;
+       mxc_gpio_release_multiple_pins(pin_list, i);
+       return ret;
+}
+EXPORT_SYMBOL(mxc_gpio_setup_multiple_pins);
 
-       while (p != pin_list) {
-               p--;
-               gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
+void mxc_gpio_release_multiple_pins(const int *pin_list, int count)
+{
+       const int *p = pin_list;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               unsigned gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
                gpio_free(gpio);
+               p++;
        }
 
-       return -EINVAL;
 }
-EXPORT_SYMBOL(mxc_gpio_setup_multiple_pins);
+EXPORT_SYMBOL(mxc_gpio_release_multiple_pins);
 
index d862c9e5f8dbc935a7f89ba5576746186427eb86..6e7578a3514bf6792e2d5a4e78c945279e5b5fd7 100644 (file)
  * MA  02110-1301, USA.
  */
 
+#include <linux/module.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <mach/common.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
 
 #define AVIC_BASE              IO_ADDRESS(AVIC_BASE_ADDR)
 #define AVIC_INTCNTL           (AVIC_BASE + 0x00)      /* int control reg */
@@ -65,6 +68,28 @@ void imx_irq_set_priority(unsigned char irq, unsigned char prio)
 EXPORT_SYMBOL(imx_irq_set_priority);
 #endif
 
+#ifdef CONFIG_FIQ
+int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
+{
+       unsigned int irqt;
+
+       if (irq >= MXC_INTERNAL_IRQS)
+               return -EINVAL;
+
+       if (irq < MXC_INTERNAL_IRQS / 2) {
+               irqt = __raw_readl(AVIC_INTTYPEL) & ~(1 << irq);
+               __raw_writel(irqt | (!!type << irq), AVIC_INTTYPEL);
+       } else {
+               irq -= MXC_INTERNAL_IRQS / 2;
+               irqt = __raw_readl(AVIC_INTTYPEH) & ~(1 << irq);
+               __raw_writel(irqt | (!!type << irq), AVIC_INTTYPEH);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mxc_set_irq_fiq);
+#endif /* CONFIG_FIQ */
+
 /* Disable interrupt number "irq" in the AVIC */
 static void mxc_mask_irq(unsigned int irq)
 {
@@ -91,7 +116,6 @@ static struct irq_chip mxc_avic_chip = {
 void __init mxc_init_irq(void)
 {
        int i;
-       u32 reg;
 
        /* put the AVIC into the reset value with
         * all interrupts disabled
@@ -106,7 +130,7 @@ void __init mxc_init_irq(void)
        /* all IRQ no FIQ */
        __raw_writel(0, AVIC_INTTYPEH);
        __raw_writel(0, AVIC_INTTYPEL);
-       for (i = 0; i < MXC_MAX_INT_LINES; i++) {
+       for (i = 0; i < MXC_INTERNAL_IRQS; i++) {
                set_irq_chip(i, &mxc_avic_chip);
                set_irq_handler(i, handle_level_irq);
                set_irq_flags(i, IRQF_VALID);
@@ -119,5 +143,10 @@ void __init mxc_init_irq(void)
        /* init architectures chained interrupt handler */
        mxc_register_gpios();
 
+#ifdef CONFIG_FIQ
+       /* Initialize FIQ */
+       init_FIQ();
+#endif
+
        printk(KERN_INFO "MXC IRQ initialized\n");
 }
index a94f0c44ebc8286b042f39a8de172c7d80eb4238..46d3b0b9ce696eaef46d895a37b7a694059dd554 100644 (file)
@@ -14,9 +14,11 @@ config ARCH_OMAP1
 
 config ARCH_OMAP2
        bool "TI OMAP2"
+       select CPU_V6
 
 config ARCH_OMAP3
        bool "TI OMAP3"
+       select CPU_V7
 
 endchoice
 
index e31154b15d9ec1bfec395891709558694272fdeb..f6684832ca8f6cb500812d8d72f9575aa517ea97 100644 (file)
@@ -69,15 +69,15 @@ int __init debug_card_init(u32 addr, unsigned gpio)
        smc91x_resources[0].start = addr + 0x300;
        smc91x_resources[0].end   = addr + 0x30f;
 
-       smc91x_resources[1].start = OMAP_GPIO_IRQ(gpio);
-       smc91x_resources[1].end   = OMAP_GPIO_IRQ(gpio);
+       smc91x_resources[1].start = gpio_to_irq(gpio);
+       smc91x_resources[1].end   = gpio_to_irq(gpio);
 
-       status = omap_request_gpio(gpio);
+       status = gpio_request(gpio, "SMC91x irq");
        if (status < 0) {
                printk(KERN_ERR "GPIO%d unavailable for smc91x IRQ\n", gpio);
                return status;
        }
-       omap_set_gpio_direction(gpio, 1);
+       gpio_direction_input(gpio);
 
        led_resources[0].start = addr;
        led_resources[0].end   = addr + SZ_4K - 1;
index 2f4c0cabfd341fbaa2d54e0fba2673c8d0ec383b..be4eefda4767fa11f54177bb6ba8a3a1ed27d770 100644 (file)
@@ -83,8 +83,8 @@ static void h2p2_dbg_leds_event(led_event_t evt)
                /* all leds off during suspend or shutdown */
 
                if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
-                       omap_set_gpio_dataout(GPIO_TIMER, 0);
-                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+                       gpio_set_value(GPIO_TIMER, 0);
+                       gpio_set_value(GPIO_IDLE, 0);
                }
 
                __raw_writew(~0, &fpga->leds);
@@ -107,7 +107,7 @@ static void h2p2_dbg_leds_event(led_event_t evt)
                if (machine_is_omap_perseus2() || machine_is_omap_h4())
                        hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
                else {
-                       omap_set_gpio_dataout(GPIO_TIMER,
+                       gpio_set_value(GPIO_TIMER,
                                        led_state & LED_TIMER_ON);
                        goto done;
                }
@@ -121,7 +121,7 @@ static void h2p2_dbg_leds_event(led_event_t evt)
                if (machine_is_omap_perseus2() || machine_is_omap_h4())
                        hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
                else {
-                       omap_set_gpio_dataout(GPIO_IDLE, 1);
+                       gpio_set_value(GPIO_IDLE, 1);
                        goto done;
                }
 
@@ -131,7 +131,7 @@ static void h2p2_dbg_leds_event(led_event_t evt)
                if (machine_is_omap_perseus2() || machine_is_omap_h4())
                        hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
                else {
-                       omap_set_gpio_dataout(GPIO_IDLE, 0);
+                       gpio_set_value(GPIO_IDLE, 0);
                        goto done;
                }
 
index 0cb2b22388e93454a7fe78b69e465fee6a519379..ac15c23fd5da840e5816e6223b3456d60b24c0c6 100644 (file)
@@ -192,202 +192,48 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
 
 /*-------------------------------------------------------------------------*/
 
-#if    defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
        defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
-#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_MMC_NR_RES                2
 
-#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);
-               }
-
-               /* 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
 
 /*-------------------------------------------------------------------------*/
@@ -532,7 +378,6 @@ static int __init omap_init_devices(void)
         */
        omap_init_dsp();
        omap_init_kp();
-       omap_init_mmc();
        omap_init_uwire();
        omap_init_wdt();
        omap_init_rng();
index 50f8b4ad9a0942a0e818a746dff055d17b8be139..692d2b495af34260cdd57619240b9ab46ffdf8f9 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <asm/system.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 #include <mach/tc.h>
 
@@ -1848,9 +1848,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);
index 963c31cd15416b69aacd5ae253e393f641de0e8a..e4f0ce04ba928130f8bfd973c9cc04d05b013f19 100644 (file)
@@ -539,10 +539,6 @@ void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
-       /* REVISIT: hw feature, ttgr overtaking tldr? */
-       while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)))
-               cpu_relax();
-
        omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
 }
 
@@ -553,14 +549,15 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
        u32 l;
 
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       if (autoreload)
+       if (autoreload) {
                l |= OMAP_TIMER_CTRL_AR;
-       else
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+       } else {
                l &= ~OMAP_TIMER_CTRL_AR;
+       }
        l |= OMAP_TIMER_CTRL_ST;
 
        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load);
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 }
 
index 424049d83fbeb42b63e66286642b35ecbf3bd661..07b6968a7d16745988883da1a2f6c1ba75b91f15 100644 (file)
@@ -152,6 +152,7 @@ struct gpio_bank {
        u32 level_mask;
        spinlock_t lock;
        struct gpio_chip chip;
+       struct clk *dbck;
 };
 
 #define METHOD_MPUIO           0
@@ -244,6 +245,8 @@ static inline struct gpio_bank *get_gpio_bank(int gpio)
                return &gpio_bank[gpio >> 5];
        if (cpu_is_omap34xx())
                return &gpio_bank[gpio >> 5];
+       BUG();
+       return NULL;
 }
 
 static inline int get_gpio_index(int gpio)
@@ -332,19 +335,6 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
        __raw_writel(l, reg);
 }
 
-void omap_set_gpio_direction(int gpio, int is_input)
-{
-       struct gpio_bank *bank;
-       unsigned long flags;
-
-       if (check_gpio(gpio) < 0)
-               return;
-       bank = get_gpio_bank(gpio);
-       spin_lock_irqsave(&bank->lock, flags);
-       _set_gpio_direction(bank, get_gpio_index(gpio), is_input);
-       spin_unlock_irqrestore(&bank->lock, flags);
-}
-
 static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
 {
        void __iomem *reg = bank->base;
@@ -406,20 +396,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
        __raw_writel(l, reg);
 }
 
-void omap_set_gpio_dataout(int gpio, int enable)
-{
-       struct gpio_bank *bank;
-       unsigned long flags;
-
-       if (check_gpio(gpio) < 0)
-               return;
-       bank = get_gpio_bank(gpio);
-       spin_lock_irqsave(&bank->lock, flags);
-       _set_gpio_dataout(bank, get_gpio_index(gpio), enable);
-       spin_unlock_irqrestore(&bank->lock, flags);
-}
-
-int omap_get_gpio_datain(int gpio)
+static int __omap_get_gpio_datain(int gpio)
 {
        struct gpio_bank *bank;
        void __iomem *reg;
@@ -473,6 +450,7 @@ void omap_set_gpio_debounce(int gpio, int enable)
 {
        struct gpio_bank *bank;
        void __iomem *reg;
+       unsigned long flags;
        u32 val, l = 1 << get_gpio_index(gpio);
 
        if (cpu_class_is_omap1())
@@ -480,16 +458,28 @@ void omap_set_gpio_debounce(int gpio, int enable)
 
        bank = get_gpio_bank(gpio);
        reg = bank->base;
-
        reg += OMAP24XX_GPIO_DEBOUNCE_EN;
+
+       spin_lock_irqsave(&bank->lock, flags);
        val = __raw_readl(reg);
 
-       if (enable)
+       if (enable && !(val & l))
                val |= l;
-       else
+       else if (!enable && (val & l))
                val &= ~l;
+       else
+               goto done;
+
+       if (cpu_is_omap34xx()) {
+               if (enable)
+                       clk_enable(bank->dbck);
+               else
+                       clk_disable(bank->dbck);
+       }
 
        __raw_writel(val, reg);
+done:
+       spin_unlock_irqrestore(&bank->lock, flags);
 }
 EXPORT_SYMBOL(omap_set_gpio_debounce);
 
@@ -906,26 +896,17 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable)
        return retval;
 }
 
-int omap_request_gpio(int gpio)
+static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
-       struct gpio_bank *bank;
+       struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
        unsigned long flags;
-       int status;
-
-       if (check_gpio(gpio) < 0)
-               return -EINVAL;
 
-       status = gpio_request(gpio, NULL);
-       if (status < 0)
-               return status;
-
-       bank = get_gpio_bank(gpio);
        spin_lock_irqsave(&bank->lock, flags);
 
        /* Set trigger to none. You need to enable the desired trigger with
         * request_irq() or set_irq_type().
         */
-       _set_gpio_triggering(bank, get_gpio_index(gpio), IRQ_TYPE_NONE);
+       _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
 
 #ifdef CONFIG_ARCH_OMAP15XX
        if (bank->method == METHOD_GPIO_1510) {
@@ -933,7 +914,7 @@ int omap_request_gpio(int gpio)
 
                /* Claim the pin for MPU */
                reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
-               __raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
+               __raw_writel(__raw_readl(reg) | (1 << offset), reg);
        }
 #endif
        spin_unlock_irqrestore(&bank->lock, flags);
@@ -941,39 +922,28 @@ int omap_request_gpio(int gpio)
        return 0;
 }
 
-void omap_free_gpio(int gpio)
+static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
-       struct gpio_bank *bank;
+       struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
        unsigned long flags;
 
-       if (check_gpio(gpio) < 0)
-               return;
-       bank = get_gpio_bank(gpio);
        spin_lock_irqsave(&bank->lock, flags);
-       if (unlikely(!gpiochip_is_requested(&bank->chip,
-                               get_gpio_index(gpio)))) {
-               spin_unlock_irqrestore(&bank->lock, flags);
-               printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);
-               dump_stack();
-               return;
-       }
 #ifdef CONFIG_ARCH_OMAP16XX
        if (bank->method == METHOD_GPIO_1610) {
                /* Disable wake-up during idle for dynamic tick */
                void __iomem *reg = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
-               __raw_writel(1 << get_gpio_index(gpio), reg);
+               __raw_writel(1 << offset, reg);
        }
 #endif
 #if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
        if (bank->method == METHOD_GPIO_24XX) {
                /* Disable wake-up during idle for dynamic tick */
                void __iomem *reg = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
-               __raw_writel(1 << get_gpio_index(gpio), reg);
+               __raw_writel(1 << offset, reg);
        }
 #endif
-       _reset_gpio(bank, gpio);
+       _reset_gpio(bank, bank->chip.base + offset);
        spin_unlock_irqrestore(&bank->lock, flags);
-       gpio_free(gpio);
 }
 
 /*
@@ -1252,7 +1222,7 @@ static int gpio_input(struct gpio_chip *chip, unsigned offset)
 
 static int gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-       return omap_get_gpio_datain(chip->base + offset);
+       return __omap_get_gpio_datain(chip->base + offset);
 }
 
 static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
@@ -1279,6 +1249,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;
@@ -1296,7 +1274,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
 
@@ -1310,9 +1287,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;
 
@@ -1367,12 +1342,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
@@ -1479,10 +1448,13 @@ static int __init _omap_gpio_init(void)
                /* REVISIT eventually switch from OMAP-specific gpio structs
                 * over to the generic ones
                 */
+               bank->chip.request = omap_gpio_request;
+               bank->chip.free = omap_gpio_free;
                bank->chip.direction_input = gpio_input;
                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
@@ -1511,6 +1483,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.
@@ -1739,12 +1718,6 @@ static int __init omap_gpio_sysinit(void)
        return ret;
 }
 
-EXPORT_SYMBOL(omap_request_gpio);
-EXPORT_SYMBOL(omap_free_gpio);
-EXPORT_SYMBOL(omap_set_gpio_direction);
-EXPORT_SYMBOL(omap_set_gpio_dataout);
-EXPORT_SYMBOL(omap_get_gpio_datain);
-
 arch_initcall(omap_gpio_sysinit);
 
 
@@ -1801,14 +1774,14 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
                                continue;
 
                        irq = bank->virtual_irq_start + j;
-                       value = omap_get_gpio_datain(gpio);
+                       value = gpio_get_value(gpio);
                        is_in = gpio_is_input(bank, mask);
 
                        if (bank_is_mpuio(bank))
                                seq_printf(s, "MPUIO %2d ", j);
                        else
                                seq_printf(s, "GPIO %3d ", gpio);
-                       seq_printf(s, "(%10s): %s %s",
+                       seq_printf(s, "(%-20.20s): %s %s",
                                        label,
                                        is_in ? "in " : "out",
                                        value ? "hi"  : "lo");
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 731c858cf3fe70e836a9fbead02bee5ed7bfb5fa..61bd5e8f09b138f5c414b69b27ce0c51273fb9f9 100644 (file)
 #ifndef __ASM_ARCH_OMAP_APOLLON_H
 #define __ASM_ARCH_OMAP_APOLLON_H
 
+#include <mach/cpu.h>
+
 extern void apollon_mmc_init(void);
 
 static inline int apollon_plus(void)
 {
        /* The apollon plus has IDCODE revision 5 */
-       return system_rev & 0xc0;
+       return omap_rev() & 0xc0;
 }
 
 /* Placeholder for APOLLON specific defines */
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 66e2746c04cac80a8637b3ce28e74c01782591cd..f23399665212f11c988834b835c900fc2cc01038 100644 (file)
@@ -32,5 +32,8 @@
 extern void twl4030_bci_battery_init(void);
 
 #define TWL4030_IRQNUM         INT_34XX_SYS_NIRQ
-
+#define LDP_SMC911X_CS         1
+#define LDP_SMC911X_GPIO       152
+#define DEBUG_BASE             0x08000000
+#define OMAP34XX_ETHR_START    DEBUG_BASE
 #endif /* __ASM_ARCH_OMAP_LDP_H */
index c23c12ccb3532c912285a70ef012dd6b030ff5b1..9466772fc7c88c11fabaa42a4025efa1fef704c6 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
@@ -35,27 +34,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;
-       /* use the internal clock */
-       unsigned internal_clock: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;
index dc9886760577b4be3510571863f38cf03ba0e04c..269147f3836f50985809c3ab5b9a3f81a944e2f4 100644 (file)
@@ -74,6 +74,7 @@
 #define OMAP243X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
 #define OMAP243X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
 #define OMAP243X_CONTROL_IVA2_GEMCFG   (OMAP2_CONTROL_GENERAL + 0x0198)
+#define OMAP243X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x0230)
 
 /* 24xx-only CONTROL_GENERAL register offsets */
 #define OMAP24XX_CONTROL_DEBOBS                (OMAP2_CONTROL_GENERAL + 0x0000)
 #define OMAP343X_CONTROL_TEST_KEY_13   (OMAP2_CONTROL_GENERAL + 0x00fc)
 #define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
 #define OMAP343X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
+#define OMAP343X_CONTROL_PBIAS_LITE    (OMAP2_CONTROL_GENERAL + 0x02b0)
 #define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02b4)
 
 /*
  * and the security mode (secure, non-secure, don't care)
  */
 /* CONTROL_DEVCONF0 bits */
+#define OMAP2_MMCSDIO1ADPCLKISEL       (1 << 24) /* MMC1 loop back clock */
 #define OMAP24XX_USBSTANDBYCTRL                (1 << 15)
 #define OMAP2_MCBSP2_CLKS_MASK         (1 << 6)
 #define OMAP2_MCBSP1_CLKS_MASK         (1 << 2)
 
 /* CONTROL_DEVCONF1 bits */
+#define OMAP243X_MMC1_ACTIVE_OVERWRITE (1 << 31)
+#define OMAP2_MMCSDIO2ADPCLKISEL       (1 << 6) /* MMC2 loop back clock */
 #define OMAP2_MCBSP5_CLKS_MASK         (1 << 4) /* > 242x */
 #define OMAP2_MCBSP4_CLKS_MASK         (1 << 2) /* > 242x */
 #define OMAP2_MCBSP3_CLKS_MASK         (1 << 0) /* > 242x */
 #define OMAP2_SYSBOOT_1_MASK           (1 << 1)
 #define OMAP2_SYSBOOT_0_MASK           (1 << 0)
 
+/* CONTROL_PBIAS_LITE bits */
+#define OMAP343X_PBIASLITESUPPLY_HIGH1 (1 << 15)
+#define OMAP343X_PBIASLITEVMODEERROR1  (1 << 11)
+#define OMAP343X_PBIASSPEEDCTRL1       (1 << 10)
+#define OMAP343X_PBIASLITEPWRDNZ1      (1 << 9)
+#define OMAP343X_PBIASLITEVMODE1       (1 << 8)
+#define OMAP343X_PBIASLITESUPPLY_HIGH0 (1 << 7)
+#define OMAP343X_PBIASLITEVMODEERROR0  (1 << 3)
+#define OMAP2_PBIASSPEEDCTRL0          (1 << 2)
+#define OMAP2_PBIASLITEPWRDNZ0         (1 << 1)
+#define OMAP2_PBIASLITEVMODE0          (1 << 0)
+
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 extern void __iomem *omap_ctrl_base_get(void);
index e0464187209dcc9d4227267e251944b1e7cd7337..b2062f1175de0c73196e05ee1ceaae4e68725da5 100644 (file)
 
 struct omap_chip_id {
        u8 oc;
+       u8 type;
 };
 
 #define OMAP_CHIP_INIT(x)      { .oc = x }
 
-extern unsigned int system_rev;
-
-#define omap2_cpu_rev()                ((system_rev >> 12) & 0x0f)
+/*
+ * omap_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]
+ */
+unsigned int omap_rev(void);
 
 /*
  * 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 (omap_rev() & 0xff)
 
 #define IS_OMAP_CLASS(class, id)                       \
 static inline int is_omap ##class (void)               \
@@ -116,7 +121,7 @@ static inline int is_omap ##class (void)            \
        return (GET_OMAP_CLASS == (id)) ? 1 : 0;        \
 }
 
-#define GET_OMAP_SUBCLASS      ((system_rev >> 20) & 0x0fff)
+#define GET_OMAP_SUBCLASS      ((omap_rev() >> 20) & 0x0fff)
 
 #define IS_OMAP_SUBCLASS(subclass, id)                 \
 static inline int is_omap ##subclass (void)            \
@@ -226,7 +231,7 @@ IS_OMAP_SUBCLASS(343x, 0x343)
  * cpu_is_omap2430():  True for OMAP2430
  * cpu_is_omap3430():  True for OMAP3430
  */
-#define GET_OMAP_TYPE  ((system_rev >> 16) & 0xffff)
+#define GET_OMAP_TYPE  ((omap_rev() >> 16) & 0xffff)
 
 #define IS_OMAP_TYPE(type, id)                         \
 static inline int is_omap ##type (void)                        \
@@ -320,44 +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)))
+/* 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_less_than(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 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 get_sil_rev() \
-               get_sil_revision(system_rev)
-
-/* Various silicon macros defined here */
-#define OMAP242X_CLASS         0x24200000
-#define OMAP2420_REV_ES1_0     0x24200000
-#define OMAP2420_REV_ES2_0     0x24201000
-
-#define OMAP243X_CLASS         0x24300000
-#define OMAP2430_REV_ES1_0     0x24300000
-
-#define OMAP343X_CLASS         0x34300000
-#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
@@ -382,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 98e9008b7e9d172ad06eb50a000cca0ef5443bb0..04e68e88f1348a9c2e3d01e74974d7967509ee01 100644 (file)
                                 IH_GPIO_BASE + (nr))
 
 extern int omap_gpio_init(void);       /* Call from board init only */
-extern int omap_request_gpio(int gpio);
-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);
@@ -92,6 +87,16 @@ extern void omap_set_gpio_debounce_time(int gpio, int enable);
 #include <linux/errno.h>
 #include <asm-generic/gpio.h>
 
+static inline int omap_request_gpio(int gpio)
+{
+       return gpio_request(gpio, "FIXME");
+}
+
+static inline void omap_free_gpio(int gpio)
+{
+       gpio_free(gpio);
+}
+
 static inline int gpio_get_value(unsigned gpio)
 {
        return __gpio_get_value(gpio);
@@ -109,16 +114,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 adc83b7b82052f296dae128af5597084ed1c1e45..d92bf7964481c5f39dffeeea8f2be507e1ec2065 100644 (file)
@@ -42,8 +42,8 @@
  * We don't actually have real ISA nor PCI buses, but there is so many
  * drivers out there that might just work if we fake them...
  */
-#define __io(a)                        ((void __iomem *)(PCIO_BASE + (a)))
-#define __mem_pci(a)           (a)
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
 
 /*
  * ----------------------------------------------------------------------------
@@ -51,8 +51,6 @@
  * ----------------------------------------------------------------------------
  */
 
-#define PCIO_BASE      0
-
 #if defined(CONFIG_ARCH_OMAP1)
 
 #define IO_PHYS                        0xFFFB0000
index d40cac60b95986043e4ff9bb4fce21bea5a6b1fa..211c9f6619e991f4b434a88a4ae94bb85215d7c7 100644 (file)
 #define PHYS_OFFSET            UL(0x80000000)
 #endif
 
-/*
- * Conversion between SDRAM and fake PCI bus, used by USB
- * NOTE: Physical address must be converted to Local Bus address
- *      on OMAP-1510 only
- */
-
 /*
  * Bus address is physical address, except for OMAP-1510 Local Bus.
- */
-#define __virt_to_bus(x)       __virt_to_phys(x)
-#define __bus_to_virt(x)       __phys_to_virt(x)
-
-/*
  * OMAP-1510 bus address is translated into a Local Bus address if the
  * OMAP bus type is lbus. We do the address translation based on the
  * device overriding the defaults used in the dma-mapping API.
 
 #define __arch_page_to_dma(dev, page)  ({is_lbus_device(dev) ? \
                                        (dma_addr_t)virt_to_lbus(page_address(page)) : \
-                                       (dma_addr_t)__virt_to_bus(page_address(page));})
+                                       (dma_addr_t)__virt_to_phys(page_address(page));})
 
 #define __arch_dma_to_virt(dev, addr)  ({ (void *) (is_lbus_device(dev) ? \
                                                lbus_to_virt(addr) : \
-                                               __bus_to_virt(addr)); })
+                                               __phys_to_virt(addr)); })
 
 #define __arch_virt_to_dma(dev, addr)  ({ unsigned long __addr = (unsigned long)(addr); \
                                           (dma_addr_t) (is_lbus_device(dev) ? \
                                                virt_to_lbus(__addr) : \
-                                               __virt_to_bus(__addr)); })
+                                               __virt_to_phys(__addr)); })
 
 #endif /* CONFIG_ARCH_OMAP15XX */
 
index fc15d13058fc74e5116490b4e704be355dd7b576..031250f028050b4e95bb805194ba36484b6e4229 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 HSMMC3                 (1 << 2)
+#define HSMMC2                 (1 << 1)
+#define HSMMC1                 (1 << 0)
+
 #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 +57,31 @@ 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 {
+
+               /* 4 wire signaling is optional, and is used for SD/SDIO/HSMMC;
+                * 8 wire signaling is also optional, and is used with HSMMC
+                */
+               u8 wires;
+
+               /*
+                * 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;
+
+               /* use the internal clock */
+               unsigned internal_clock:1;
+               s16 power_pin;
+
+               int switch_pin;                 /* gpio (card detect) */
+               int gpio_wp;                    /* gpio (write protect) */
+
                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 +89,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 +106,31 @@ 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
 #endif
index 6bbf1789bed5debac64e2f9a7bc4ab0b19c0a834..f4362b8682c7a01f134a3f53109af4d6ca9ea593 100644 (file)
@@ -632,6 +632,15 @@ enum omap24xx_index {
        AC7_2430_USB0HS_DATA7,
 
        /* 2430 McBSP */
+       AD6_2430_MCBSP_CLKS,
+
+       AB2_2430_MCBSP1_CLKR,
+       AD5_2430_MCBSP1_FSR,
+       AA1_2430_MCBSP1_DX,
+       AF3_2430_MCBSP1_DR,
+       AB3_2430_MCBSP1_FSX,
+       Y9_2430_MCBSP1_CLKX,
+
        AC10_2430_MCBSP2_FSX,
        AD16_2430_MCBSP2_CLX,
        AE13_2430_MCBSP2_DX,
@@ -641,6 +650,30 @@ enum omap24xx_index {
        AE13_2430_MCBSP2_DX_OFF,
        AD13_2430_MCBSP2_DR_OFF,
 
+       AC9_2430_MCBSP3_CLKX,
+       AE4_2430_MCBSP3_FSX,
+       AE2_2430_MCBSP3_DR,
+       AF4_2430_MCBSP3_DX,
+
+       N3_2430_MCBSP4_CLKX,
+       AD23_2430_MCBSP4_DR,
+       AB25_2430_MCBSP4_DX,
+       AC25_2430_MCBSP4_FSX,
+
+       AE16_2430_MCBSP5_CLKX,
+       AF12_2430_MCBSP5_FSX,
+       K7_2430_MCBSP5_DX,
+       M1_2430_MCBSP5_DR,
+
+       /* 2430 McSPI*/
+       Y18_2430_MCSPI1_CLK,
+       AD15_2430_MCSPI1_SIMO,
+       AE17_2430_MCSPI1_SOMI,
+       U1_2430_MCSPI1_CS0,
+
+       /* Touchscreen GPIO */
+       AF19_2430_GPIO_85,
+
 };
 
 enum omap34xx_index {
@@ -749,6 +782,14 @@ enum omap34xx_index {
        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 {
index dcd9d16da2e9f5f0df6e36484e09edaed84139e9..be7bcaf2b832d325aaaefb352789d2ca46ff1a74 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <mach/sram.h>
 #include <mach/board.h>
+#include <mach/cpu.h>
 
 #include <mach/control.h>
 
@@ -87,7 +88,7 @@ static int is_sram_locked(void)
        int type = 0;
 
        if (cpu_is_omap242x())
-               type = system_rev & OMAP2_DEVICETYPE_MASK;
+               type = omap_rev() & OMAP2_DEVICETYPE_MASK;
 
        if (type == GP_DEVICE) {
                /* RAMFW: R/W access to all initiators for all qualifier sets */
index 198f3dde2be3ddc745da4d22f9301acf065c1de7..56021a72e10ce340e7ada4d4e4270dd8854bab51 100644 (file)
@@ -6,3 +6,5 @@ obj-y   := irq.o pcie.o time.o
 obj-m  :=
 obj-n  :=
 obj-   :=
+
+obj-$(CONFIG_GENERIC_GPIO) += gpio.o
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
new file mode 100644 (file)
index 0000000..9671864
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * arch/arm/plat-orion/gpio.c
+ *
+ * Marvell Orion SoC GPIO handling.
+ *
+ * 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/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <asm/gpio.h>
+
+static DEFINE_SPINLOCK(gpio_lock);
+static const char *gpio_label[GPIO_MAX];  /* non null for allocated GPIOs */
+static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)];
+
+static inline void __set_direction(unsigned pin, int input)
+{
+       u32 u;
+
+       u = readl(GPIO_IO_CONF(pin));
+       if (input)
+               u |= 1 << (pin & 31);
+       else
+               u &= ~(1 << (pin & 31));
+       writel(u, GPIO_IO_CONF(pin));
+}
+
+static void __set_level(unsigned pin, int high)
+{
+       u32 u;
+
+       u = readl(GPIO_OUT(pin));
+       if (high)
+               u |= 1 << (pin & 31);
+       else
+               u &= ~(1 << (pin & 31));
+       writel(u, GPIO_OUT(pin));
+}
+
+
+/*
+ * GENERIC_GPIO primitives.
+ */
+int gpio_direction_input(unsigned pin)
+{
+       unsigned long flags;
+
+       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
+               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       /*
+        * Some callers might not have used gpio_request(),
+        * so flag this pin as requested now.
+        */
+       if (gpio_label[pin] == NULL)
+               gpio_label[pin] = "?";
+
+       /*
+        * Configure GPIO direction.
+        */
+       __set_direction(pin, 1);
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned pin, int value)
+{
+       unsigned long flags;
+       u32 u;
+
+       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
+               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       /*
+        * Some callers might not have used gpio_request(),
+        * so flag this pin as requested now.
+        */
+       if (gpio_label[pin] == NULL)
+               gpio_label[pin] = "?";
+
+       /*
+        * Disable blinking.
+        */
+       u = readl(GPIO_BLINK_EN(pin));
+       u &= ~(1 << (pin & 31));
+       writel(u, GPIO_BLINK_EN(pin));
+
+       /*
+        * Configure GPIO output value.
+        */
+       __set_level(pin, value);
+
+       /*
+        * Configure GPIO direction.
+        */
+       __set_direction(pin, 0);
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned pin)
+{
+       int val;
+
+       if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31)))
+               val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin));
+       else
+               val = readl(GPIO_OUT(pin));
+
+       return (val >> (pin & 31)) & 1;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned pin, int value)
+{
+       unsigned long flags;
+       u32 u;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       /*
+        * Disable blinking.
+        */
+       u = readl(GPIO_BLINK_EN(pin));
+       u &= ~(1 << (pin & 31));
+       writel(u, GPIO_BLINK_EN(pin));
+
+       /*
+        * Configure GPIO output value.
+        */
+       __set_level(pin, value);
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_request(unsigned pin, const char *label)
+{
+       unsigned long flags;
+       int ret;
+
+       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
+               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&gpio_lock, flags);
+       if (gpio_label[pin] == NULL) {
+               gpio_label[pin] = label ? label : "?";
+               ret = 0;
+       } else {
+               pr_debug("%s: GPIO %d already used as %s\n",
+                        __func__, pin, gpio_label[pin]);
+               ret = -EBUSY;
+       }
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned pin)
+{
+       if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
+               pr_debug("%s: invalid GPIO %d\n", __func__, pin);
+               return;
+       }
+
+       if (gpio_label[pin] == NULL)
+               pr_warning("%s: GPIO %d already freed\n", __func__, pin);
+       else
+               gpio_label[pin] = NULL;
+}
+EXPORT_SYMBOL(gpio_free);
+
+
+/*
+ * Orion-specific GPIO API extensions.
+ */
+void __init orion_gpio_set_unused(unsigned pin)
+{
+       /*
+        * Configure as output, drive low.
+        */
+       __set_level(pin, 0);
+       __set_direction(pin, 0);
+}
+
+void __init orion_gpio_set_valid(unsigned pin, int valid)
+{
+       if (valid)
+               __set_bit(pin, gpio_valid);
+       else
+               __clear_bit(pin, gpio_valid);
+}
+
+void orion_gpio_set_blink(unsigned pin, int blink)
+{
+       unsigned long flags;
+       u32 u;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       /*
+        * Set output value to zero.
+        */
+       __set_level(pin, 0);
+
+       u = readl(GPIO_BLINK_EN(pin));
+       if (blink)
+               u |= 1 << (pin & 31);
+       else
+               u &= ~(1 << (pin & 31));
+       writel(u, GPIO_BLINK_EN(pin));
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+}
+EXPORT_SYMBOL(orion_gpio_set_blink);
+
+
+/*****************************************************************************
+ * Orion GPIO IRQ
+ *
+ * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
+ * value of the line or the opposite value.
+ *
+ * Level IRQ handlers: DATA_IN is used directly as cause register.
+ *                     Interrupt are masked by LEVEL_MASK registers.
+ * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
+ *                     Interrupt are masked by EDGE_MASK registers.
+ * Both-edge handlers: Similar to regular Edge handlers, but also swaps
+ *                     the polarity to catch the next line transaction.
+ *                     This is a race condition that might not perfectly
+ *                     work on some use cases.
+ *
+ * Every eight GPIO lines are grouped (OR'ed) before going up to main
+ * cause register.
+ *
+ *                    EDGE  cause    mask
+ *        data-in   /--------| |-----| |----\
+ *     -----| |-----                         ---- to main cause reg
+ *           X      \----------------| |----/
+ *        polarity    LEVEL          mask
+ *
+ ****************************************************************************/
+static void gpio_irq_edge_ack(u32 irq)
+{
+       int pin = irq_to_gpio(irq);
+
+       writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin));
+}
+
+static void gpio_irq_edge_mask(u32 irq)
+{
+       int pin = irq_to_gpio(irq);
+       u32 u;
+
+       u = readl(GPIO_EDGE_MASK(pin));
+       u &= ~(1 << (pin & 31));
+       writel(u, GPIO_EDGE_MASK(pin));
+}
+
+static void gpio_irq_edge_unmask(u32 irq)
+{
+       int pin = irq_to_gpio(irq);
+       u32 u;
+
+       u = readl(GPIO_EDGE_MASK(pin));
+       u |= 1 << (pin & 31);
+       writel(u, GPIO_EDGE_MASK(pin));
+}
+
+static void gpio_irq_level_mask(u32 irq)
+{
+       int pin = irq_to_gpio(irq);
+       u32 u;
+
+       u = readl(GPIO_LEVEL_MASK(pin));
+       u &= ~(1 << (pin & 31));
+       writel(u, GPIO_LEVEL_MASK(pin));
+}
+
+static void gpio_irq_level_unmask(u32 irq)
+{
+       int pin = irq_to_gpio(irq);
+       u32 u;
+
+       u = readl(GPIO_LEVEL_MASK(pin));
+       u |= 1 << (pin & 31);
+       writel(u, GPIO_LEVEL_MASK(pin));
+}
+
+static int gpio_irq_set_type(u32 irq, u32 type)
+{
+       int pin = irq_to_gpio(irq);
+       struct irq_desc *desc;
+       u32 u;
+
+       u = readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31));
+       if (!u) {
+               printk(KERN_ERR "orion gpio_irq_set_type failed "
+                               "(irq %d, pin %d).\n", irq, pin);
+               return -EINVAL;
+       }
+
+       desc = irq_desc + irq;
+
+       /*
+        * Set edge/level type.
+        */
+       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+               desc->chip = &orion_gpio_irq_edge_chip;
+       } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+               desc->chip = &orion_gpio_irq_level_chip;
+       } else {
+               printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type);
+               return -EINVAL;
+       }
+
+       /*
+        * Configure interrupt polarity.
+        */
+       if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) {
+               u = readl(GPIO_IN_POL(pin));
+               u &= ~(1 << (pin & 31));
+               writel(u, GPIO_IN_POL(pin));
+       } else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) {
+               u = readl(GPIO_IN_POL(pin));
+               u |= 1 << (pin & 31);
+               writel(u, GPIO_IN_POL(pin));
+       } else if (type == IRQ_TYPE_EDGE_BOTH) {
+               u32 v;
+
+               v = readl(GPIO_IN_POL(pin)) ^ readl(GPIO_DATA_IN(pin));
+
+               /*
+                * set initial polarity based on current input level
+                */
+               u = readl(GPIO_IN_POL(pin));
+               if (v & (1 << (pin & 31)))
+                       u |= 1 << (pin & 31);           /* falling */
+               else
+                       u &= ~(1 << (pin & 31));        /* rising */
+               writel(u, GPIO_IN_POL(pin));
+       }
+
+       desc->status = (desc->status & ~IRQ_TYPE_SENSE_MASK) | type;
+
+       return 0;
+}
+
+struct irq_chip orion_gpio_irq_edge_chip = {
+       .name           = "orion_gpio_irq_edge",
+       .ack            = gpio_irq_edge_ack,
+       .mask           = gpio_irq_edge_mask,
+       .unmask         = gpio_irq_edge_unmask,
+       .set_type       = gpio_irq_set_type,
+};
+
+struct irq_chip orion_gpio_irq_level_chip = {
+       .name           = "orion_gpio_irq_level",
+       .mask           = gpio_irq_level_mask,
+       .mask_ack       = gpio_irq_level_mask,
+       .unmask         = gpio_irq_level_unmask,
+       .set_type       = gpio_irq_set_type,
+};
+
+void orion_gpio_irq_handler(int pinoff)
+{
+       u32 cause;
+       int pin;
+
+       cause = readl(GPIO_DATA_IN(pinoff)) & readl(GPIO_LEVEL_MASK(pinoff));
+       cause |= readl(GPIO_EDGE_CAUSE(pinoff)) & readl(GPIO_EDGE_MASK(pinoff));
+
+       for (pin = pinoff; pin < pinoff + 8; pin++) {
+               int irq = gpio_to_irq(pin);
+               struct irq_desc *desc = irq_desc + irq;
+
+               if (!(cause & (1 << (pin & 31))))
+                       continue;
+
+               if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
+                       /* Swap polarity (race with GPIO line) */
+                       u32 polarity;
+
+                       polarity = readl(GPIO_IN_POL(pin));
+                       polarity ^= 1 << (pin & 31);
+                       writel(polarity, GPIO_IN_POL(pin));
+               }
+               desc_handle_irq(irq, desc);
+       }
+}
index 64343051095ae03f729e30392ad156dc5b44348c..4ec668e774601920f8a6a4371391dd02fb02e781 100644 (file)
 
 #include <linux/mbus.h>
 
+enum orion_ehci_phy_ver {
+       EHCI_PHY_ORION,
+       EHCI_PHY_DD,
+       EHCI_PHY_KW,
+       EHCI_PHY_NA,
+};
+
 struct orion_ehci_data {
        struct mbus_dram_target_info    *dram;
+       enum orion_ehci_phy_ver phy_version;
 };
 
 
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
new file mode 100644 (file)
index 0000000..54deaf2
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/arm/plat-orion/include/plat/gpio.h
+ *
+ * Marvell Orion SoC GPIO handling.
+ *
+ * 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 __PLAT_GPIO_H
+#define __PLAT_GPIO_H
+
+/*
+ * GENERIC_GPIO primitives.
+ */
+int gpio_request(unsigned pin, const char *label);
+void gpio_free(unsigned pin);
+int gpio_direction_input(unsigned pin);
+int gpio_direction_output(unsigned pin, int value);
+int gpio_get_value(unsigned pin);
+void gpio_set_value(unsigned pin, int value);
+
+/*
+ * Orion-specific GPIO API extensions.
+ */
+void orion_gpio_set_unused(unsigned pin);
+void orion_gpio_set_valid(unsigned pin, int valid);
+void orion_gpio_set_blink(unsigned pin, int blink);
+
+/*
+ * GPIO interrupt handling.
+ */
+extern struct irq_chip orion_gpio_irq_edge_chip;
+extern struct irq_chip orion_gpio_irq_level_chip;
+void orion_gpio_irq_handler(int irqoff);
+
+
+#endif
index 31656c33e05ebdb60994a391711203f44bf69901..de9383814e5ef15db9cc36b20ee7e84cf49819b2 100644 (file)
@@ -6,34 +6,32 @@
 
 config PLAT_S3C
        bool
-       depends on ARCH_S3C2410
-       default y if ARCH_S3C2410
+       depends on ARCH_S3C2410 || ARCH_S3C24A0 || ARCH_S3C64XX
+       default y
        select NO_IOPORT
        help
          Base platform code for any Samsung S3C device
 
 # low-level serial option nodes
 
+if PLAT_S3C
+
 config CPU_LLSERIAL_S3C2410_ONLY
        bool
-       depends on ARCH_S3C2410
        default y if CPU_LLSERIAL_S3C2410 && !CPU_LLSERIAL_S3C2440
 
 config CPU_LLSERIAL_S3C2440_ONLY
        bool
-       depends on ARCH_S3C2410
        default y if CPU_LLSERIAL_S3C2440 && !CPU_LLSERIAL_S3C2410
 
 config CPU_LLSERIAL_S3C2410
        bool
-       depends on ARCH_S3C2410
        help
          Selected if there is an S3C2410 (or register compatible) serial
          low-level implementation needed
 
 config CPU_LLSERIAL_S3C2440
        bool
-       depends on ARCH_S3C2410
        help
          Selected if there is an S3C2440 (or register compatible) serial
          low-level implementation needed
@@ -44,7 +42,7 @@ comment "Boot options"
 
 config S3C_BOOT_WATCHDOG
        bool "S3C Initialisation watchdog"
-       depends on PLAT_S3C && S3C2410_WATCHDOG
+       depends on S3C2410_WATCHDOG
        help
          Say y to enable the watchdog during the kernel decompression
          stage. If the kernel fails to uncompress, then the watchdog
@@ -52,16 +50,22 @@ config S3C_BOOT_WATCHDOG
 
 config S3C_BOOT_ERROR_RESET
        bool "S3C Reboot on decompression error"
-       depends on PLAT_S3C
        help
          Say y here to use the watchdog to reset the system if the
          kernel decompressor detects an error during decompression.
 
+config S3C_BOOT_UART_FORCE_FIFO
+       bool "Force UART FIFO on during boot process"
+       default y
+       help
+         Say Y here to force the UART FIFOs on during the kernel
+        uncompressor
+
 comment "Power management"
 
 config S3C2410_PM_DEBUG
        bool "S3C2410 PM Suspend debug"
-       depends on PLAT_S3C && PM
+       depends on PM
        help
          Say Y here if you want verbose debugging from the PM Suspend and
          Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
@@ -69,7 +73,7 @@ config S3C2410_PM_DEBUG
 
 config S3C2410_PM_CHECK
        bool "S3C2410 PM Suspend Memory CRC"
-       depends on PLAT_S3C && PM && CRC32
+       depends on PM && CRC32
        help
          Enable the PM code's memory area checksum over sleep. This option
          will generate CRCs of all blocks of memory, and store them before
@@ -83,7 +87,7 @@ config S3C2410_PM_CHECK
 
 config S3C2410_PM_CHECK_CHUNKSIZE
        int "S3C2410 PM Suspend CRC Chunksize (KiB)"
-       depends on PLAT_S3C && PM && S3C2410_PM_CHECK
+       depends on PM && S3C2410_PM_CHECK
        default 64
        help
          Set the chunksize in Kilobytes of the CRC for checking memory
@@ -95,10 +99,77 @@ config S3C2410_PM_CHECK_CHUNKSIZE
 
 config S3C_LOWLEVEL_UART_PORT
        int "S3C UART to use for low-level messages"
-       depends on PLAT_S3C
        default 0
        help
          Choice of which UART port to use for the low-level messages,
          such as the `Uncompressing...` at start time. The value of
          this configuration should be between zero and two. The port
          must have been initialised by the boot-loader before use.
+
+# options for gpiolib support
+
+config S3C_GPIO_SPACE
+       int "Space between gpio banks"
+       default 0
+       help
+         Add a number of spare GPIO entries between each bank for debugging
+         purposes. This allows any problems where an counter overflows from
+         one bank to another to be caught, at the expense of using a little
+         more memory.
+
+config S3C_GPIO_TRACK
+       bool
+       help
+         Internal configuration option to enable the s3c specific gpio
+         chip tracking if the platform requires it.
+
+config S3C_GPIO_PULL_UPDOWN
+       bool
+       help
+         Internal configuration to enable the correct GPIO pull helper
+
+config S3C_GPIO_PULL_DOWN
+       bool
+       help
+         Internal configuration to enable the correct GPIO pull helper
+
+config S3C_GPIO_PULL_UP
+       bool
+       help
+         Internal configuration to enable the correct GPIO pull helper
+
+config S3C_GPIO_CFG_S3C24XX
+       bool
+       help
+         Internal configuration to enable S3C24XX style GPIO configuration
+         functions.
+
+config S3C_GPIO_CFG_S3C64XX
+       bool
+       help
+         Internal configuration to enable S3C64XX style GPIO configuration
+         functions.
+
+# device definitions to compile in
+
+config S3C_DEV_HSMMC
+       bool
+       help
+         Compile in platform device definitions for HSMMC code
+
+config S3C_DEV_HSMMC1
+       bool
+       help
+         Compile in platform device definitions for HSMMC channel 1
+
+config S3C_DEV_I2C1
+       bool
+       help
+         Compile in platform device definitions for I2C channel 1
+
+config S3C_DEV_FB
+       bool
+       help
+         Compile in platform device definition for framebuffer
+
+endif
index f03d7b35ba3773c7699bc4fffafb8e2396b09945..39195f972d5ed8e7c5fc7f8dc7f3c2525c781c2e 100644 (file)
@@ -1,3 +1,27 @@
-# dummy makefile, currently just including asm/arm/plat-s3c/include/plat
+# arch/arm/plat-s3c/Makefile
+#
+# Copyright 2008 Simtec Electronics
+#
+# Licensed under GPLv2
 
-obj-n  := dummy.o
+obj-y                          :=
+obj-m                          :=
+obj-n                          :=
+obj-                           :=
+
+# Core support for all Samsung SoCs
+
+obj-y                          +=  init.o
+obj-y                          += time.o
+obj-y                          += clock.o
+obj-y                          += pwm-clock.o
+obj-y                          += gpio.o
+obj-y                          += gpio-config.o
+
+# devices
+
+obj-$(CONFIG_S3C_DEV_HSMMC)    += dev-hsmmc.o
+obj-$(CONFIG_S3C_DEV_HSMMC1)   += dev-hsmmc1.o
+obj-y                          += dev-i2c0.o
+obj-$(CONFIG_S3C_DEV_I2C1)     += dev-i2c1.o
+obj-$(CONFIG_S3C_DEV_FB)       += dev-fb.o
diff --git a/arch/arm/plat-s3c/clock.c b/arch/arm/plat-s3c/clock.c
new file mode 100644 (file)
index 0000000..b6be76e
--- /dev/null
@@ -0,0 +1,368 @@
+/* linux/arch/arm/plat-s3c24xx/clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX Core clock control support
+ *
+ * Based on, and code from linux/arch/arm/mach-versatile/clock.c
+ **
+ **  Copyright (C) 2004 ARM Limited.
+ **  Written by Deep Blue Solutions Limited.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/irq.h>
+
+#include <plat/cpu-freq.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/* clock information */
+
+static LIST_HEAD(clocks);
+
+/* We originally used an mutex here, but some contexts (see resume)
+ * are calling functions such as clk_set_parent() with IRQs disabled
+ * causing an BUG to be triggered.
+ */
+DEFINE_SPINLOCK(clocks_lock);
+
+/* enable and disable calls for use with the clk struct */
+
+static int clk_null_enable(struct clk *clk, int enable)
+{
+       return 0;
+}
+
+/* Clock API calls */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       struct clk *p;
+       struct clk *clk = ERR_PTR(-ENOENT);
+       int idno;
+
+       if (dev == NULL || dev->bus != &platform_bus_type)
+               idno = -1;
+       else
+               idno = to_platform_device(dev)->id;
+
+       spin_lock(&clocks_lock);
+
+       list_for_each_entry(p, &clocks, list) {
+               if (p->id == idno &&
+                   strcmp(id, p->name) == 0 &&
+                   try_module_get(p->owner)) {
+                       clk = p;
+                       break;
+               }
+       }
+
+       /* check for the case where a device was supplied, but the
+        * clock that was being searched for is not device specific */
+
+       if (IS_ERR(clk)) {
+               list_for_each_entry(p, &clocks, list) {
+                       if (p->id == -1 && strcmp(id, p->name) == 0 &&
+                           try_module_get(p->owner)) {
+                               clk = p;
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock(&clocks_lock);
+       return clk;
+}
+
+void clk_put(struct clk *clk)
+{
+       module_put(clk->owner);
+}
+
+int clk_enable(struct clk *clk)
+{
+       if (IS_ERR(clk) || clk == NULL)
+               return -EINVAL;
+
+       clk_enable(clk->parent);
+
+       spin_lock(&clocks_lock);
+
+       if ((clk->usage++) == 0)
+               (clk->enable)(clk, 1);
+
+       spin_unlock(&clocks_lock);
+       return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+       if (IS_ERR(clk) || clk == NULL)
+               return;
+
+       spin_lock(&clocks_lock);
+
+       if ((--clk->usage) == 0)
+               (clk->enable)(clk, 0);
+
+       spin_unlock(&clocks_lock);
+       clk_disable(clk->parent);
+}
+
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (IS_ERR(clk))
+               return 0;
+
+       if (clk->rate != 0)
+               return clk->rate;
+
+       if (clk->get_rate != NULL)
+               return (clk->get_rate)(clk);
+
+       if (clk->parent != NULL)
+               return clk_get_rate(clk->parent);
+
+       return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (!IS_ERR(clk) && clk->round_rate)
+               return (clk->round_rate)(clk, rate);
+
+       return rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret;
+
+       if (IS_ERR(clk))
+               return -EINVAL;
+
+       /* We do not default just do a clk->rate = rate as
+        * the clock may have been made this way by choice.
+        */
+
+       WARN_ON(clk->set_rate == NULL);
+
+       if (clk->set_rate == NULL)
+               return -EINVAL;
+
+       spin_lock(&clocks_lock);
+       ret = (clk->set_rate)(clk, rate);
+       spin_unlock(&clocks_lock);
+
+       return ret;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+       return clk->parent;
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = 0;
+
+       if (IS_ERR(clk))
+               return -EINVAL;
+
+       spin_lock(&clocks_lock);
+
+       if (clk->set_parent)
+               ret = (clk->set_parent)(clk, parent);
+
+       spin_unlock(&clocks_lock);
+
+       return ret;
+}
+
+EXPORT_SYMBOL(clk_get);
+EXPORT_SYMBOL(clk_put);
+EXPORT_SYMBOL(clk_enable);
+EXPORT_SYMBOL(clk_disable);
+EXPORT_SYMBOL(clk_get_rate);
+EXPORT_SYMBOL(clk_round_rate);
+EXPORT_SYMBOL(clk_set_rate);
+EXPORT_SYMBOL(clk_get_parent);
+EXPORT_SYMBOL(clk_set_parent);
+
+/* base clocks */
+
+static int clk_default_setrate(struct clk *clk, unsigned long rate)
+{
+       clk->rate = rate;
+       return 0;
+}
+
+struct clk clk_xtal = {
+       .name           = "xtal",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
+};
+
+struct clk clk_ext = {
+       .name           = "ext",
+       .id             = -1,
+};
+
+struct clk clk_epll = {
+       .name           = "epll",
+       .id             = -1,
+};
+
+struct clk clk_mpll = {
+       .name           = "mpll",
+       .id             = -1,
+       .set_rate       = clk_default_setrate,
+};
+
+struct clk clk_upll = {
+       .name           = "upll",
+       .id             = -1,
+       .parent         = NULL,
+       .ctrlbit        = 0,
+};
+
+struct clk clk_f = {
+       .name           = "fclk",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = &clk_mpll,
+       .ctrlbit        = 0,
+       .set_rate       = clk_default_setrate,
+};
+
+struct clk clk_h = {
+       .name           = "hclk",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
+       .set_rate       = clk_default_setrate,
+};
+
+struct clk clk_p = {
+       .name           = "pclk",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = NULL,
+       .ctrlbit        = 0,
+       .set_rate       = clk_default_setrate,
+};
+
+struct clk clk_usb_bus = {
+       .name           = "usb-bus",
+       .id             = -1,
+       .rate           = 0,
+       .parent         = &clk_upll,
+};
+
+
+
+struct clk s3c24xx_uclk = {
+       .name           = "uclk",
+       .id             = -1,
+};
+
+/* initialise the clock system */
+
+int s3c24xx_register_clock(struct clk *clk)
+{
+       clk->owner = THIS_MODULE;
+
+       if (clk->enable == NULL)
+               clk->enable = clk_null_enable;
+
+       /* add to the list of available clocks */
+
+       /* Quick check to see if this clock has already been registered. */
+       BUG_ON(clk->list.prev != clk->list.next);
+
+       spin_lock(&clocks_lock);
+       list_add(&clk->list, &clocks);
+       spin_unlock(&clocks_lock);
+
+       return 0;
+}
+
+int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
+{
+       int fails = 0;
+
+       for (; nr_clks > 0; nr_clks--, clks++) {
+               if (s3c24xx_register_clock(*clks) < 0)
+                       fails++;
+       }
+
+       return fails;
+}
+
+/* initalise all the clocks */
+
+int __init s3c24xx_register_baseclocks(unsigned long xtal)
+{
+       printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
+
+       clk_xtal.rate = xtal;
+
+       /* register our clocks */
+
+       if (s3c24xx_register_clock(&clk_xtal) < 0)
+               printk(KERN_ERR "failed to register master xtal\n");
+
+       if (s3c24xx_register_clock(&clk_mpll) < 0)
+               printk(KERN_ERR "failed to register mpll clock\n");
+
+       if (s3c24xx_register_clock(&clk_upll) < 0)
+               printk(KERN_ERR "failed to register upll clock\n");
+
+       if (s3c24xx_register_clock(&clk_f) < 0)
+               printk(KERN_ERR "failed to register cpu fclk\n");
+
+       if (s3c24xx_register_clock(&clk_h) < 0)
+               printk(KERN_ERR "failed to register cpu hclk\n");
+
+       if (s3c24xx_register_clock(&clk_p) < 0)
+               printk(KERN_ERR "failed to register cpu pclk\n");
+
+       return 0;
+}
+
diff --git a/arch/arm/plat-s3c/dev-fb.c b/arch/arm/plat-s3c/dev-fb.c
new file mode 100644 (file)
index 0000000..0454b8e
--- /dev/null
@@ -0,0 +1,72 @@
+/* linux/arch/arm/plat-s3c/dev-fb.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for framebuffer device
+ *
+ * This program is free software; you can 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/string.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+
+#include <plat/fb.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_fb_resource[] = {
+       [0] = {
+               .start = S3C_PA_FB,
+               .end   = S3C_PA_FB + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_LCD_VSYNC,
+               .end   = IRQ_LCD_VSYNC,
+               .flags = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start = IRQ_LCD_FIFO,
+               .end   = IRQ_LCD_FIFO,
+               .flags = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start = IRQ_LCD_SYSTEM,
+               .end   = IRQ_LCD_SYSTEM,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c_device_fb = {
+       .name             = "s3c-fb",
+       .id               = -1,
+       .num_resources    = ARRAY_SIZE(s3c_fb_resource),
+       .resource         = s3c_fb_resource,
+       .dev.dma_mask     = &s3c_device_fb.dev.coherent_dma_mask,
+       .dev.coherent_dma_mask = 0xffffffffUL,
+};
+
+void __init s3c_fb_set_platdata(struct s3c_fb_platdata *pd)
+{
+       struct s3c_fb_platdata *npd;
+
+       if (!pd) {
+               printk(KERN_ERR "%s: no platform data\n", __func__);
+               return;
+       }
+
+       npd = kmemdup(pd, sizeof(struct s3c_fb_platdata), GFP_KERNEL);
+       if (!npd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+
+       s3c_device_fb.dev.platform_data = npd;
+}
diff --git a/arch/arm/plat-s3c/dev-hsmmc.c b/arch/arm/plat-s3c/dev-hsmmc.c
new file mode 100644 (file)
index 0000000..4c05b39
--- /dev/null
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-s3c/dev-hsmmc.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for hsmmc devices
+ *
+ * This program is free software; you can 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/mmc/host.h>
+
+#include <mach/map.h>
+#include <plat/sdhci.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#define S3C_SZ_HSMMC   (0x1000)
+
+static struct resource s3c_hsmmc_resource[] = {
+       [0] = {
+               .start = S3C_PA_HSMMC0,
+               .end   = S3C_PA_HSMMC0 + S3C_SZ_HSMMC - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_HSMMC0,
+               .end   = IRQ_HSMMC0,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 s3c_device_hsmmc_dmamask = 0xffffffffUL;
+
+struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = {
+       .max_width      = 4,
+       .host_caps      = (MMC_CAP_4_BIT_DATA |
+                          MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+};
+
+struct platform_device s3c_device_hsmmc0 = {
+       .name           = "s3c-sdhci",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s3c_hsmmc_resource),
+       .resource       = s3c_hsmmc_resource,
+       .dev            = {
+               .dma_mask               = &s3c_device_hsmmc_dmamask,
+               .coherent_dma_mask      = 0xffffffffUL,
+               .platform_data          = &s3c_hsmmc0_def_platdata,
+       },
+};
+
+void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd)
+{
+       struct s3c_sdhci_platdata *set = &s3c_hsmmc0_def_platdata;
+
+       set->max_width = pd->max_width;
+
+       if (pd->cfg_gpio)
+               set->cfg_gpio = pd->cfg_gpio;
+       if (pd->cfg_card)
+               set->cfg_card = pd->cfg_card;
+}
diff --git a/arch/arm/plat-s3c/dev-hsmmc1.c b/arch/arm/plat-s3c/dev-hsmmc1.c
new file mode 100644 (file)
index 0000000..e49bc4c
--- /dev/null
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-s3c/dev-hsmmc1.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for hsmmc device 1
+ *
+ * This program is free software; you can 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/mmc/host.h>
+
+#include <mach/map.h>
+#include <plat/sdhci.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+#define S3C_SZ_HSMMC   (0x1000)
+
+static struct resource s3c_hsmmc1_resource[] = {
+       [0] = {
+               .start = S3C_PA_HSMMC1,
+               .end   = S3C_PA_HSMMC1 + S3C_SZ_HSMMC - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_HSMMC1,
+               .end   = IRQ_HSMMC1,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static u64 s3c_device_hsmmc1_dmamask = 0xffffffffUL;
+
+struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata = {
+       .max_width      = 4,
+       .host_caps      = (MMC_CAP_4_BIT_DATA |
+                          MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+};
+
+struct platform_device s3c_device_hsmmc1 = {
+       .name           = "s3c-sdhci",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(s3c_hsmmc1_resource),
+       .resource       = s3c_hsmmc1_resource,
+       .dev            = {
+               .dma_mask               = &s3c_device_hsmmc1_dmamask,
+               .coherent_dma_mask      = 0xffffffffUL,
+               .platform_data          = &s3c_hsmmc1_def_platdata,
+       },
+};
+
+void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd)
+{
+       struct s3c_sdhci_platdata *set = &s3c_hsmmc1_def_platdata;
+
+       set->max_width = pd->max_width;
+
+       if (pd->cfg_gpio)
+               set->cfg_gpio = pd->cfg_gpio;
+       if (pd->cfg_card)
+               set->cfg_card = pd->cfg_card;
+}
diff --git a/arch/arm/plat-s3c/dev-i2c0.c b/arch/arm/plat-s3c/dev-i2c0.c
new file mode 100644 (file)
index 0000000..2c0128c
--- /dev/null
@@ -0,0 +1,71 @@
+/* linux/arch/arm/plat-s3c/dev-i2c0.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for i2c device 0
+ *
+ * This program is free software; you can 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/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+       [0] = {
+               .start = S3C_PA_IIC,
+               .end   = S3C_PA_IIC + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_IIC,
+               .end   = IRQ_IIC,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c_device_i2c0 = {
+       .name             = "s3c2410-i2c",
+#ifdef CONFIG_S3C_DEV_I2C1
+       .id               = 0,
+#else
+       .id               = -1,
+#endif
+       .num_resources    = ARRAY_SIZE(s3c_i2c_resource),
+       .resource         = s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
+       .flags          = 0,
+       .slave_addr     = 0x10,
+       .bus_freq       = 100*1000,
+       .max_freq       = 400*1000,
+       .sda_delay      = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
+};
+
+void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+       struct s3c2410_platform_i2c *npd;
+
+       if (!pd)
+               pd = &default_i2c_data0;
+
+       npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+       if (!npd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+       else if (!npd->cfg_gpio)
+               npd->cfg_gpio = s3c_i2c0_cfg_gpio;
+
+       s3c_device_i2c0.dev.platform_data = npd;
+}
diff --git a/arch/arm/plat-s3c/dev-i2c1.c b/arch/arm/plat-s3c/dev-i2c1.c
new file mode 100644 (file)
index 0000000..9658fb0
--- /dev/null
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-s3c/dev-i2c1.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series device definition for i2c device 1
+ *
+ * This program is free software; you can 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/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+       [0] = {
+               .start = S3C_PA_IIC1,
+               .end   = S3C_PA_IIC1 + SZ_4K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_IIC1,
+               .end   = IRQ_IIC1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device s3c_device_i2c1 = {
+       .name             = "s3c2410-i2c",
+       .id               = 1,
+       .num_resources    = ARRAY_SIZE(s3c_i2c_resource),
+       .resource         = s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data1 __initdata = {
+       .flags          = 0,
+       .bus_num        = 1,
+       .slave_addr     = 0x10,
+       .bus_freq       = 100*1000,
+       .max_freq       = 400*1000,
+       .sda_delay      = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
+};
+
+void __init s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+       struct s3c2410_platform_i2c *npd;
+
+       if (!pd)
+               pd = &default_i2c_data1;
+
+       npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+       if (!npd)
+               printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+       else if (!npd->cfg_gpio)
+               npd->cfg_gpio = s3c_i2c1_cfg_gpio;
+
+       s3c_device_i2c1.dev.platform_data = npd;
+}
diff --git a/arch/arm/plat-s3c/gpio-config.c b/arch/arm/plat-s3c/gpio-config.c
new file mode 100644 (file)
index 0000000..7642b97
--- /dev/null
@@ -0,0 +1,163 @@
+/* linux/arch/arm/plat-s3c/gpio-config.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series GPIO configuration core
+ *
+ * This program is free software; you can 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/gpio.h>
+#include <linux/io.h>
+
+#include <mach/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
+{
+       struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
+       unsigned long flags;
+       int offset;
+       int ret;
+
+       if (!chip)
+               return -EINVAL;
+
+       offset = pin - chip->chip.base;
+
+       local_irq_save(flags);
+       ret = s3c_gpio_do_setcfg(chip, offset, config);
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull)
+{
+       struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
+       unsigned long flags;
+       int offset, ret;
+
+       if (!chip)
+               return -EINVAL;
+
+       offset = pin - chip->chip.base;
+
+       local_irq_save(flags);
+       ret = s3c_gpio_do_setpull(chip, offset, pull);
+       local_irq_restore(flags);
+
+       return ret;
+}
+
+#ifdef CONFIG_S3C_GPIO_CFG_S3C24XX
+int s3c_gpio_setcfg_s3c24xx_banka(struct s3c_gpio_chip *chip,
+                                 unsigned int off, unsigned int cfg)
+{
+       void __iomem *reg = chip->base;
+       unsigned int shift = off;
+       u32 con;
+
+       if (s3c_gpio_is_cfg_special(cfg)) {
+               cfg &= 0xf;
+
+               /* Map output to 0, and SFN2 to 1 */
+               cfg -= 1;
+               if (cfg > 1)
+                       return -EINVAL;
+
+               cfg <<= shift;
+       }
+
+       con = __raw_readl(reg);
+       con &= ~(0x1 << shift);
+       con |= cfg;
+       __raw_writel(con, reg);
+
+       return 0;
+}
+
+int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,
+                           unsigned int off, unsigned int cfg)
+{
+       void __iomem *reg = chip->base;
+       unsigned int shift = off * 2;
+       u32 con;
+
+       if (s3c_gpio_is_cfg_special(cfg)) {
+               cfg &= 0xf;
+               if (cfg > 3)
+                       return -EINVAL;
+
+               cfg <<= shift;
+       }
+
+       con = __raw_readl(reg);
+       con &= ~(0x3 << shift);
+       con |= cfg;
+       __raw_writel(con, reg);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
+int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
+                                unsigned int off, unsigned int cfg)
+{
+       void __iomem *reg = chip->base;
+       unsigned int shift = (off & 7) * 4;
+       u32 con;
+
+       if (off < 8 && chip->chip.ngpio >= 8)
+               reg -= 4;
+
+       if (s3c_gpio_is_cfg_special(cfg)) {
+               cfg &= 0xf;
+               cfg <<= shift;
+       }
+
+       con = __raw_readl(reg);
+       con &= ~(0xf << shift);
+       con |= cfg;
+       __raw_writel(con, reg);
+
+       return 0;
+}
+#endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */
+
+#ifdef CONFIG_S3C_GPIO_PULL_UPDOWN
+int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
+                           unsigned int off, s3c_gpio_pull_t pull)
+{
+       void __iomem *reg = chip->base + 0x08;
+       int shift = off * 2;
+       u32 pup;
+
+       pup = __raw_readl(reg);
+       pup &= ~(3 << shift);
+       pup |= pull << shift;
+       __raw_writel(pup, reg);
+
+       return 0;
+}
+
+s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
+                                       unsigned int off)
+{
+       void __iomem *reg = chip->base + 0x08;
+       int shift = off * 2;
+       u32 pup = __raw_readl(reg);
+
+       pup >>= shift;
+       pup &= 0x3;
+       return (__force s3c_gpio_pull_t)pup;
+}
+#endif
diff --git a/arch/arm/plat-s3c/gpio.c b/arch/arm/plat-s3c/gpio.c
new file mode 100644 (file)
index 0000000..d71dd6d
--- /dev/null
@@ -0,0 +1,147 @@
+/* linux/arch/arm/plat-s3c/gpio.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series GPIO core
+ *
+ * This program is free software; you can 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/io.h>
+#include <linux/gpio.h>
+
+#include <plat/gpio-core.h>
+
+#ifdef CONFIG_S3C_GPIO_TRACK
+struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END];
+
+static __init void s3c_gpiolib_track(struct s3c_gpio_chip *chip)
+{
+       unsigned int gpn;
+       int i;
+
+       gpn = chip->chip.base;
+       for (i = 0; i < chip->chip.ngpio; i++, gpn++) {
+               BUG_ON(gpn > ARRAY_SIZE(s3c_gpios));
+               s3c_gpios[gpn] = chip;
+       }
+}
+#endif /* CONFIG_S3C_GPIO_TRACK */
+
+/* Default routines for controlling GPIO, based on the original S3C24XX
+ * GPIO functions which deal with the case where each gpio bank of the
+ * chip is as following:
+ *
+ * base + 0x00: Control register, 2 bits per gpio
+ *             gpio n: 2 bits starting at (2*n)
+ *             00 = input, 01 = output, others mean special-function
+ * base + 0x04: Data register, 1 bit per gpio
+ *             bit n: data bit n
+*/
+
+static int s3c_gpiolib_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long flags;
+       unsigned long con;
+
+       local_irq_save(flags);
+
+       con = __raw_readl(base + 0x00);
+       con &= ~(3 << (offset * 2));
+
+       __raw_writel(con, base + 0x00);
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+static int s3c_gpiolib_output(struct gpio_chip *chip,
+                             unsigned offset, int value)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long flags;
+       unsigned long dat;
+       unsigned long con;
+
+       local_irq_save(flags);
+
+       dat = __raw_readl(base + 0x04);
+       dat &= ~(1 << offset);
+       if (value)
+               dat |= 1 << offset;
+       __raw_writel(dat, base + 0x04);
+
+       con = __raw_readl(base + 0x00);
+       con &= ~(3 << (offset * 2));
+       con |= 1 << (offset * 2);
+
+       __raw_writel(con, base + 0x00);
+       __raw_writel(dat, base + 0x04);
+
+       local_irq_restore(flags);
+       return 0;
+}
+
+static void s3c_gpiolib_set(struct gpio_chip *chip,
+                           unsigned offset, int value)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long flags;
+       unsigned long dat;
+
+       local_irq_save(flags);
+
+       dat = __raw_readl(base + 0x04);
+       dat &= ~(1 << offset);
+       if (value)
+               dat |= 1 << offset;
+       __raw_writel(dat, base + 0x04);
+
+       local_irq_restore(flags);
+}
+
+static int s3c_gpiolib_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       unsigned long val;
+
+       val = __raw_readl(ourchip->base + 0x04);
+       val >>= offset;
+       val &= 1;
+
+       return val;
+}
+
+__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
+{
+       struct gpio_chip *gc = &chip->chip;
+       int ret;
+
+       BUG_ON(!chip->base);
+       BUG_ON(!gc->label);
+       BUG_ON(!gc->ngpio);
+
+       if (!gc->direction_input)
+               gc->direction_input = s3c_gpiolib_input;
+       if (!gc->direction_output)
+               gc->direction_output = s3c_gpiolib_output;
+       if (!gc->set)
+               gc->set = s3c_gpiolib_set;
+       if (!gc->get)
+               gc->get = s3c_gpiolib_get;
+
+       /* gpiochip_add() prints own failure message on error. */
+       ret = gpiochip_add(gc);
+       if (ret >= 0)
+               s3c_gpiolib_track(chip);
+}
diff --git a/arch/arm/plat-s3c/include/mach/io.h b/arch/arm/plat-s3c/include/mach/io.h
new file mode 100644 (file)
index 0000000..f6a5363
--- /dev/null
@@ -0,0 +1,18 @@
+/* arch/arm/plat-s3c/include/mach/io.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben-linux@fluff.org>
+ *
+ * Default IO routines for plat-s3c based systems, such as S3C24A0
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/* No current ISA/PCI bus support. */
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
+
+#define IO_SPACE_LIMIT (0xFFFFFFFF)
+
+#endif
similarity index 91%
rename from arch/arm/mach-s3c2410/include/mach/vmalloc.h
rename to arch/arm/plat-s3c/include/mach/vmalloc.h
index 315b0078a34d68e9f020157721cf26b836817993..bfd2ca6e3074a6d4abd4d5706dcc4bf9d0031099 100644 (file)
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/vmalloc.h
+/* arch/arm/plat-s3c/include/mach/vmalloc.h
  *
  * from arch/arm/mach-iop3xx/include/mach/vmalloc.h
  *
diff --git a/arch/arm/plat-s3c/include/plat/adc.h b/arch/arm/plat-s3c/include/plat/adc.h
new file mode 100644 (file)
index 0000000..43df2a4
--- /dev/null
@@ -0,0 +1,29 @@
+/* arch/arm/plat-s3c/include/plat/adc.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simnte.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX ADC driver information
+ *
+ * This program is free software; you can 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_PLAT_ADC_H
+#define __ASM_PLAT_ADC_H __FILE__
+
+struct s3c_adc_client;
+
+extern int s3c_adc_start(struct s3c_adc_client *client,
+                        unsigned int channel, unsigned int nr_samples);
+
+extern struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
+                                              void (*select)(unsigned selected),
+                                              void (*conv)(unsigned d0, unsigned d1),
+                                              unsigned int is_ts);
+
+extern void s3c_adc_release(struct s3c_adc_client *client);
+
+#endif /* __ASM_PLAT_ADC_H */
similarity index 66%
rename from arch/arm/plat-s3c24xx/include/plat/clock.h
rename to arch/arm/plat-s3c/include/plat/clock.h
index 235b753cd877a94d290201196e9a845be9733853..a10622eed43ab10ab2b5fd13474d6f7a27af71fe 100644 (file)
@@ -1,5 +1,4 @@
-/* linux/include/asm-arm/plat-s3c24xx/clock.h
- * linux/arch/arm/mach-s3c2410/clock.h
+/* linux/arch/arm/plat-s3c/include/plat/clock.h
  *
  * Copyright (c) 2004-2005 Simtec Electronics
  *     http://www.simtec.co.uk/products/SWLINUX/
@@ -10,6 +9,8 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/spinlock.h>
+
 struct clk {
        struct list_head      list;
        struct module        *owner;
@@ -44,21 +45,44 @@ extern struct clk clk_h;
 extern struct clk clk_p;
 extern struct clk clk_mpll;
 extern struct clk clk_upll;
+extern struct clk clk_epll;
 extern struct clk clk_xtal;
+extern struct clk clk_ext;
+
+/* S3C64XX specific clocks */
+extern struct clk clk_27m;
+extern struct clk clk_48m;
 
 /* exports for arch/arm/mach-s3c2410
  *
  * Please DO NOT use these outside of arch/arm/mach-s3c2410
 */
 
-extern struct mutex clocks_mutex;
+extern spinlock_t clocks_lock;
 
 extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
 
 extern int s3c24xx_register_clock(struct clk *clk);
 extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
 
-extern int s3c24xx_setup_clocks(unsigned long xtal,
-                               unsigned long fclk,
-                               unsigned long hclk,
-                               unsigned long pclk);
+extern int s3c24xx_register_baseclocks(unsigned long xtal);
+
+extern void s3c64xx_register_clocks(void);
+
+extern void s3c24xx_setup_clocks(unsigned long fclk,
+                                unsigned long hclk,
+                                unsigned long pclk);
+
+extern void s3c2410_setup_clocks(void);
+extern void s3c2412_setup_clocks(void);
+extern void s3c244x_setup_clocks(void);
+extern void s3c2443_setup_clocks(void);
+
+/* S3C64XX specific functions and clocks */
+
+extern int s3c64xx_sclk_ctrl(struct clk *clk, int enable);
+
+/* Init for pwm clock code */
+
+extern void s3c_pwmclk_init(void);
+
diff --git a/arch/arm/plat-s3c/include/plat/cpu-freq.h b/arch/arm/plat-s3c/include/plat/cpu-freq.h
new file mode 100644 (file)
index 0000000..c86a133
--- /dev/null
@@ -0,0 +1,94 @@
+/* arch/arm/plat-s3c/include/plat/cpu-freq.h
+ *
+ * Copyright (c) 2006,2007 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C CPU frequency scaling support - driver and board
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/cpufreq.h>
+
+struct s3c_cpufreq_info;
+struct s3c_cpufreq_board;
+struct s3c_iotimings;
+
+struct s3c_freq {
+       unsigned long   fclk;
+       unsigned long   armclk;
+       unsigned long   hclk_tns;       /* in 10ths of ns */
+       unsigned long   hclk;
+       unsigned long   pclk;
+};
+
+/* wrapper 'struct cpufreq_freqs' so that any drivers receiving the
+ * notification can use this information that is not provided by just
+ * having the core frequency alone.
+ */
+
+struct s3c_cpufreq_freqs {
+       struct cpufreq_freqs    freqs;
+       struct s3c_freq         old;
+       struct s3c_freq         new;
+};
+
+#define to_s3c_cpufreq(_cf) container_of(_cf, struct s3c_cpufreq_freqs, freqs)
+
+struct s3c_clkdivs {
+       int             p_divisor;      /* fclk / pclk */
+       int             h_divisor;      /* fclk / hclk */
+       int             arm_divisor;    /* not all cpus have this. */
+       unsigned char   dvs;            /* using dvs mode to arm. */
+};
+
+#define PLLVAL(_m, _p, _s) (((_m) << 12) | ((_p) << 4) | (_s))
+
+struct s3c_pllval {
+       unsigned long           freq;
+       unsigned long           pll_reg;
+};
+
+struct s3c_cpufreq_config {
+       struct s3c_freq         freq;
+       struct s3c_pllval       pll;
+       struct s3c_clkdivs      divs;
+       struct s3c_cpufreq_info *info;  /* for core, not drivers */
+       struct s3c_cpufreq_board *board;
+};
+
+/* s3c_cpufreq_board
+ *
+ * per-board configuraton information, such as memory refresh and
+ * how to initialise IO timings.
+ */
+struct s3c_cpufreq_board {
+       unsigned int    refresh;        /* refresh period in ns */
+       unsigned int    auto_io:1;      /* automatically init io timings. */
+       unsigned int    need_io:1;      /* set if needs io timing support. */
+
+       /* any non-zero field in here is taken as an upper limit. */
+       struct s3c_freq max;    /* frequency limits */
+};
+
+/* Things depending on frequency scaling. */
+#ifdef CONFIG_CPU_FREQ_S3C
+#define __init_or_cpufreq
+#else
+#define __init_or_cpufreq __init
+#endif
+
+/* Board functions */
+
+#ifdef CONFIG_CPU_FREQ_S3C
+extern int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board);
+#else
+
+static inline int s3c_cpufreq_setboard(struct s3c_cpufreq_board *board)
+{
+       return 0;
+}
+#endif  /* CONFIG_CPU_FREQ_S3C */
similarity index 70%
rename from arch/arm/plat-s3c24xx/include/plat/cpu.h
rename to arch/arm/plat-s3c/include/plat/cpu.h
index 23e420e8bd5bcf1d1aee6fa562374fa6e273426a..e62ae0fcfe56ad0833764a4cd9a4fdfe7a98dffe 100644 (file)
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/plat-s3c24xx/cpu.h
+/* linux/arch/arm/plat-s3c/include/plat/cpu.h
  *
  * Copyright (c) 2004-2005 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
@@ -18,7 +18,7 @@
 #define MHZ (1000*1000)
 #endif
 
-#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
+#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000)
 
 /* forward declaration */
 struct s3c24xx_uart_resources;
@@ -26,11 +26,28 @@ struct platform_device;
 struct s3c2410_uartcfg;
 struct map_desc;
 
+/* per-cpu initialisation function table. */
+
+struct cpu_table {
+       unsigned long   idcode;
+       unsigned long   idmask;
+       void            (*map_io)(void);
+       void            (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
+       void            (*init_clocks)(int xtal);
+       int             (*init)(void);
+       const char      *name;
+};
+
+extern void s3c_init_cpu(unsigned long idcode,
+                        struct cpu_table *cpus, unsigned int cputab_size);
+
 /* core initialisation functions */
 
 extern void s3c24xx_init_irq(void);
+extern void s3c64xx_init_irq(u32 vic0, u32 vic1);
 
 extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
+extern void s3c64xx_init_io(struct map_desc *mach_desc, int size);
 
 extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
index 4aa7e2e6c001a1f55624fdfcb612fa43a96ac405..3634d4e3708b05c0970667ce8647697b05ffc688 100644 (file)
@@ -20,7 +20,7 @@
        .endm
 
 #ifndef fifo_level
-#define fifo_level fifo_level_s3c2410
+#define fifo_level fifo_level_s3c2440
 #endif
 
        .macro  fifo_full_s3c2440 rd, rx
similarity index 79%
rename from arch/arm/plat-s3c24xx/include/plat/devs.h
rename to arch/arm/plat-s3c/include/plat/devs.h
index badaac9d64a8a465d4312f4cf54c6e2d623a6101..6b1b5231511ca9751a913fa6ecaa54c398bd3fbe 100644 (file)
@@ -17,21 +17,26 @@ struct s3c24xx_uart_resources {
 };
 
 extern struct s3c24xx_uart_resources s3c2410_uart_resources[];
+extern struct s3c24xx_uart_resources s3c64xx_uart_resources[];
 
 extern struct platform_device *s3c24xx_uart_devs[];
 extern struct platform_device *s3c24xx_uart_src[];
 
 extern struct platform_device s3c_device_timer[];
 
+extern struct platform_device s3c_device_fb;
 extern struct platform_device s3c_device_usb;
 extern struct platform_device s3c_device_lcd;
 extern struct platform_device s3c_device_wdt;
-extern struct platform_device s3c_device_i2c;
+extern struct platform_device s3c_device_i2c0;
+extern struct platform_device s3c_device_i2c1;
 extern struct platform_device s3c_device_iis;
 extern struct platform_device s3c_device_rtc;
 extern struct platform_device s3c_device_adc;
 extern struct platform_device s3c_device_sdi;
-extern struct platform_device s3c_device_hsmmc;
+extern struct platform_device s3c_device_hsmmc0;
+extern struct platform_device s3c_device_hsmmc1;
+extern struct platform_device s3c_device_hsmmc2;
 
 extern struct platform_device s3c_device_spi0;
 extern struct platform_device s3c_device_spi1;
diff --git a/arch/arm/plat-s3c/include/plat/fb.h b/arch/arm/plat-s3c/include/plat/fb.h
new file mode 100644 (file)
index 0000000..214ff56
--- /dev/null
@@ -0,0 +1,73 @@
+/* linux/arch/arm/plat-s3c/include/plat/fb.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - FB platform data definitions
+ *
+ * This program is free software; you can 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 __PLAT_S3C_FB_H
+#define __PLAT_S3C_FB_H __FILE__
+
+/**
+ * struct s3c_fb_pd_win - per window setup data
+ * @win_mode: The display parameters to initialise (not for window 0)
+ * @virtual_x: The virtual X size.
+ * @virtual_y: The virtual Y size.
+ */
+struct s3c_fb_pd_win {
+       struct fb_videomode     win_mode;
+
+       unsigned short          default_bpp;
+       unsigned short          max_bpp;
+       unsigned short          virtual_x;
+       unsigned short          virtual_y;
+};
+
+/**
+ * struct s3c_fb_platdata -  S3C driver platform specific information
+ * @setup_gpio: Setup the external GPIO pins to the right state to transfer
+ *             the data from the display system to the connected display
+ *             device.
+ * @vidcon0: The base vidcon0 values to control the panel data format.
+ * @vidcon1: The base vidcon1 values to control the panel data output.
+ * @win: The setup data for each hardware window, or NULL for unused.
+ * @display_mode: The LCD output display mode.
+ *
+ * The platform data supplies the video driver with all the information
+ * it requires to work with the display(s) attached to the machine. It
+ * controls the initial mode, the number of display windows (0 is always
+ * the base framebuffer) that are initialised etc.
+ *
+ */
+struct s3c_fb_platdata {
+       void    (*setup_gpio)(void);
+
+       struct s3c_fb_pd_win    *win[S3C_FB_MAX_WIN];
+
+       u32                      vidcon0;
+       u32                      vidcon1;
+};
+
+/**
+ * s3c_fb_set_platdata() - Setup the FB device with platform data.
+ * @pd: The platform data to set. The data is copied from the passed structure
+ *      so the machine data can mark the data __initdata so that any unused
+ *      machines will end up dumping their data at runtime.
+ */
+extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd);
+
+/**
+ * s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD
+ *
+ * Initialise the GPIO for an 24bpp LCD display on the RGB interface.
+ */
+extern void s3c64xx_fb_gpio_setup_24bpp(void);
+
+#endif /* __PLAT_S3C_FB_H */
diff --git a/arch/arm/plat-s3c/include/plat/gpio-cfg-helpers.h b/arch/arm/plat-s3c/include/plat/gpio-cfg-helpers.h
new file mode 100644 (file)
index 0000000..652e2bb
--- /dev/null
@@ -0,0 +1,176 @@
+/* linux/arch/arm/plat-s3c/include/plat/gpio-cfg-helper.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C Platform - GPIO pin configuration helper definitions
+ *
+ * This program is free software; you can 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 is meant for core cpu support, machine or other driver files
+ * should not be including this header.
+ */
+
+#ifndef __PLAT_GPIO_CFG_HELPERS_H
+#define __PLAT_GPIO_CFG_HELPERS_H __FILE__
+
+/* As a note, all gpio configuration functions are entered exclusively, either
+ * with the relevant lock held or the system prevented from doing anything else
+ * by disabling interrupts.
+*/
+
+static inline int s3c_gpio_do_setcfg(struct s3c_gpio_chip *chip,
+                                    unsigned int off, unsigned int config)
+{
+       return (chip->config->set_config)(chip, off, config);
+}
+
+static inline int s3c_gpio_do_setpull(struct s3c_gpio_chip *chip,
+                                     unsigned int off, s3c_gpio_pull_t pull)
+{
+       return (chip->config->set_pull)(chip, off, pull);
+}
+
+/**
+ * s3c_gpio_setcfg_s3c24xx - S3C24XX style GPIO configuration.
+ * @chip: The gpio chip that is being configured.
+ * @off: The offset for the GPIO being configured.
+ * @cfg: The configuration value to set.
+ *
+ * This helper deal with the GPIO cases where the control register
+ * has two bits of configuration per gpio, which have the following
+ * functions:
+ *     00 = input
+ *     01 = output
+ *     1x = special function
+*/
+extern int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,
+                                  unsigned int off, unsigned int cfg);
+
+/**
+ * s3c_gpio_setcfg_s3c24xx_a - S3C24XX style GPIO configuration (Bank A)
+ * @chip: The gpio chip that is being configured.
+ * @off: The offset for the GPIO being configured.
+ * @cfg: The configuration value to set.
+ *
+ * This helper deal with the GPIO cases where the control register
+ * has one bit of configuration for the gpio, where setting the bit
+ * means the pin is in special function mode and unset means output.
+*/
+extern int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip,
+                                    unsigned int off, unsigned int cfg);
+
+/**
+ * s3c_gpio_setcfg_s3c64xx_4bit - S3C64XX 4bit single register GPIO config.
+ * @chip: The gpio chip that is being configured.
+ * @off: The offset for the GPIO being configured.
+ * @cfg: The configuration value to set.
+ *
+ * This helper deal with the GPIO cases where the control register has 4 bits
+ * of control per GPIO, generally in the form of:
+ *     0000 = Input
+ *     0001 = Output
+ *     others = Special functions (dependant on bank)
+ *
+ * Note, since the code to deal with the case where there are two control
+ * registers instead of one, we do not have a seperate set of functions for
+ * each case.
+*/
+extern int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
+                                       unsigned int off, unsigned int cfg);
+
+
+/* Pull-{up,down} resistor controls.
+ *
+ * S3C2410,S3C2440,S3C24A0 = Pull-UP,
+ * S3C2412,S3C2413 = Pull-Down
+ * S3C6400,S3C6410 = Pull-Both [None,Down,Up,Undef]
+ * S3C2443 = Pull-Both [not same as S3C6400]
+ */
+
+/**
+ * s3c_gpio_setpull_1up() - Pull configuration for choice of up or none.
+ * @chip: The gpio chip that is being configured.
+ * @off: The offset for the GPIO being configured.
+ * @param: pull: The pull mode being requested.
+ *
+ * This is a helper function for the case where we have GPIOs with one
+ * bit configuring the presence of a pull-up resistor.
+ */
+extern int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
+                               unsigned int off, s3c_gpio_pull_t pull);
+
+/**
+ * s3c_gpio_setpull_1down() - Pull configuration for choice of down or none
+ * @chip: The gpio chip that is being configured
+ * @off: The offset for the GPIO being configured
+ * @param: pull: The pull mode being requested
+ *
+ * This is a helper function for the case where we have GPIOs with one
+ * bit configuring the presence of a pull-down resistor.
+ */
+extern int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip,
+                                 unsigned int off, s3c_gpio_pull_t pull);
+
+/**
+ * s3c_gpio_setpull_upown() - Pull configuration for choice of up, down or none
+ * @chip: The gpio chip that is being configured.
+ * @off: The offset for the GPIO being configured.
+ * @param: pull: The pull mode being requested.
+ *
+ * This is a helper function for the case where we have GPIOs with two
+ * bits configuring the presence of a pull resistor, in the following
+ * order:
+ *     00 = No pull resistor connected
+ *     01 = Pull-up resistor connected
+ *     10 = Pull-down resistor connected
+ */
+extern int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
+                                  unsigned int off, s3c_gpio_pull_t pull);
+
+
+/**
+ * s3c_gpio_getpull_updown() - Get configuration for choice of up, down or none
+ * @chip: The gpio chip that the GPIO pin belongs to
+ * @off: The offset to the pin to get the configuration of.
+ *
+ * This helper function reads the state of the pull-{up,down} resistor for the
+ * given GPIO in the same case as s3c_gpio_setpull_upown.
+*/
+extern s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,
+                                              unsigned int off);
+
+/**
+ * s3c_gpio_setpull_s3c2443() - Pull configuration for s3c2443.
+ * @chip: The gpio chip that is being configured.
+ * @off: The offset for the GPIO being configured.
+ * @param: pull: The pull mode being requested.
+ *
+ * This is a helper function for the case where we have GPIOs with two
+ * bits configuring the presence of a pull resistor, in the following
+ * order:
+ *     00 = Pull-up resistor connected
+ *     10 = Pull-down resistor connected
+ *     x1 = No pull up resistor
+ */
+extern int s3c_gpio_setpull_s3c2443(struct s3c_gpio_chip *chip,
+                                   unsigned int off, s3c_gpio_pull_t pull);
+
+/**
+ * s3c_gpio_getpull_s3c2443() - Get configuration for s3c2443 pull resistors
+ * @chip: The gpio chip that the GPIO pin belongs to.
+ * @off: The offset to the pin to get the configuration of.
+ *
+ * This helper function reads the state of the pull-{up,down} resistor for the
+ * given GPIO in the same case as s3c_gpio_setpull_upown.
+*/
+extern s3c_gpio_pull_t s3c_gpio_getpull_s3c24xx(struct s3c_gpio_chip *chip,
+                                               unsigned int off);
+
+#endif /* __PLAT_GPIO_CFG_HELPERS_H */
+
diff --git a/arch/arm/plat-s3c/include/plat/gpio-cfg.h b/arch/arm/plat-s3c/include/plat/gpio-cfg.h
new file mode 100644 (file)
index 0000000..29cd6a8
--- /dev/null
@@ -0,0 +1,110 @@
+/* linux/arch/arm/plat-s3c/include/plat/gpio-cfg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C Platform - GPIO pin configuration
+ *
+ * This program is free software; you can 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 file contains the necessary definitions to get the basic gpio
+ * pin configuration done such as setting a pin to input or output or
+ * changing the pull-{up,down} configurations.
+ */
+
+/* Note, this interface is being added to the s3c64xx arch first and will
+ * be added to the s3c24xx systems later.
+ */
+
+#ifndef __PLAT_GPIO_CFG_H
+#define __PLAT_GPIO_CFG_H __FILE__
+
+typedef unsigned int __bitwise__ s3c_gpio_pull_t;
+
+/* forward declaration if gpio-core.h hasn't been included */
+struct s3c_gpio_chip;
+
+/**
+ * struct s3c_gpio_cfg GPIO configuration
+ * @cfg_eint: Configuration setting when used for external interrupt source
+ * @get_pull: Read the current pull configuration for the GPIO
+ * @set_pull: Set the current pull configuraiton for the GPIO
+ * @set_config: Set the current configuration for the GPIO
+ * @get_config: Read the current configuration for the GPIO
+ *
+ * Each chip can have more than one type of GPIO bank available and some
+ * have different capabilites even when they have the same control register
+ * layouts. Provide an point to vector control routine and provide any
+ * per-bank configuration information that other systems such as the
+ * external interrupt code will need.
+ */
+struct s3c_gpio_cfg {
+       unsigned int    cfg_eint;
+
+       s3c_gpio_pull_t (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs);
+       int             (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs,
+                                   s3c_gpio_pull_t pull);
+
+       unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs);
+       int      (*set_config)(struct s3c_gpio_chip *chip, unsigned offs,
+                              unsigned config);
+};
+
+#define S3C_GPIO_SPECIAL_MARK  (0xfffffff0)
+#define S3C_GPIO_SPECIAL(x)    (S3C_GPIO_SPECIAL_MARK | (x))
+
+/* Defines for generic pin configurations */
+#define S3C_GPIO_INPUT (S3C_GPIO_SPECIAL(0))
+#define S3C_GPIO_OUTPUT        (S3C_GPIO_SPECIAL(1))
+#define S3C_GPIO_SFN(x)        (S3C_GPIO_SPECIAL(x))
+
+#define s3c_gpio_is_cfg_special(_cfg) \
+       (((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK)
+
+/**
+ * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
+ * @pin pin The pin number to configure.
+ * @pin to The configuration for the pin's function.
+ *
+ * Configure which function is actually connected to the external
+ * pin, such as an gpio input, output or some form of special function
+ * connected to an internal peripheral block.
+ */
+extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
+
+/* Define values for the pull-{up,down} available for each gpio pin.
+ *
+ * These values control the state of the weak pull-{up,down} resistors
+ * available on most pins on the S3C series. Not all chips support both
+ * up or down settings, and it may be dependant on the chip that is being
+ * used to whether the particular mode is available.
+ */
+#define S3C_GPIO_PULL_NONE     ((__force s3c_gpio_pull_t)0x00)
+#define S3C_GPIO_PULL_DOWN     ((__force s3c_gpio_pull_t)0x01)
+#define S3C_GPIO_PULL_UP       ((__force s3c_gpio_pull_t)0x02)
+
+/**
+ * s3c_gpio_setpull() - set the state of a gpio pin pull resistor
+ * @pin: The pin number to configure the pull resistor.
+ * @pull: The configuration for the pull resistor.
+ *
+ * This function sets the state of the pull-{up,down} resistor for the
+ * specified pin. It will return 0 if successfull, or a negative error
+ * code if the pin cannot support the requested pull setting.
+*/
+extern int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);
+
+/**
+ * s3c_gpio_getpull() - get the pull resistor state of a gpio pin
+ * @pin: The pin number to get the settings for
+ *
+ * Read the pull resistor value for the specified pin.
+*/
+extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin);
+
+#endif /* __PLAT_GPIO_CFG_H */
diff --git a/arch/arm/plat-s3c/include/plat/gpio-core.h b/arch/arm/plat-s3c/include/plat/gpio-core.h
new file mode 100644 (file)
index 0000000..2fc60a5
--- /dev/null
@@ -0,0 +1,77 @@
+/* linux/arch/arm/plat-s3c/include/plat/gpio-core.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C Platform - GPIO core
+ *
+ * This program is free software; you can 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 the core gpiolib support functions that the s3c platforms may
+ * need to extend or change depending on the hardware and the s3c chip
+ * selected at build or found at run time.
+ *
+ * These definitions are not intended for driver inclusion, there is
+ * nothing here that should not live outside the platform and core
+ * specific code.
+*/
+
+struct s3c_gpio_cfg;
+
+/**
+ * struct s3c_gpio_chip - wrapper for specific implementation of gpio
+ * @chip: The chip structure to be exported via gpiolib.
+ * @base: The base pointer to the gpio configuration registers.
+ * @config: special function and pull-resistor control information.
+ *
+ * This wrapper provides the necessary information for the Samsung
+ * specific gpios being registered with gpiolib.
+ */
+struct s3c_gpio_chip {
+       struct gpio_chip        chip;
+       struct s3c_gpio_cfg     *config;
+       void __iomem            *base;
+};
+
+static inline struct s3c_gpio_chip *to_s3c_gpio(struct gpio_chip *gpc)
+{
+       return container_of(gpc, struct s3c_gpio_chip, chip);
+}
+
+/** s3c_gpiolib_add() - add the s3c specific version of a gpio_chip.
+ * @chip: The chip to register
+ *
+ * This is a wrapper to gpiochip_add() that takes our specific gpio chip
+ * information and makes the necessary alterations for the platform and
+ * notes the information for use with the configuration systems and any
+ * other parts of the system.
+ */
+extern void s3c_gpiolib_add(struct s3c_gpio_chip *chip);
+
+/* CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios
+ * for use with the configuration calls, and other parts of the s3c gpiolib
+ * support code.
+ *
+ * Not all s3c support code will need this, as some configurations of cpu
+ * may only support one or two different configuration options and have an
+ * easy gpio to s3c_gpio_chip mapping function. If this is the case, then
+ * the machine support file should provide its own s3c_gpiolib_getchip()
+ * and any other necessary functions.
+ */
+
+#ifdef CONFIG_S3C_GPIO_TRACK
+extern struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END];
+
+static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int chip)
+{
+       return (chip < S3C_GPIO_END) ? s3c_gpios[chip] : NULL;
+}
+#else
+/* machine specific code should provide s3c_gpiolib_getchip */
+
+static inline void s3c_gpiolib_track(struct s3c_gpio_chip *chip) { }
+#endif
diff --git a/arch/arm/plat-s3c/include/plat/iic-core.h b/arch/arm/plat-s3c/include/plat/iic-core.h
new file mode 100644 (file)
index 0000000..36397ca
--- /dev/null
@@ -0,0 +1,35 @@
+/* arch/arm/mach-s3c2410/include/mach/iic-core.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - I2C Controller core functions
+ *
+ * This program is free software; you can 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_IIC_CORE_H
+#define __ASM_ARCH_IIC_CORE_H __FILE__
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s3c_i2c0_setname(char *name)
+{
+       /* currently this device is always compiled in */
+       s3c_device_i2c0.name = name;
+}
+
+static inline void s3c_i2c1_setname(char *name)
+{
+#ifdef CONFIG_S3C_DEV_I2C1
+       s3c_device_i2c1.name = name;
+#endif
+}
+
+#endif /* __ASM_ARCH_IIC_H */
similarity index 51%
rename from include/asm-arm/plat-s3c/iic.h
rename to arch/arm/plat-s3c/include/plat/iic.h
index 5106acaa1d0ebfe1252e54a46ebd206ca6f5729f..dc1dfcb9bc6c63034e0a42750ab334ed72ed06d0 100644 (file)
@@ -28,6 +28,30 @@ struct s3c2410_platform_i2c {
        unsigned long   max_freq;       /* max frequency for the bus */
        unsigned long   min_freq;       /* min frequency for the bus */
        unsigned int    sda_delay;      /* pclks (s3c2440 only) */
+
+       void    (*cfg_gpio)(struct platform_device *dev);
 };
 
+/**
+ * s3c_i2c0_set_platdata - set platform data for i2c0 device
+ * @i2c: The platform data to set, or NULL for default data.
+ *
+ * Register the given platform data for use with the i2c0 device. This
+ * call copies the platform data, so the caller can use __initdata for
+ * their copy.
+ *
+ * This call will set cfg_gpio if is null to the default platform
+ * implementation.
+ *
+ * Any user of s3c_device_i2c0 should call this, even if it is with
+ * NULL to ensure that the device is given the default platform data
+ * as the driver will no longer carry defaults.
+ */
+extern void s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *i2c);
+
+/* defined by architecture to configure gpio */
+extern void s3c_i2c0_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c1_cfg_gpio(struct platform_device *dev);
+
 #endif /* __ASM_ARCH_IIC_H */
diff --git a/arch/arm/plat-s3c/include/plat/regs-fb.h b/arch/arm/plat-s3c/include/plat/regs-fb.h
new file mode 100644 (file)
index 0000000..e9ee599
--- /dev/null
@@ -0,0 +1,366 @@
+/* arch/arm/plat-s3c/include/plat/regs-fb.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C Platform - new-style framebuffer register definitions
+ *
+ * This is the register set for the new style framebuffer interface
+ * found from the S3C2443 onwards into the S3C2416, S3C2450 and the
+ * S3C64XX series such as the S3C6400 and S3C6410.
+ *
+ * The file does not contain the cpu specific items which are based on
+ * whichever architecture is selected, it only contains the core of the
+ * register set. See <mach/regs-fb.h> to get the specifics.
+ *
+ * Note, we changed to using regs-fb.h as it avoids any clashes with
+ * the original regs-lcd.h so out of the way of regs-lcd.h as well as
+ * indicating the newer block is much more than just an LCD interface.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* Please do not include this file directly, use <mach/regs-fb.h> to
+ * ensure all the localised SoC support is included as necessary.
+*/
+
+/* VIDCON0 */
+
+#define VIDCON0                                        (0x00)
+#define VIDCON0_INTERLACE                      (1 << 29)
+#define VIDCON0_VIDOUT_MASK                    (0x3 << 26)
+#define VIDCON0_VIDOUT_SHIFT                   (26)
+#define VIDCON0_VIDOUT_RGB                     (0x0 << 26)
+#define VIDCON0_VIDOUT_TV                      (0x1 << 26)
+#define VIDCON0_VIDOUT_I80_LDI0                        (0x2 << 26)
+#define VIDCON0_VIDOUT_I80_LDI1                        (0x3 << 26)
+
+#define VIDCON0_L1_DATA_MASK                   (0x7 << 23)
+#define VIDCON0_L1_DATA_SHIFT                  (23)
+#define VIDCON0_L1_DATA_16BPP                  (0x0 << 23)
+#define VIDCON0_L1_DATA_18BPP16                        (0x1 << 23)
+#define VIDCON0_L1_DATA_18BPP9                 (0x2 << 23)
+#define VIDCON0_L1_DATA_24BPP                  (0x3 << 23)
+#define VIDCON0_L1_DATA_18BPP                  (0x4 << 23)
+#define VIDCON0_L1_DATA_16BPP8                 (0x5 << 23)
+
+#define VIDCON0_L0_DATA_MASK                   (0x7 << 20)
+#define VIDCON0_L0_DATA_SHIFT                  (20)
+#define VIDCON0_L0_DATA_16BPP                  (0x0 << 20)
+#define VIDCON0_L0_DATA_18BPP16                        (0x1 << 20)
+#define VIDCON0_L0_DATA_18BPP9                 (0x2 << 20)
+#define VIDCON0_L0_DATA_24BPP                  (0x3 << 20)
+#define VIDCON0_L0_DATA_18BPP                  (0x4 << 20)
+#define VIDCON0_L0_DATA_16BPP8                 (0x5 << 20)
+
+#define VIDCON0_PNRMODE_MASK                   (0x3 << 17)
+#define VIDCON0_PNRMODE_SHIFT                  (17)
+#define VIDCON0_PNRMODE_RGB                    (0x0 << 17)
+#define VIDCON0_PNRMODE_BGR                    (0x1 << 17)
+#define VIDCON0_PNRMODE_SERIAL_RGB             (0x2 << 17)
+#define VIDCON0_PNRMODE_SERIAL_BGR             (0x3 << 17)
+
+#define VIDCON0_CLKVALUP                       (1 << 16)
+#define VIDCON0_CLKVAL_F_MASK                  (0xff << 6)
+#define VIDCON0_CLKVAL_F_SHIFT                 (6)
+#define VIDCON0_CLKVAL_F_LIMIT                 (0xff)
+#define VIDCON0_CLKVAL_F(_x)                   ((_x) << 6)
+#define VIDCON0_VLCKFREE                       (1 << 5)
+#define VIDCON0_CLKDIR                         (1 << 4)
+
+#define VIDCON0_CLKSEL_MASK                    (0x3 << 2)
+#define VIDCON0_CLKSEL_SHIFT                   (2)
+#define VIDCON0_CLKSEL_HCLK                    (0x0 << 2)
+#define VIDCON0_CLKSEL_LCD                     (0x1 << 2)
+#define VIDCON0_CLKSEL_27M                     (0x3 << 2)
+
+#define VIDCON0_ENVID                          (1 << 1)
+#define VIDCON0_ENVID_F                                (1 << 0)
+
+#define VIDCON1                                        (0x04)
+#define VIDCON1_LINECNT_MASK                   (0x7ff << 16)
+#define VIDCON1_LINECNT_SHIFT                  (16)
+#define VIDCON1_LINECNT_GET(_v)                        (((_v) >> 16) & 0x7ff)
+#define VIDCON1_VSTATUS_MASK                   (0x3 << 13)
+#define VIDCON1_VSTATUS_SHIFT                  (13)
+#define VIDCON1_VSTATUS_VSYNC                  (0x0 << 13)
+#define VIDCON1_VSTATUS_BACKPORCH              (0x1 << 13)
+#define VIDCON1_VSTATUS_ACTIVE                 (0x2 << 13)
+#define VIDCON1_VSTATUS_FRONTPORCH             (0x0 << 13)
+
+#define VIDCON1_INV_VCLK                       (1 << 7)
+#define VIDCON1_INV_HSYNC                      (1 << 6)
+#define VIDCON1_INV_VSYNC                      (1 << 5)
+#define VIDCON1_INV_VDEN                       (1 << 4)
+
+/* VIDCON2 */
+
+#define VIDCON2                                        (0x08)
+#define VIDCON2_EN601                          (1 << 23)
+#define VIDCON2_TVFMTSEL_SW                    (1 << 14)
+
+#define VIDCON2_TVFMTSEL1_MASK                 (0x3 << 12)
+#define VIDCON2_TVFMTSEL1_SHIFT                        (12)
+#define VIDCON2_TVFMTSEL1_RGB                  (0x0 << 12)
+#define VIDCON2_TVFMTSEL1_YUV422               (0x1 << 12)
+#define VIDCON2_TVFMTSEL1_YUV444               (0x2 << 12)
+
+#define VIDCON2_ORGYCbCr                       (1 << 8)
+#define VIDCON2_YUVORDCrCb                     (1 << 7)
+
+/* VIDTCON0 */
+
+#define VIDTCON0_VBPDE_MASK                    (0xff << 24)
+#define VIDTCON0_VBPDE_SHIFT                   (24)
+#define VIDTCON0_VBPDE_LIMIT                   (0xff)
+#define VIDTCON0_VBPDE(_x)                     ((_x) << 24)
+
+#define VIDTCON0_VBPD_MASK                     (0xff << 16)
+#define VIDTCON0_VBPD_SHIFT                    (16)
+#define VIDTCON0_VBPD_LIMIT                    (0xff)
+#define VIDTCON0_VBPD(_x)                      ((_x) << 16)
+
+#define VIDTCON0_VFPD_MASK                     (0xff << 8)
+#define VIDTCON0_VFPD_SHIFT                    (8)
+#define VIDTCON0_VFPD_LIMIT                    (0xff)
+#define VIDTCON0_VFPD(_x)                      ((_x) << 8)
+
+#define VIDTCON0_VSPW_MASK                     (0xff << 0)
+#define VIDTCON0_VSPW_SHIFT                    (0)
+#define VIDTCON0_VSPW_LIMIT                    (0xff)
+#define VIDTCON0_VSPW(_x)                      ((_x) << 0)
+
+/* VIDTCON1 */
+
+#define VIDTCON1_VFPDE_MASK                    (0xff << 24)
+#define VIDTCON1_VFPDE_SHIFT                   (24)
+#define VIDTCON1_VFPDE_LIMIT                   (0xff)
+#define VIDTCON1_VFPDE(_x)                     ((_x) << 24)
+
+#define VIDTCON1_HBPD_MASK                     (0xff << 16)
+#define VIDTCON1_HBPD_SHIFT                    (16)
+#define VIDTCON1_HBPD_LIMIT                    (0xff)
+#define VIDTCON1_HBPD(_x)                      ((_x) << 16)
+
+#define VIDTCON1_HFPD_MASK                     (0xff << 8)
+#define VIDTCON1_HFPD_SHIFT                    (8)
+#define VIDTCON1_HFPD_LIMIT                    (0xff)
+#define VIDTCON1_HFPD(_x)                      ((_x) << 8)
+
+#define VIDTCON1_HSPW_MASK                     (0xff << 0)
+#define VIDTCON1_HSPW_SHIFT                    (0)
+#define VIDTCON1_HSPW_LIMIT                    (0xff)
+#define VIDTCON1_HSPW(_x)                      ((_x) << 0)
+
+#define VIDTCON2                               (0x18)
+#define VIDTCON2_LINEVAL_MASK                  (0x7ff << 11)
+#define VIDTCON2_LINEVAL_SHIFT                 (11)
+#define VIDTCON2_LINEVAL_LIMIT                 (0x7ff)
+#define VIDTCON2_LINEVAL(_x)                   ((_x) << 11)
+
+#define VIDTCON2_HOZVAL_MASK                   (0x7ff << 0)
+#define VIDTCON2_HOZVAL_SHIFT                  (0)
+#define VIDTCON2_HOZVAL_LIMIT                  (0x7ff)
+#define VIDTCON2_HOZVAL(_x)                    ((_x) << 0)
+
+/* WINCONx */
+
+
+#define WINCONx_BITSWP                         (1 << 18)
+#define WINCONx_BYTSWP                         (1 << 17)
+#define WINCONx_HAWSWP                         (1 << 16)
+#define WINCONx_BURSTLEN_MASK                  (0x3 << 9)
+#define WINCONx_BURSTLEN_SHIFT                 (9)
+#define WINCONx_BURSTLEN_16WORD                        (0x0 << 9)
+#define WINCONx_BURSTLEN_8WORD                 (0x1 << 9)
+#define WINCONx_BURSTLEN_4WORD                 (0x2 << 9)
+
+#define WINCONx_ENWIN                          (1 << 0)
+#define WINCON0_BPPMODE_MASK                   (0xf << 2)
+#define WINCON0_BPPMODE_SHIFT                  (2)
+#define WINCON0_BPPMODE_1BPP                   (0x0 << 2)
+#define WINCON0_BPPMODE_2BPP                   (0x1 << 2)
+#define WINCON0_BPPMODE_4BPP                   (0x2 << 2)
+#define WINCON0_BPPMODE_8BPP_PALETTE           (0x3 << 2)
+#define WINCON0_BPPMODE_16BPP_565              (0x5 << 2)
+#define WINCON0_BPPMODE_16BPP_1555             (0x7 << 2)
+#define WINCON0_BPPMODE_18BPP_666              (0x8 << 2)
+#define WINCON0_BPPMODE_24BPP_888              (0xb << 2)
+
+#define WINCON1_BLD_PIX                                (1 << 6)
+
+#define WINCON1_ALPHA_SEL                      (1 << 1)
+#define WINCON1_BPPMODE_MASK                   (0xf << 2)
+#define WINCON1_BPPMODE_SHIFT                  (2)
+#define WINCON1_BPPMODE_1BPP                   (0x0 << 2)
+#define WINCON1_BPPMODE_2BPP                   (0x1 << 2)
+#define WINCON1_BPPMODE_4BPP                   (0x2 << 2)
+#define WINCON1_BPPMODE_8BPP_PALETTE           (0x3 << 2)
+#define WINCON1_BPPMODE_8BPP_1232              (0x4 << 2)
+#define WINCON1_BPPMODE_16BPP_565              (0x5 << 2)
+#define WINCON1_BPPMODE_16BPP_A1555            (0x6 << 2)
+#define WINCON1_BPPMODE_16BPP_I1555            (0x7 << 2)
+#define WINCON1_BPPMODE_18BPP_666              (0x8 << 2)
+#define WINCON1_BPPMODE_18BPP_A1665            (0x9 << 2)
+#define WINCON1_BPPMODE_19BPP_A1666            (0xa << 2)
+#define WINCON1_BPPMODE_24BPP_888              (0xb << 2)
+#define WINCON1_BPPMODE_24BPP_A1887            (0xc << 2)
+#define WINCON1_BPPMODE_25BPP_A1888            (0xd << 2)
+#define WINCON1_BPPMODE_28BPP_A4888            (0xd << 2)
+
+
+#define VIDOSDxA_TOPLEFT_X_MASK                        (0x7ff << 11)
+#define VIDOSDxA_TOPLEFT_X_SHIFT               (11)
+#define VIDOSDxA_TOPLEFT_X_LIMIT               (0x7ff)
+#define VIDOSDxA_TOPLEFT_X(_x)                 ((_x) << 11)
+
+#define VIDOSDxA_TOPLEFT_Y_MASK                        (0x7ff << 0)
+#define VIDOSDxA_TOPLEFT_Y_SHIFT               (0)
+#define VIDOSDxA_TOPLEFT_Y_LIMIT               (0x7ff)
+#define VIDOSDxA_TOPLEFT_Y(_x)                 ((_x) << 0)
+
+#define VIDOSDxB_BOTRIGHT_X_MASK               (0x7ff << 11)
+#define VIDOSDxB_BOTRIGHT_X_SHIFT              (11)
+#define VIDOSDxB_BOTRIGHT_X_LIMIT              (0x7ff)
+#define VIDOSDxB_BOTRIGHT_X(_x)                        ((_x) << 11)
+
+#define VIDOSDxB_BOTRIGHT_Y_MASK               (0x7ff << 0)
+#define VIDOSDxB_BOTRIGHT_Y_SHIFT              (0)
+#define VIDOSDxB_BOTRIGHT_Y_LIMIT              (0x7ff)
+#define VIDOSDxB_BOTRIGHT_Y(_x)                        ((_x) << 0)
+
+/* For VIDOSD[1..4]C */
+#define VIDISD14C_ALPHA0_R(_x)                 ((_x) << 20)
+#define VIDISD14C_ALPHA0_G_MASK                        (0xf << 16)
+#define VIDISD14C_ALPHA0_G_SHIFT               (16)
+#define VIDISD14C_ALPHA0_G_LIMIT               (0xf)
+#define VIDISD14C_ALPHA0_G(_x)                 ((_x) << 16)
+#define VIDISD14C_ALPHA0_B_MASK                        (0xf << 12)
+#define VIDISD14C_ALPHA0_B_SHIFT               (12)
+#define VIDISD14C_ALPHA0_B_LIMIT               (0xf)
+#define VIDISD14C_ALPHA0_B(_x)                 ((_x) << 12)
+#define VIDISD14C_ALPHA1_R_MASK                        (0xf << 8)
+#define VIDISD14C_ALPHA1_R_SHIFT               (8)
+#define VIDISD14C_ALPHA1_R_LIMIT               (0xf)
+#define VIDISD14C_ALPHA1_R(_x)                 ((_x) << 8)
+#define VIDISD14C_ALPHA1_G_MASK                        (0xf << 4)
+#define VIDISD14C_ALPHA1_G_SHIFT               (4)
+#define VIDISD14C_ALPHA1_G_LIMIT               (0xf)
+#define VIDISD14C_ALPHA1_G(_x)                 ((_x) << 4)
+#define VIDISD14C_ALPHA1_B_MASK                        (0xf << 0)
+#define VIDISD14C_ALPHA1_B_SHIFT               (0)
+#define VIDISD14C_ALPHA1_B_LIMIT               (0xf)
+#define VIDISD14C_ALPHA1_B(_x)                 ((_x) << 0)
+
+/* Video buffer addresses */
+#define VIDW_BUF_START(_buff)                  (0xA0 + ((_buff) * 8))
+#define VIDW_BUF_START1(_buff)                 (0xA4 + ((_buff) * 8))
+#define VIDW_BUF_END(_buff)                    (0xD0 + ((_buff) * 8))
+#define VIDW_BUF_END1(_buff)                   (0xD4 + ((_buff) * 8))
+#define VIDW_BUF_SIZE(_buff)                   (0x100 + ((_buff) * 4))
+
+#define VIDW_BUF_SIZE_OFFSET_MASK              (0x1fff << 13)
+#define VIDW_BUF_SIZE_OFFSET_SHIFT             (13)
+#define VIDW_BUF_SIZE_OFFSET_LIMIT             (0x1fff)
+#define VIDW_BUF_SIZE_OFFSET(_x)               ((_x) << 13)
+
+#define VIDW_BUF_SIZE_PAGEWIDTH_MASK           (0x1fff << 0)
+#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT          (0)
+#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT          (0x1fff)
+#define VIDW_BUF_SIZE_PAGEWIDTH(_x)            ((_x) << 0)
+
+/* Interrupt controls and status */
+
+#define VIDINTCON0_FIFOINTERVAL_MASK           (0x3f << 20)
+#define VIDINTCON0_FIFOINTERVAL_SHIFT          (20)
+#define VIDINTCON0_FIFOINTERVAL_LIMIT          (0x3f)
+#define VIDINTCON0_FIFOINTERVAL(_x)            ((_x) << 20)
+
+#define VIDINTCON0_INT_SYSMAINCON              (1 << 19)
+#define VIDINTCON0_INT_SYSSUBCON               (1 << 18)
+#define VIDINTCON0_INT_I80IFDONE               (1 << 17)
+
+#define VIDINTCON0_FRAMESEL0_MASK              (0x3 << 15)
+#define VIDINTCON0_FRAMESEL0_SHIFT             (15)
+#define VIDINTCON0_FRAMESEL0_BACKPORCH         (0x0 << 15)
+#define VIDINTCON0_FRAMESEL0_VSYNC             (0x1 << 15)
+#define VIDINTCON0_FRAMESEL0_ACTIVE            (0x2 << 15)
+#define VIDINTCON0_FRAMESEL0_FRONTPORCH                (0x3 << 15)
+
+#define VIDINTCON0_FRAMESEL1                   (1 << 14)
+#define VIDINTCON0_FRAMESEL1_NONE              (0x0 << 14)
+#define VIDINTCON0_FRAMESEL1_BACKPORCH         (0x1 << 14)
+#define VIDINTCON0_FRAMESEL1_VSYNC             (0x2 << 14)
+#define VIDINTCON0_FRAMESEL1_FRONTPORCH                (0x3 << 14)
+
+#define VIDINTCON0_INT_FRAME                   (1 << 12)
+#define VIDINTCON0_FIFIOSEL_MASK               (0x7f << 5)
+#define VIDINTCON0_FIFIOSEL_SHIFT              (5)
+#define VIDINTCON0_FIFIOSEL_WINDOW0            (0x1 << 5)
+#define VIDINTCON0_FIFIOSEL_WINDOW1            (0x2 << 5)
+
+#define VIDINTCON0_FIFOLEVEL_MASK              (0x7 << 2)
+#define VIDINTCON0_FIFOLEVEL_SHIFT             (2)
+#define VIDINTCON0_FIFOLEVEL_TO25PC            (0x0 << 2)
+#define VIDINTCON0_FIFOLEVEL_TO50PC            (0x1 << 2)
+#define VIDINTCON0_FIFOLEVEL_TO75PC            (0x2 << 2)
+#define VIDINTCON0_FIFOLEVEL_EMPTY             (0x3 << 2)
+#define VIDINTCON0_FIFOLEVEL_FULL              (0x4 << 2)
+
+#define VIDINTCON0_INT_FIFO_MASK               (0x3 << 0)
+#define VIDINTCON0_INT_FIFO_SHIFT              (0)
+#define VIDINTCON0_INT_ENABLE                  (1 << 0)
+
+#define VIDINTCON1                             (0x134)
+#define VIDINTCON1_INT_I180                    (1 << 2)
+#define VIDINTCON1_INT_FRAME                   (1 << 1)
+#define VIDINTCON1_INT_FIFO                    (1 << 0)
+
+/* Window colour-key control registers */
+
+#define WxKEYCON0_KEYBL_EN                     (1 << 26)
+#define WxKEYCON0_KEYEN_F                      (1 << 25)
+#define WxKEYCON0_DIRCON                       (1 << 24)
+#define WxKEYCON0_COMPKEY_MASK                 (0xffffff << 0)
+#define WxKEYCON0_COMPKEY_SHIFT                        (0)
+#define WxKEYCON0_COMPKEY_LIMIT                        (0xffffff)
+#define WxKEYCON0_COMPKEY(_x)                  ((_x) << 0)
+#define WxKEYCON1_COLVAL_MASK                  (0xffffff << 0)
+#define WxKEYCON1_COLVAL_SHIFT                 (0)
+#define WxKEYCON1_COLVAL_LIMIT                 (0xffffff)
+#define WxKEYCON1_COLVAL(_x)                   ((_x) << 0)
+
+
+/* Window blanking (MAP) */
+
+#define WINxMAP_MAP                            (1 << 24)
+#define WINxMAP_MAP_COLOUR_MASK                        (0xffffff << 0)
+#define WINxMAP_MAP_COLOUR_SHIFT               (0)
+#define WINxMAP_MAP_COLOUR_LIMIT               (0xffffff)
+#define WINxMAP_MAP_COLOUR(_x)                 ((_x) << 0)
+
+#define WPALCON_PAL_UPDATE                     (1 << 9)
+#define WPALCON_W1PAL_MASK                     (0x7 << 3)
+#define WPALCON_W1PAL_SHIFT                    (3)
+#define WPALCON_W1PAL_25BPP_A888               (0x0 << 3)
+#define WPALCON_W1PAL_24BPP                    (0x1 << 3)
+#define WPALCON_W1PAL_19BPP_A666               (0x2 << 3)
+#define WPALCON_W1PAL_18BPP_A665               (0x3 << 3)
+#define WPALCON_W1PAL_18BPP                    (0x4 << 3)
+#define WPALCON_W1PAL_16BPP_A555               (0x5 << 3)
+#define WPALCON_W1PAL_16BPP_565                        (0x6 << 3)
+
+#define WPALCON_W0PAL_MASK                     (0x7 << 0)
+#define WPALCON_W0PAL_SHIFT                    (0)
+#define WPALCON_W0PAL_25BPP_A888               (0x0 << 0)
+#define WPALCON_W0PAL_24BPP                    (0x1 << 0)
+#define WPALCON_W0PAL_19BPP_A666               (0x2 << 0)
+#define WPALCON_W0PAL_18BPP_A665               (0x3 << 0)
+#define WPALCON_W0PAL_18BPP                    (0x4 << 0)
+#define WPALCON_W0PAL_16BPP_A555               (0x5 << 0)
+#define WPALCON_W0PAL_16BPP_565                        (0x6 << 0)
+
diff --git a/arch/arm/plat-s3c/include/plat/regs-irqtype.h b/arch/arm/plat-s3c/include/plat/regs-irqtype.h
new file mode 100644 (file)
index 0000000..c63cd3f
--- /dev/null
@@ -0,0 +1,21 @@
+/* arch/arm/plat-s3c/include/plat/regs-irqtype.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C - IRQ detection types.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* values for S3C2410_EXTINT0/1/2 and other cpus in the series, including
+ * the S3C64XX
+*/
+#define S3C2410_EXTINT_LOWLEV   (0x00)
+#define S3C2410_EXTINT_HILEV    (0x01)
+#define S3C2410_EXTINT_FALLEDGE         (0x02)
+#define S3C2410_EXTINT_RISEEDGE         (0x04)
+#define S3C2410_EXTINT_BOTHEDGE         (0x06)
diff --git a/arch/arm/plat-s3c/include/plat/regs-sdhci.h b/arch/arm/plat-s3c/include/plat/regs-sdhci.h
new file mode 100644 (file)
index 0000000..e34049a
--- /dev/null
@@ -0,0 +1,87 @@
+/* linux/arch/arm/plat-s3c/include/plat/regs-sdhci.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C Platform - SDHCI (HSMMC) register definitions
+ *
+ * This program is free software; you can 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 __PLAT_S3C_SDHCI_REGS_H
+#define __PLAT_S3C_SDHCI_REGS_H __FILE__
+
+#define S3C_SDHCI_CONTROL2                     (0x80)
+#define S3C_SDHCI_CONTROL3                     (0x84)
+#define S3C64XX_SDHCI_CONTROL4                 (0x8C)
+
+#define S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR      (1 << 31)
+#define S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK                (1 << 30)
+#define S3C_SDHCI_CTRL2_CDINVRXD3              (1 << 29)
+#define S3C_SDHCI_CTRL2_SLCARDOUT              (1 << 28)
+
+#define S3C_SDHCI_CTRL2_FLTCLKSEL_MASK         (0xf << 24)
+#define S3C_SDHCI_CTRL2_FLTCLKSEL_SHIFT                (24)
+#define S3C_SDHCI_CTRL2_FLTCLKSEL(_x)          ((_x) << 24)
+
+#define S3C_SDHCI_CTRL2_LVLDAT_MASK            (0xff << 16)
+#define S3C_SDHCI_CTRL2_LVLDAT_SHIFT           (16)
+#define S3C_SDHCI_CTRL2_LVLDAT(_x)             ((_x) << 16)
+
+#define S3C_SDHCI_CTRL2_ENFBCLKTX              (1 << 15)
+#define S3C_SDHCI_CTRL2_ENFBCLKRX              (1 << 14)
+#define S3C_SDHCI_CTRL2_SDCDSEL                        (1 << 13)
+#define S3C_SDHCI_CTRL2_SDSIGPC                        (1 << 12)
+#define S3C_SDHCI_CTRL2_ENBUSYCHKTXSTART       (1 << 11)
+
+#define S3C_SDHCI_CTRL2_DFCNT_MASK             (0x3 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_SHIFT            (9)
+#define S3C_SDHCI_CTRL2_DFCNT_NONE             (0x0 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_4SDCLK           (0x1 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_16SDCLK          (0x2 << 9)
+#define S3C_SDHCI_CTRL2_DFCNT_64SDCLK          (0x3 << 9)
+
+#define S3C_SDHCI_CTRL2_ENCLKOUTHOLD           (1 << 8)
+#define S3C_SDHCI_CTRL2_RWAITMODE              (1 << 7)
+#define S3C_SDHCI_CTRL2_DISBUFRD               (1 << 6)
+#define S3C_SDHCI_CTRL2_SELBASECLK_MASK                (0x3 << 4)
+#define S3C_SDHCI_CTRL2_SELBASECLK_SHIFT       (4)
+#define S3C_SDHCI_CTRL2_PWRSYNC                        (1 << 3)
+#define S3C_SDHCI_CTRL2_ENCLKOUTMSKCON         (1 << 1)
+#define S3C_SDHCI_CTRL2_HWINITFIN              (1 << 0)
+
+#define S3C_SDHCI_CTRL3_FCSEL3                 (1 << 31)
+#define S3C_SDHCI_CTRL3_FCSEL2                 (1 << 23)
+#define S3C_SDHCI_CTRL3_FCSEL1                 (1 << 15)
+#define S3C_SDHCI_CTRL3_FCSEL0                 (1 << 7)
+
+#define S3C_SDHCI_CTRL3_FIA3_MASK              (0x7f << 24)
+#define S3C_SDHCI_CTRL3_FIA3_SHIFT             (24)
+#define S3C_SDHCI_CTRL3_FIA3(_x)               ((_x) << 24)
+
+#define S3C_SDHCI_CTRL3_FIA2_MASK              (0x7f << 16)
+#define S3C_SDHCI_CTRL3_FIA2_SHIFT             (16)
+#define S3C_SDHCI_CTRL3_FIA2(_x)               ((_x) << 16)
+
+#define S3C_SDHCI_CTRL3_FIA1_MASK              (0x7f << 8)
+#define S3C_SDHCI_CTRL3_FIA1_SHIFT             (8)
+#define S3C_SDHCI_CTRL3_FIA1(_x)               ((_x) << 8)
+
+#define S3C_SDHCI_CTRL3_FIA0_MASK              (0x7f << 0)
+#define S3C_SDHCI_CTRL3_FIA0_SHIFT             (0)
+#define S3C_SDHCI_CTRL3_FIA0(_x)               ((_x) << 0)
+
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_MASK      (0x3 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_SHIFT     (16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_2mA       (0x0 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_4mA       (0x1 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_7mA       (0x2 << 16)
+#define S3C64XX_SDHCI_CONTROL4_DRIVE_9mA       (0x3 << 16)
+
+#define S3C64XX_SDHCI_CONTROL4_BUSY            (1)
+
+#endif /* __PLAT_S3C_SDHCI_REGS_H */
index a0daa647b92ce4ffc2f327c23045cc69faca118d..487d7d2a7e1d1a315fdd7f3f8f6687882203833a 100644 (file)
 #define S3C2440_UCON_FCLK        (3<<10)
 #define S3C2443_UCON_EPLL        (3<<10)
 
+#define S3C6400_UCON_CLKMASK   (3<<10)
+#define S3C6400_UCON_PCLK      (0<<10)
+#define S3C6400_UCON_PCLK2     (2<<10)
+#define S3C6400_UCON_UCLK0     (1<<10)
+#define S3C6400_UCON_UCLK1     (3<<10)
+
 #define S3C2440_UCON2_FCLK_EN    (1<<15)
 #define S3C2440_UCON0_DIVMASK    (15 << 12)
 #define S3C2440_UCON1_DIVMASK    (15 << 12)
 #define S3C2410_UFSTAT_RXMASK    (15<<0)
 #define S3C2410_UFSTAT_RXSHIFT   (0)
 
+/* UFSTAT S3C24A0 */
+#define S3C24A0_UFSTAT_TXFULL    (1 << 14)
+#define S3C24A0_UFSTAT_RXFULL    (1 << 6)
+#define S3C24A0_UFSTAT_TXMASK    (63 << 8)
+#define S3C24A0_UFSTAT_TXSHIFT   (8)
+#define S3C24A0_UFSTAT_RXMASK    (63)
+#define S3C24A0_UFSTAT_RXSHIFT   (0)
+
 /* UFSTAT S3C2443 same as S3C2440 */
 #define S3C2440_UFSTAT_TXFULL    (1<<14)
 #define S3C2440_UFSTAT_RXFULL    (1<<6)
@@ -224,7 +238,7 @@ struct s3c2410_uartcfg {
  * or platform_add_device() before the console_initcall()
 */
 
-extern struct platform_device *s3c24xx_uart_devs[3];
+extern struct platform_device *s3c24xx_uart_devs[4];
 
 #endif /* __ASSEMBLY__ */
 
index cc0eedd53e38a8a410693c5df3ad20493ab90767..d097d92f8cc7cdd32adb32b5404f41a556127dad 100644 (file)
@@ -10,7 +10,6 @@
  * S3C2410 Timer configuration
 */
 
-
 #ifndef __ASM_ARCH_REGS_TIMER_H
 #define __ASM_ARCH_REGS_TIMER_H
 
@@ -21,6 +20,8 @@
 #define S3C2410_TCFG1        S3C_TIMERREG(0x04)
 #define S3C2410_TCON         S3C_TIMERREG(0x08)
 
+#define S3C64XX_TINT_CSTAT    S3C_TIMERREG(0x44)
+
 #define S3C2410_TCFG_PRESCALER0_MASK (255<<0)
 #define S3C2410_TCFG_PRESCALER1_MASK (255<<8)
 #define S3C2410_TCFG_PRESCALER1_SHIFT (8)
 #define S3C2410_TCFG1_MUX_TCLK    (4<<0)
 #define S3C2410_TCFG1_MUX_MASK   (15<<0)
 
+#define S3C64XX_TCFG1_MUX_DIV1   (0<<0)
+#define S3C64XX_TCFG1_MUX_DIV2   (1<<0)
+#define S3C64XX_TCFG1_MUX_DIV4   (2<<0)
+#define S3C64XX_TCFG1_MUX_DIV8    (3<<0)
+#define S3C64XX_TCFG1_MUX_DIV16   (4<<0)
+#define S3C64XX_TCFG1_MUX_TCLK    (5<<0)  /* 3 sets of TCLK */
+#define S3C64XX_TCFG1_MUX_MASK   (15<<0)
+
 #define S3C2410_TCFG1_SHIFT(x)   ((x) * 4)
 
 /* for each timer, we have an count buffer, an compare buffer and
diff --git a/arch/arm/plat-s3c/include/plat/sdhci.h b/arch/arm/plat-s3c/include/plat/sdhci.h
new file mode 100644 (file)
index 0000000..c4ca392
--- /dev/null
@@ -0,0 +1,108 @@
+/* linux/arch/arm/plat-s3c/include/plat/sdhci.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C Platform - SDHCI (HSMMC) platform data definitions
+ *
+ * This program is free software; you can 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 __PLAT_S3C_SDHCI_H
+#define __PLAT_S3C_SDHCI_H __FILE__
+
+struct platform_device;
+struct mmc_host;
+struct mmc_card;
+struct mmc_ios;
+
+/**
+ * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
+ * @max_width: The maximum number of data bits supported.
+ * @host_caps: Standard MMC host capabilities bit field.
+ * @cfg_gpio: Configure the GPIO for a specific card bit-width
+ * @cfg_card: Configure the interface for a specific card and speed. This
+ *            is necessary the controllers and/or GPIO blocks require the
+ *           changing of driver-strength and other controls dependant on
+ *           the card and speed of operation.
+ *
+ * Initialisation data specific to either the machine or the platform
+ * for the device driver to use or call-back when configuring gpio or
+ * card speed information.
+*/
+struct s3c_sdhci_platdata {
+       unsigned int    max_width;
+       unsigned int    host_caps;
+
+       char            **clocks;       /* set of clock sources */
+
+       void    (*cfg_gpio)(struct platform_device *dev, int width);
+       void    (*cfg_card)(struct platform_device *dev,
+                           void __iomem *regbase,
+                           struct mmc_ios *ios,
+                           struct mmc_card *card);
+};
+
+/**
+ * s3c_sdhci0_set_platdata - Set platform data for S3C SDHCI device.
+ * @pd: Platform data to register to device.
+ *
+ * Register the given platform data for use withe S3C SDHCI device.
+ * The call will copy the platform data, so the board definitions can
+ * make the structure itself __initdata.
+ */
+extern void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd);
+extern void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd);
+
+/* Default platform data, exported so that per-cpu initialisation can
+ * set the correct one when there are more than one cpu type selected.
+*/
+
+extern struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata;
+extern struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata;
+
+/* Helper function availablity */
+
+#ifdef CONFIG_S3C6410_SETUP_SDHCI
+extern char *s3c6410_hsmmc_clksrcs[4];
+
+extern void s3c6410_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void s3c6410_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+
+extern void s3c6410_setup_sdhci0_cfg_card(struct platform_device *dev,
+                                          void __iomem *r,
+                                          struct mmc_ios *ios,
+                                          struct mmc_card *card);
+
+#ifdef CONFIG_S3C_DEV_HSMMC
+static inline void s3c6410_default_sdhci0(void)
+{
+       s3c_hsmmc0_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
+       s3c_hsmmc0_def_platdata.cfg_gpio = s3c6410_setup_sdhci0_cfg_gpio;
+       s3c_hsmmc0_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
+}
+#else
+static inline void s3c6410_default_sdhci0(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC */
+
+#ifdef CONFIG_S3C_DEV_HSMMC1
+static inline void s3c6410_default_sdhci1(void)
+{
+       s3c_hsmmc1_def_platdata.clocks = s3c6410_hsmmc_clksrcs;
+       s3c_hsmmc1_def_platdata.cfg_gpio = s3c6410_setup_sdhci1_cfg_gpio;
+       s3c_hsmmc1_def_platdata.cfg_card = s3c6410_setup_sdhci0_cfg_card;
+}
+#else
+static inline void s3c6410_default_sdhci1(void) { }
+#endif /* CONFIG_S3C_DEV_HSMMC1 */
+
+#else
+static inline void s3c6410_default_sdhci0(void) { }
+static inline void s3c6410_default_sdhci1(void) { }
+#endif /* CONFIG_S3C6410_SETUP_SDHCI */
+
+#endif /* __PLAT_S3C_SDHCI_H */
index 4df006b9cc1053199d59fe348bdbca61fde624f4..6061de87f225d43e5f7bbaea948d71f227fb2a5d 100644 (file)
@@ -28,7 +28,7 @@ static void arch_detect_cpu(void);
 /* defines for UART registers */
 
 #include <plat/regs-serial.h>
-#include <asm/plat-s3c/regs-watchdog.h>
+#include <plat/regs-watchdog.h>
 
 /* working in physical space... */
 #undef S3C2410_WDOGREG
@@ -37,7 +37,7 @@ static void arch_detect_cpu(void);
 /* how many bytes we allow into the FIFO at a time in FIFO mode */
 #define FIFO_MAX        (14)
 
-#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT)
+#define uart_base S3C_PA_UART + (S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT)
 
 static __inline__ void
 uart_wr(unsigned int reg, unsigned int val)
@@ -139,6 +139,28 @@ static void arch_decomp_error(const char *x)
 
 static void error(char *err);
 
+#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
+static inline void arch_enable_uart_fifo(void)
+{
+       u32 fifocon = uart_rd(S3C2410_UFCON);
+
+       if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
+               fifocon |= S3C2410_UFCON_RESETBOTH;
+               uart_wr(S3C2410_UFCON, fifocon);
+
+               /* wait for fifo reset to complete */
+               while (1) {
+                       fifocon = uart_rd(S3C2410_UFCON);
+                       if (!(fifocon & S3C2410_UFCON_RESETBOTH))
+                               break;
+               }
+       }
+}
+#else
+#define arch_enable_uart_fifo() do { } while(0)
+#endif
+
+
 static void
 arch_decomp_setup(void)
 {
@@ -149,6 +171,12 @@ arch_decomp_setup(void)
 
        arch_detect_cpu();
        arch_decomp_wdog_start();
+
+       /* Enable the UART FIFOs if they where not enabled and our
+        * configuration says we should turn them on.
+        */
+
+       arch_enable_uart_fifo();
 }
 
 
diff --git a/arch/arm/plat-s3c/init.c b/arch/arm/plat-s3c/init.c
new file mode 100644 (file)
index 0000000..6790edf
--- /dev/null
@@ -0,0 +1,160 @@
+/* linux/arch/arm/plat-s3c/init.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C series CPU initialisation
+ *
+ * This program is free software; you can 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/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+
+#include <plat/regs-serial.h>
+
+static struct cpu_table *cpu;
+
+static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode,
+                                               struct cpu_table *tab,
+                                               unsigned int count)
+{
+       for (; count != 0; count--, tab++) {
+               if ((idcode & tab->idmask) == tab->idcode)
+                       return tab;
+       }
+
+       return NULL;
+}
+
+void __init s3c_init_cpu(unsigned long idcode,
+                        struct cpu_table *cputab, unsigned int cputab_size)
+{
+       cpu = s3c_lookup_cpu(idcode, cputab, cputab_size);
+
+       if (cpu == NULL) {
+               printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
+               panic("Unknown S3C24XX CPU");
+       }
+
+       printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
+
+       if (cpu->map_io == NULL || cpu->init == NULL) {
+               printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
+               panic("Unsupported Samsung CPU");
+       }
+
+       cpu->map_io();
+}
+
+/* s3c24xx_init_clocks
+ *
+ * Initialise the clock subsystem and associated information from the
+ * given master crystal value.
+ *
+ * xtal  = 0 -> use default PLL crystal value (normally 12MHz)
+ *      != 0 -> PLL crystal value in Hz
+*/
+
+void __init s3c24xx_init_clocks(int xtal)
+{
+       if (xtal == 0)
+               xtal = 12*1000*1000;
+
+       if (cpu == NULL)
+               panic("s3c24xx_init_clocks: no cpu setup?\n");
+
+       if (cpu->init_clocks == NULL)
+               panic("s3c24xx_init_clocks: cpu has no clock init\n");
+       else
+               (cpu->init_clocks)(xtal);
+}
+
+/* uart management */
+
+static int nr_uarts __initdata = 0;
+
+static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+/* s3c24xx_init_uartdevs
+ *
+ * copy the specified platform data and configuration into our central
+ * set of devices, before the data is thrown away after the init process.
+ *
+ * This also fills in the array passed to the serial driver for the
+ * early initialisation of the console.
+*/
+
+void __init s3c24xx_init_uartdevs(char *name,
+                                 struct s3c24xx_uart_resources *res,
+                                 struct s3c2410_uartcfg *cfg, int no)
+{
+       struct platform_device *platdev;
+       struct s3c2410_uartcfg *cfgptr = uart_cfgs;
+       struct s3c24xx_uart_resources *resp;
+       int uart;
+
+       memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
+
+       for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
+               platdev = s3c24xx_uart_src[cfgptr->hwport];
+
+               resp = res + cfgptr->hwport;
+
+               s3c24xx_uart_devs[uart] = platdev;
+
+               platdev->name = name;
+               platdev->resource = resp->resources;
+               platdev->num_resources = resp->nr_resources;
+
+               platdev->dev.platform_data = cfgptr;
+       }
+
+       nr_uarts = no;
+}
+
+void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       if (cpu == NULL)
+               return;
+
+       if (cpu->init_uarts == NULL) {
+               printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
+       } else
+               (cpu->init_uarts)(cfg, no);
+}
+
+static int __init s3c_arch_init(void)
+{
+       int ret;
+
+       // do the correct init for cpu
+
+       if (cpu == NULL)
+               panic("s3c_arch_init: NULL cpu\n");
+
+       ret = (cpu->init)();
+       if (ret != 0)
+               return ret;
+
+       ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
+       return ret;
+}
+
+arch_initcall(s3c_arch_init);
similarity index 81%
rename from arch/arm/plat-s3c24xx/pwm-clock.c
rename to arch/arm/plat-s3c/pwm-clock.c
index 3fad68a1e6bc2613308e71121a3ca88c48e52562..a318215ab5352e3b137d85e869e01a6dd3d7c8f0 100644 (file)
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/log2.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
+#include <mach/map.h>
 #include <asm/irq.h>
 
-#include <mach/regs-clock.h>
-#include <mach/regs-gpio.h>
-
 #include <plat/clock.h>
 #include <plat/cpu.h>
 
 #include <plat/regs-timer.h>
+#include <mach/pwm-clock.h>
 
 /* Each of the timers 0 through 5 go through the following
  * clock tree, with the inputs depending on the timers.
  * tclk -------------------------/
 */
 
-static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
+static struct clk clk_timer_scaler[];
+
+static unsigned long clk_pwm_scaler_get_rate(struct clk *clk)
 {
        unsigned long tcfg0 = __raw_readl(S3C2410_TCFG0);
 
-       if (clk->id == 1) {
+       if (clk == &clk_timer_scaler[1]) {
                tcfg0 &= S3C2410_TCFG_PRESCALER1_MASK;
                tcfg0 >>= S3C2410_TCFG_PRESCALER1_SHIFT;
        } else {
@@ -87,18 +89,61 @@ static unsigned long clk_pwm_scaler_getrate(struct clk *clk)
        return clk_get_rate(clk->parent) / (tcfg0 + 1);
 }
 
-/* TODO - add set rate calls. */
+static unsigned long clk_pwm_scaler_round_rate(struct clk *clk,
+                                              unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       unsigned long divisor = parent_rate / rate;
+
+       if (divisor > 256)
+               divisor = 256;
+       else if (divisor < 2)
+               divisor = 2;
+
+       return parent_rate / divisor;
+}
+
+static int clk_pwm_scaler_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long round = clk_pwm_scaler_round_rate(clk, rate);
+       unsigned long tcfg0;
+       unsigned long divisor;
+       unsigned long flags;
+
+       divisor = clk_get_rate(clk->parent) / round;
+       divisor--;
+
+       local_irq_save(flags);
+       tcfg0 = __raw_readl(S3C2410_TCFG0);
+
+       if (clk == &clk_timer_scaler[1]) {
+               tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
+               tcfg0 |= divisor << S3C2410_TCFG_PRESCALER1_SHIFT;
+       } else {
+               tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
+               tcfg0 |= divisor;
+       }
+
+       __raw_writel(tcfg0, S3C2410_TCFG0);
+       local_irq_restore(flags);
+
+       return 0;
+}
 
 static struct clk clk_timer_scaler[] = {
        [0]     = {
                .name           = "pwm-scaler0",
                .id             = -1,
-               .get_rate       = clk_pwm_scaler_getrate,
+               .get_rate       = clk_pwm_scaler_get_rate,
+               .set_rate       = clk_pwm_scaler_set_rate,
+               .round_rate     = clk_pwm_scaler_round_rate,
        },
        [1]     = {
                .name           = "pwm-scaler1",
                .id             = -1,
-               .get_rate       = clk_pwm_scaler_getrate,
+               .get_rate       = clk_pwm_scaler_get_rate,
+               .set_rate       = clk_pwm_scaler_set_rate,
+               .round_rate     = clk_pwm_scaler_round_rate,
        },
 };
 
@@ -123,11 +168,6 @@ static inline struct pwm_tdiv_clk *to_tdiv(struct clk *clk)
        return container_of(clk, struct pwm_tdiv_clk, clk);
 }
 
-static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
-{
-       return 1 << (1 + tcfg1);
-}
-
 static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
 {
        unsigned long tcfg1 = __raw_readl(S3C2410_TCFG1);
@@ -136,7 +176,7 @@ static unsigned long clk_pwm_tdiv_get_rate(struct clk *clk)
        tcfg1 >>= S3C2410_TCFG1_SHIFT(clk->id);
        tcfg1 &= S3C2410_TCFG1_MUX_MASK;
 
-       if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
+       if (pwm_cfg_src_is_tclk(tcfg1))
                divisor = to_tdiv(clk)->divisor;
        else
                divisor = tcfg_to_divisor(tcfg1);
@@ -153,7 +193,9 @@ static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
        parent_rate = clk_get_rate(clk->parent);
        divisor = parent_rate / rate;
 
-       if (divisor <= 2)
+       if (divisor <= 1 && pwm_tdiv_has_div1())
+               divisor = 1;
+       else if (divisor <= 2)
                divisor = 2;
        else if (divisor <= 4)
                divisor = 4;
@@ -167,25 +209,7 @@ static unsigned long clk_pwm_tdiv_round_rate(struct clk *clk,
 
 static unsigned long clk_pwm_tdiv_bits(struct pwm_tdiv_clk *divclk)
 {
-       unsigned long bits;
-
-       switch (divclk->divisor) {
-       case 2:
-               bits = S3C2410_TCFG1_MUX_DIV2;
-               break;
-       case 4:
-               bits = S3C2410_TCFG1_MUX_DIV4;
-               break;
-       case 8:
-               bits = S3C2410_TCFG1_MUX_DIV8;
-               break;
-       case 16:
-       default:
-               bits = S3C2410_TCFG1_MUX_DIV16;
-               break;
-       }
-
-       return bits;
+       return pwm_tdiv_div_bits(divclk->divisor);
 }
 
 static void clk_pwm_tdiv_update(struct pwm_tdiv_clk *divclk)
@@ -226,7 +250,7 @@ static int clk_pwm_tdiv_set_rate(struct clk *clk, unsigned long rate)
        /* Update the current MUX settings if we are currently
         * selected as the clock source for this clock. */
 
-       if (tcfg1 != S3C2410_TCFG1_MUX_TCLK)
+       if (!pwm_cfg_src_is_tclk(tcfg1))
                clk_pwm_tdiv_update(divclk);
 
        return 0;
@@ -313,7 +337,7 @@ static int clk_pwm_tin_set_parent(struct clk *clk, struct clk *parent)
        unsigned long shift = S3C2410_TCFG1_SHIFT(id);
 
        if (parent == s3c24xx_pwmclk_tclk(id))
-               bits = S3C2410_TCFG1_MUX_TCLK << shift;
+               bits = S3C_TCFG1_MUX_TCLK << shift;
        else if (parent == s3c24xx_pwmclk_tdiv(id))
                bits = clk_pwm_tdiv_bits(to_tdiv(parent)) << shift;
        else
@@ -375,7 +399,7 @@ static __init int clk_pwm_tin_register(struct clk *pwm)
        tcfg1 >>= S3C2410_TCFG1_SHIFT(id);
        tcfg1 &= S3C2410_TCFG1_MUX_MASK;
 
-       if (tcfg1 == S3C2410_TCFG1_MUX_TCLK)
+       if (pwm_cfg_src_is_tclk(tcfg1))
                parent = s3c24xx_pwmclk_tclk(id);
        else
                parent = s3c24xx_pwmclk_tdiv(id);
@@ -383,7 +407,16 @@ static __init int clk_pwm_tin_register(struct clk *pwm)
        return clk_set_parent(pwm, parent);
 }
 
-static __init int s3c24xx_pwmclk_init(void)
+/**
+ * s3c_pwmclk_init() - initialise pwm clocks
+ *
+ * Initialise and register the clocks which provide the inputs for the
+ * pwm timer blocks.
+ *
+ * Note, this call is required by the time core, so must be called after
+ * the base clocks are added and before any of the initcalls are run.
+ */
+__init void s3c_pwmclk_init(void)
 {
        struct clk *clk_timers;
        unsigned int clk;
@@ -392,7 +425,7 @@ static __init int s3c24xx_pwmclk_init(void)
        clk_timers = clk_get(NULL, "timers");
        if (IS_ERR(clk_timers)) {
                printk(KERN_ERR "%s: no parent clock\n", __func__);
-               return -EINVAL;
+               return;
        }
 
        for (clk = 0; clk < ARRAY_SIZE(clk_timer_scaler); clk++) {
@@ -400,7 +433,7 @@ static __init int s3c24xx_pwmclk_init(void)
                ret = s3c24xx_register_clock(&clk_timer_scaler[clk]);
                if (ret < 0) {
                        printk(KERN_ERR "error adding pwm scaler%d clock\n", clk);
-                       goto err;
+                       return;
                }
        }
 
@@ -408,7 +441,7 @@ static __init int s3c24xx_pwmclk_init(void)
                ret = s3c24xx_register_clock(&clk_timer_tclk[clk]);
                if (ret < 0) {
                        printk(KERN_ERR "error adding pww tclk%d\n", clk);
-                       goto err;
+                       return;
                }
        }
 
@@ -416,7 +449,7 @@ static __init int s3c24xx_pwmclk_init(void)
                ret = clk_pwm_tdiv_register(clk);
                if (ret < 0) {
                        printk(KERN_ERR "error adding pwm%d tdiv clock\n", clk);
-                       goto err;
+                       return;
                }
        }
 
@@ -424,14 +457,7 @@ static __init int s3c24xx_pwmclk_init(void)
                ret = clk_pwm_tin_register(&clk_tin[clk]);
                if (ret < 0) {
                        printk(KERN_ERR "error adding pwm%d tin clock\n", clk);
-                       goto err;
+                       return;
                }
        }
-
-       return 0;
-
- err:
-       return ret;
 }
-
-arch_initcall(s3c24xx_pwmclk_init);
similarity index 80%
rename from arch/arm/plat-s3c24xx/time.c
rename to arch/arm/plat-s3c/time.c
index c51916236ac082bfad855f9ecc6d93588a9fbdc1..3b27b29da4787e452f76c2c2f5573e3605e06df6 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 
 #include <asm/system.h>
 #include <asm/leds.h>
@@ -36,6 +37,7 @@
 #include <plat/regs-timer.h>
 #include <mach/regs-irq.h>
 #include <asm/mach/time.h>
+#include <mach/tick.h>
 
 #include <plat/clock.h>
 #include <plat/cpu.h>
 static unsigned long timer_startval;
 static unsigned long timer_usec_ticks;
 
+#ifndef TICK_MAX
+#define TICK_MAX (0xffff)
+#endif
+
 #define TIMER_USEC_SHIFT 16
 
 /* we use the shifted arithmetic to work out the ratio of timer ticks
@@ -91,23 +97,19 @@ static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
  * IRQs are disabled before entering here from do_gettimeofday()
  */
 
-#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
-
 static unsigned long s3c2410_gettimeoffset (void)
 {
        unsigned long tdone;
-       unsigned long irqpend;
        unsigned long tval;
 
        /* work out how many ticks have gone since last timer interrupt */
 
-        tval =  __raw_readl(S3C2410_TCNTO(4));
+       tval =  __raw_readl(S3C2410_TCNTO(4));
        tdone = timer_startval - tval;
 
        /* check to see if there is an interrupt pending */
 
-       irqpend = __raw_readl(S3C2410_SRCPND);
-       if (irqpend & SRCPND_TIMER4) {
+       if (s3c24xx_ostimer_pending()) {
                /* re-read the timer, and try and fix up for the missed
                 * interrupt. Note, the interrupt may go off before the
                 * timer has re-loaded from wrapping.
@@ -144,7 +146,11 @@ static struct irqaction s3c2410_timer_irq = {
        machine_is_bast()       || \
        machine_is_vr1000()     || \
        machine_is_anubis()     || \
-       machine_is_osiris() )
+       machine_is_osiris())
+
+static struct clk *tin;
+static struct clk *tdiv;
+static struct clk *timerclk;
 
 /*
  * Set up timer interrupt, and return the current time in seconds.
@@ -159,13 +165,7 @@ static void s3c2410_timer_setup (void)
        unsigned long tcfg1;
        unsigned long tcfg0;
 
-       tcnt = 0xffff;  /* default value for tcnt */
-
-       /* read the current timer configuration bits */
-
-       tcon = __raw_readl(S3C2410_TCON);
-       tcfg1 = __raw_readl(S3C2410_TCFG1);
-       tcfg0 = __raw_readl(S3C2410_TCFG0);
+       tcnt = TICK_MAX;  /* default value for tcnt */
 
        /* configure the system for whichever machine is in use */
 
@@ -174,11 +174,13 @@ static void s3c2410_timer_setup (void)
                timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
                tcnt = 12000000 / HZ;
 
+               tcfg1 = __raw_readl(S3C2410_TCFG1);
                tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
                tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
+               __raw_writel(tcfg1, S3C2410_TCFG1);
        } else {
                unsigned long pclk;
-               struct clk *clk;
+               struct clk *tscaler;
 
                /* for the h1940 (and others), we use the pclk from the core
                 * to generate the timer values. since values around 50 to
@@ -189,38 +191,34 @@ static void s3c2410_timer_setup (void)
                 * (8.45 ticks per usec)
                 */
 
-               /* this is used as default if no other timer can be found */
-
-               clk = clk_get(NULL, "timers");
-               if (IS_ERR(clk))
-                       panic("failed to get clock for system timer");
-
-               clk_enable(clk);
-
-               pclk = clk_get_rate(clk);
+               pclk = clk_get_rate(timerclk);
 
                /* configure clock tick */
 
                timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
 
-               tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
-               tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
+               tscaler = clk_get_parent(tdiv);
 
-               tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
-               tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
+               clk_set_rate(tscaler, pclk / 3);
+               clk_set_rate(tdiv, pclk / 6);
+               clk_set_parent(tin, tdiv);
 
-               tcnt = (pclk / 6) / HZ;
+               tcnt = clk_get_rate(tin) / HZ;
        }
 
+       tcon = __raw_readl(S3C2410_TCON);
+       tcfg0 = __raw_readl(S3C2410_TCFG0);
+       tcfg1 = __raw_readl(S3C2410_TCFG1);
+
        /* timers reload after counting zero, so reduce the count by 1 */
 
        tcnt--;
 
-       printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
+       printk(KERN_DEBUG "timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
               tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
 
        /* check to see if timer is within 16bit range... */
-       if (tcnt > 0xffff) {
+       if (tcnt > TICK_MAX) {
                panic("setup_timer: HZ is too small, cannot configure timer!");
                return;
        }
@@ -247,8 +245,35 @@ static void s3c2410_timer_setup (void)
        __raw_writel(tcon, S3C2410_TCON);
 }
 
-static void __init s3c2410_timer_init (void)
+static void __init s3c2410_timer_resources(void)
+{
+       struct platform_device tmpdev;
+
+       tmpdev.dev.bus = &platform_bus_type;
+       tmpdev.id = 4;
+
+       timerclk = clk_get(NULL, "timers");
+       if (IS_ERR(timerclk))
+               panic("failed to get clock for system timer");
+
+       clk_enable(timerclk);
+
+       if (!use_tclk1_12()) {
+               tin = clk_get(&tmpdev.dev, "pwm-tin");
+               if (IS_ERR(tin))
+                       panic("failed to get pwm-tin clock for system timer");
+
+               tdiv = clk_get(&tmpdev.dev, "pwm-tdiv");
+               if (IS_ERR(tdiv))
+                       panic("failed to get pwm-tdiv clock for system timer");
+       }
+
+       clk_enable(tin);
+}
+
+static void __init s3c2410_timer_init(void)
 {
+       s3c2410_timer_resources();
        s3c2410_timer_setup();
        setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
 }
index 0af3872fb76306fa6b6119dcf12ad124c9463189..2c8a2f5d75ffb5a40553047f30c4ea28d7ccd52b 100644 (file)
@@ -6,8 +6,8 @@
 
 config PLAT_S3C24XX
        bool
-       depends on ARCH_S3C2410
-       default y if ARCH_S3C2410
+       depends on ARCH_S3C2410 || ARCH_S3C24A0
+       default y
        select NO_IOPORT
        select ARCH_REQUIRE_GPIOLIB
        help
@@ -15,6 +15,19 @@ config PLAT_S3C24XX
 
 if PLAT_S3C24XX
 
+# code that is shared between a number of the s3c24xx implementations
+
+config S3C2410_CLOCK
+       bool
+       help
+         Clock code for the S3C2410, and similar processors which
+         is currently includes the S3C2410, S3C2440, S3C2442.
+
+config S3C24XX_DCLK
+       bool
+       help
+         Clock code for supporting DCLK/CLKOUT on S3C24XX architectures
+
 config CPU_S3C244X
        bool
        depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
@@ -28,6 +41,27 @@ config S3C24XX_PWM
          Support for exporting the PWM timer blocks via the pwm device
          system.
 
+
+# gpio configurations
+
+config S3C24XX_GPIO_EXTRA
+       int
+       default 128 if S3C24XX_GPIO_EXTRA128
+       default 64 if S3C24XX_GPIO_EXTRA64
+       default 0
+
+config S3C24XX_GPIO_EXTRA64
+       bool
+       help
+         Add an extra 64 gpio numbers to the available GPIO pool. This is
+         available for boards that need extra gpios for external devices.
+
+config S3C24XX_GPIO_EXTRA128
+       bool
+       help
+         Add an extra 128 gpio numbers to the available GPIO pool. This is
+         available for boards that need extra gpios for external devices.
+
 config PM_SIMTEC
        bool
        help
@@ -49,6 +83,29 @@ config S3C2410_DMA_DEBUG
          Enable debugging output for the DMA code. This option sends info
          to the kernel log, at priority KERN_DEBUG.
 
+config S3C24XX_ADC
+       bool "ADC common driver support"
+       help
+         Core support for the ADC block found in the S3C24XX SoC systems
+         for drivers such as the touchscreen and hwmon to use to share
+         this resource.
+
+# SPI default pin configuration code
+
+config S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13
+       bool
+       help
+         SPI GPIO configuration code for BUS0 when connected to
+         GPE11, GPE12 and GPE13.
+
+config S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7
+       bool
+       help
+         SPI GPIO configuration code for BUS 1 when connected to
+         GPG5, GPG6 and GPG7.
+
+# common code for s3c24xx based machines, such as the SMDKs.
+
 config MACH_SMDK
        bool
        help
index d82767b2b8334995076001eb1b0870867c683efe..1e0767b266b8e9d6963bb390a02b1bf203b9b801 100644 (file)
@@ -17,9 +17,8 @@ obj-y                         += irq.o
 obj-y                          += devs.o
 obj-y                          += gpio.o
 obj-y                          += gpiolib.o
-obj-y                          += time.o
 obj-y                          += clock.o
-obj-y                          += pwm-clock.o
+obj-$(CONFIG_S3C24XX_DCLK)     += clock-dclk.o
 
 # Architecture dependant builds
 
@@ -30,5 +29,18 @@ obj-$(CONFIG_PM_SIMTEC)              += pm-simtec.o
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += sleep.o
 obj-$(CONFIG_HAVE_PWM)         += pwm.o
+obj-$(CONFIG_S3C2410_CLOCK)    += s3c2410-clock.o
 obj-$(CONFIG_S3C2410_DMA)      += dma.o
+obj-$(CONFIG_S3C24XX_ADC)      += adc.o
+
+# device specific setup and/or initialisation
+obj-$(CONFIG_ARCH_S3C2410)     += setup-i2c.o
+
+# SPI gpio central GPIO functions
+
+obj-$(CONFIG_S3C24XX_SPI_BUS0_GPE11_GPE12_GPE13) += spi-bus0-gpe11_12_13.o
+obj-$(CONFIG_S3C24XX_SPI_BUS1_GPG5_GPG6_GPG7)    += spi-bus1-gpg5_6_7.o
+
+# machine common support
+
 obj-$(CONFIG_MACH_SMDK)                += common-smdk.o
diff --git a/arch/arm/plat-s3c24xx/adc.c b/arch/arm/plat-s3c24xx/adc.c
new file mode 100644 (file)
index 0000000..9a5c767
--- /dev/null
@@ -0,0 +1,372 @@
+/* arch/arm/plat-s3c24xx/adc.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org>
+ *
+ * S3C24XX ADC device core
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <plat/regs-adc.h>
+#include <plat/adc.h>
+
+/* This driver is designed to control the usage of the ADC block between
+ * the touchscreen and any other drivers that may need to use it, such as
+ * the hwmon driver.
+ *
+ * Priority will be given to the touchscreen driver, but as this itself is
+ * rate limited it should not starve other requests which are processed in
+ * order that they are received.
+ *
+ * Each user registers to get a client block which uniquely identifies it
+ * and stores information such as the necessary functions to callback when
+ * action is required.
+ */
+
+struct s3c_adc_client {
+       struct platform_device  *pdev;
+       struct list_head         pend;
+
+       unsigned int             nr_samples;
+       unsigned char            is_ts;
+       unsigned char            channel;
+
+       void    (*select_cb)(unsigned selected);
+       void    (*convert_cb)(unsigned val1, unsigned val2);
+};
+
+struct adc_device {
+       struct platform_device  *pdev;
+       struct platform_device  *owner;
+       struct clk              *clk;
+       struct s3c_adc_client   *cur;
+       struct s3c_adc_client   *ts_pend;
+       void __iomem            *regs;
+
+       unsigned int             prescale;
+
+       int                      irq;
+};
+
+static struct adc_device *adc_dev;
+
+static LIST_HEAD(adc_pending);
+
+#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg)
+
+static inline void s3c_adc_convert(struct adc_device *adc)
+{
+       unsigned con = readl(adc->regs + S3C2410_ADCCON);
+
+       con |= S3C2410_ADCCON_ENABLE_START;
+       writel(con, adc->regs + S3C2410_ADCCON);
+}
+
+static inline void s3c_adc_select(struct adc_device *adc,
+                                 struct s3c_adc_client *client)
+{
+       unsigned con = readl(adc->regs + S3C2410_ADCCON);
+
+       client->select_cb(1);
+
+       con &= ~S3C2410_ADCCON_MUXMASK;
+       con &= ~S3C2410_ADCCON_STDBM;
+       con &= ~S3C2410_ADCCON_STARTMASK;
+
+       if (!client->is_ts)
+               con |= S3C2410_ADCCON_SELMUX(client->channel);
+
+       writel(con, adc->regs + S3C2410_ADCCON);
+}
+
+static void s3c_adc_dbgshow(struct adc_device *adc)
+{
+       adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n",
+               readl(adc->regs + S3C2410_ADCCON),
+               readl(adc->regs + S3C2410_ADCTSC),
+               readl(adc->regs + S3C2410_ADCDLY));
+}
+
+void s3c_adc_try(struct adc_device *adc)
+{
+       struct s3c_adc_client *next = adc->ts_pend;
+
+       if (!next && !list_empty(&adc_pending)) {
+               next = list_first_entry(&adc_pending,
+                                       struct s3c_adc_client, pend);
+               list_del(&next->pend);
+       } else
+               adc->ts_pend = NULL;
+
+       if (next) {
+               adc_dbg(adc, "new client is %p\n", next);
+               adc->cur = next;
+               s3c_adc_select(adc, next);
+               s3c_adc_convert(adc);
+               s3c_adc_dbgshow(adc);
+       }
+}
+
+int s3c_adc_start(struct s3c_adc_client *client,
+                 unsigned int channel, unsigned int nr_samples)
+{
+       struct adc_device *adc = adc_dev;
+       unsigned long flags;
+
+       if (!adc) {
+               printk(KERN_ERR "%s: failed to find adc\n", __func__);
+               return -EINVAL;
+       }
+
+       if (client->is_ts && adc->ts_pend)
+               return -EAGAIN;
+
+       local_irq_save(flags);
+
+       client->channel = channel;
+       client->nr_samples = nr_samples;
+
+       if (client->is_ts)
+               adc->ts_pend = client;
+       else
+               list_add_tail(&client->pend, &adc_pending);
+
+       if (!adc->cur)
+               s3c_adc_try(adc);
+       local_irq_restore(flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_adc_start);
+
+static void s3c_adc_default_select(unsigned select)
+{
+}
+
+struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev,
+                                       void (*select)(unsigned int selected),
+                                       void (*conv)(unsigned d0, unsigned d1),
+                                       unsigned int is_ts)
+{
+       struct s3c_adc_client *client;
+
+       WARN_ON(!pdev);
+       WARN_ON(!conv);
+
+       if (!select)
+               select = s3c_adc_default_select;
+
+       if (!conv || !pdev)
+               return ERR_PTR(-EINVAL);
+
+       client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL);
+       if (!client) {
+               dev_err(&pdev->dev, "no memory for adc client\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       client->pdev = pdev;
+       client->is_ts = is_ts;
+       client->select_cb = select;
+       client->convert_cb = conv;
+
+       return client;
+}
+EXPORT_SYMBOL_GPL(s3c_adc_register);
+
+void s3c_adc_release(struct s3c_adc_client *client)
+{
+       /* We should really check that nothing is in progress. */
+       kfree(client);
+}
+EXPORT_SYMBOL_GPL(s3c_adc_release);
+
+static irqreturn_t s3c_adc_irq(int irq, void *pw)
+{
+       struct adc_device *adc = pw;
+       struct s3c_adc_client *client = adc->cur;
+       unsigned long flags;
+       unsigned data0, data1;
+
+       if (!client) {
+               dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__);
+               return IRQ_HANDLED;
+       }
+
+       data0 = readl(adc->regs + S3C2410_ADCDAT0);
+       data1 = readl(adc->regs + S3C2410_ADCDAT1);
+       adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1);
+
+       (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff);
+
+       if (--client->nr_samples > 0) {
+               /* fire another conversion for this */
+
+               client->select_cb(1);
+               s3c_adc_convert(adc);
+       } else {
+               local_irq_save(flags);
+               (client->select_cb)(0);
+               adc->cur = NULL;
+
+               s3c_adc_try(adc);
+               local_irq_restore(flags);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int s3c_adc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct adc_device *adc;
+       struct resource *regs;
+       int ret;
+
+       adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
+       if (adc == NULL) {
+               dev_err(dev, "failed to allocate adc_device\n");
+               return -ENOMEM;
+       }
+
+       adc->pdev = pdev;
+       adc->prescale = S3C2410_ADCCON_PRSCVL(49);
+
+       adc->irq = platform_get_irq(pdev, 1);
+       if (adc->irq <= 0) {
+               dev_err(dev, "failed to get adc irq\n");
+               ret = -ENOENT;
+               goto err_alloc;
+       }
+
+       ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
+       if (ret < 0) {
+               dev_err(dev, "failed to attach adc irq\n");
+               goto err_alloc;
+       }
+
+       adc->clk = clk_get(dev, "adc");
+       if (IS_ERR(adc->clk)) {
+               dev_err(dev, "failed to get adc clock\n");
+               ret = PTR_ERR(adc->clk);
+               goto err_irq;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               dev_err(dev, "failed to find registers\n");
+               ret = -ENXIO;
+               goto err_clk;
+       }
+
+       adc->regs = ioremap(regs->start, resource_size(regs));
+       if (!adc->regs) {
+               dev_err(dev, "failed to map registers\n");
+               ret = -ENXIO;
+               goto err_clk;
+       }
+
+       clk_enable(adc->clk);
+
+       writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
+              adc->regs + S3C2410_ADCCON);
+
+       dev_info(dev, "attached adc driver\n");
+
+       platform_set_drvdata(pdev, adc);
+       adc_dev = adc;
+
+       return 0;
+
+ err_clk:
+       clk_put(adc->clk);
+
+ err_irq:
+       free_irq(adc->irq, adc);
+
+ err_alloc:
+       kfree(adc);
+       return ret;
+}
+
+static int s3c_adc_remove(struct platform_device *pdev)
+{
+       struct adc_device *adc = platform_get_drvdata(pdev);
+
+       iounmap(adc->regs);
+       free_irq(adc->irq, adc);
+       clk_disable(adc->clk);
+       clk_put(adc->clk);
+       kfree(adc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct adc_device *adc = platform_get_drvdata(pdev);
+       u32 con;
+
+       con = readl(adc->regs + S3C2410_ADCCON);
+       con |= S3C2410_ADCCON_STDBM;
+       writel(con, adc->regs + S3C2410_ADCCON);
+
+       clk_disable(adc->clk);
+
+       return 0;
+}
+
+static int s3c_adc_resume(struct platform_device *pdev)
+{
+       struct adc_device *adc = platform_get_drvdata(pdev);
+
+       clk_enable(adc->clk);
+
+       writel(adc->prescale | S3C2410_ADCCON_PRSCEN,
+              adc->regs + S3C2410_ADCCON);
+
+       return 0;
+}
+
+#else
+#define s3c_adc_suspend NULL
+#define s3c_adc_resume NULL
+#endif
+
+static struct platform_driver s3c_adc_driver = {
+       .driver         = {
+               .name   = "s3c24xx-adc",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = s3c_adc_probe,
+       .remove         = __devexit_p(s3c_adc_remove),
+       .suspend        = s3c_adc_suspend,
+       .resume         = s3c_adc_resume,
+};
+
+static int __init adc_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&s3c_adc_driver);
+       if (ret)
+               printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
+
+       return ret;
+}
+
+arch_initcall(adc_init);
diff --git a/arch/arm/plat-s3c24xx/clock-dclk.c b/arch/arm/plat-s3c24xx/clock-dclk.c
new file mode 100644 (file)
index 0000000..5b75a79
--- /dev/null
@@ -0,0 +1,194 @@
+/* linux/arch/arm/plat-s3c24xx/clock-dclk.c
+ *
+ * Copyright (c) 2004,2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C24XX - definitions for DCLK and CLKOUT registers
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/clock.h>
+#include <plat/cpu.h>
+
+/* clocks that could be registered by external code */
+
+static int s3c24xx_dclk_enable(struct clk *clk, int enable)
+{
+       unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
+
+       if (enable)
+               dclkcon |= clk->ctrlbit;
+       else
+               dclkcon &= ~clk->ctrlbit;
+
+       __raw_writel(dclkcon, S3C24XX_DCLKCON);
+
+       return 0;
+}
+
+static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
+{
+       unsigned long dclkcon;
+       unsigned int uclk;
+
+       if (parent == &clk_upll)
+               uclk = 1;
+       else if (parent == &clk_p)
+               uclk = 0;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       dclkcon = __raw_readl(S3C24XX_DCLKCON);
+
+       if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
+               if (uclk)
+                       dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
+               else
+                       dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
+       } else {
+               if (uclk)
+                       dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
+               else
+                       dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
+       }
+
+       __raw_writel(dclkcon, S3C24XX_DCLKCON);
+
+       return 0;
+}
+static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
+{
+       unsigned long div;
+
+       if ((rate == 0) || !clk->parent)
+               return 0;
+
+       div = clk_get_rate(clk->parent) / rate;
+       if (div < 2)
+               div = 2;
+       else if (div > 16)
+               div = 16;
+
+       return div;
+}
+
+static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
+       unsigned long rate)
+{
+       unsigned long div = s3c24xx_calc_div(clk, rate);
+
+       if (div == 0)
+               return 0;
+
+       return clk_get_rate(clk->parent) / div;
+}
+
+static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
+
+       if (div == 0)
+               return -EINVAL;
+
+       if (clk == &s3c24xx_dclk0) {
+               mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
+                       S3C2410_DCLKCON_DCLK0_CMP_MASK;
+               data = S3C2410_DCLKCON_DCLK0_DIV(div) |
+                       S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
+       } else if (clk == &s3c24xx_dclk1) {
+               mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
+                       S3C2410_DCLKCON_DCLK1_CMP_MASK;
+               data = S3C2410_DCLKCON_DCLK1_DIV(div) |
+                       S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
+       } else
+               return -EINVAL;
+
+       clk->rate = clk_get_rate(clk->parent) / div;
+       __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
+               S3C24XX_DCLKCON);
+       return clk->rate;
+}
+static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
+{
+       unsigned long mask;
+       unsigned long source;
+
+       /* calculate the MISCCR setting for the clock */
+
+       if (parent == &clk_xtal)
+               source = S3C2410_MISCCR_CLK0_MPLL;
+       else if (parent == &clk_upll)
+               source = S3C2410_MISCCR_CLK0_UPLL;
+       else if (parent == &clk_f)
+               source = S3C2410_MISCCR_CLK0_FCLK;
+       else if (parent == &clk_h)
+               source = S3C2410_MISCCR_CLK0_HCLK;
+       else if (parent == &clk_p)
+               source = S3C2410_MISCCR_CLK0_PCLK;
+       else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
+               source = S3C2410_MISCCR_CLK0_DCLK0;
+       else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
+               source = S3C2410_MISCCR_CLK0_DCLK0;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       if (clk == &s3c24xx_clkout0)
+               mask = S3C2410_MISCCR_CLK0_MASK;
+       else {
+               source <<= 4;
+               mask = S3C2410_MISCCR_CLK1_MASK;
+       }
+
+       s3c2410_modify_misccr(mask, source);
+       return 0;
+}
+
+/* external clock definitions */
+
+struct clk s3c24xx_dclk0 = {
+       .name           = "dclk0",
+       .id             = -1,
+       .ctrlbit        = S3C2410_DCLKCON_DCLK0EN,
+       .enable         = s3c24xx_dclk_enable,
+       .set_parent     = s3c24xx_dclk_setparent,
+       .set_rate       = s3c24xx_set_dclk_rate,
+       .round_rate     = s3c24xx_round_dclk_rate,
+};
+
+struct clk s3c24xx_dclk1 = {
+       .name           = "dclk1",
+       .id             = -1,
+       .ctrlbit        = S3C2410_DCLKCON_DCLK1EN,
+       .enable         = s3c24xx_dclk_enable,
+       .set_parent     = s3c24xx_dclk_setparent,
+       .set_rate       = s3c24xx_set_dclk_rate,
+       .round_rate     = s3c24xx_round_dclk_rate,
+};
+
+struct clk s3c24xx_clkout0 = {
+       .name           = "clkout0",
+       .id             = -1,
+       .set_parent     = s3c24xx_clkout_setparent,
+};
+
+struct clk s3c24xx_clkout1 = {
+       .name           = "clkout1",
+       .id             = -1,
+       .set_parent     = s3c24xx_clkout_setparent,
+};
index a005ddbd9ef3b00f16ac1a5668bc19889c4614ea..8474d05274bda707350d9e5240d5411c9d971484 100644 (file)
 */
 
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/sysdev.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
 #include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
 #include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
+#include <plat/cpu-freq.h>
+
 #include <plat/clock.h>
 #include <plat/cpu.h>
-
-/* clock information */
-
-static LIST_HEAD(clocks);
-
-DEFINE_MUTEX(clocks_mutex);
-
-/* enable and disable calls for use with the clk struct */
-
-static int clk_null_enable(struct clk *clk, int enable)
-{
-       return 0;
-}
-
-/* Clock API calls */
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *p;
-       struct clk *clk = ERR_PTR(-ENOENT);
-       int idno;
-
-       if (dev == NULL || dev->bus != &platform_bus_type)
-               idno = -1;
-       else
-               idno = to_platform_device(dev)->id;
-
-       mutex_lock(&clocks_mutex);
-
-       list_for_each_entry(p, &clocks, list) {
-               if (p->id == idno &&
-                   strcmp(id, p->name) == 0 &&
-                   try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-
-       /* check for the case where a device was supplied, but the
-        * clock that was being searched for is not device specific */
-
-       if (IS_ERR(clk)) {
-               list_for_each_entry(p, &clocks, list) {
-                       if (p->id == -1 && strcmp(id, p->name) == 0 &&
-                           try_module_get(p->owner)) {
-                               clk = p;
-                               break;
-                       }
-               }
-       }
-
-       mutex_unlock(&clocks_mutex);
-       return clk;
-}
-
-void clk_put(struct clk *clk)
-{
-       module_put(clk->owner);
-}
-
-int clk_enable(struct clk *clk)
-{
-       if (IS_ERR(clk) || clk == NULL)
-               return -EINVAL;
-
-       clk_enable(clk->parent);
-
-       mutex_lock(&clocks_mutex);
-
-       if ((clk->usage++) == 0)
-               (clk->enable)(clk, 1);
-
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-
-void clk_disable(struct clk *clk)
-{
-       if (IS_ERR(clk) || clk == NULL)
-               return;
-
-       mutex_lock(&clocks_mutex);
-
-       if ((--clk->usage) == 0)
-               (clk->enable)(clk, 0);
-
-       mutex_unlock(&clocks_mutex);
-       clk_disable(clk->parent);
-}
-
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       if (IS_ERR(clk))
-               return 0;
-
-       if (clk->rate != 0)
-               return clk->rate;
-
-       if (clk->get_rate != NULL)
-               return (clk->get_rate)(clk);
-
-       if (clk->parent != NULL)
-               return clk_get_rate(clk->parent);
-
-       return clk->rate;
-}
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       if (!IS_ERR(clk) && clk->round_rate)
-               return (clk->round_rate)(clk, rate);
-
-       return rate;
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       int ret;
-
-       if (IS_ERR(clk))
-               return -EINVAL;
-
-       /* We do not default just do a clk->rate = rate as
-        * the clock may have been made this way by choice.
-        */
-
-       WARN_ON(clk->set_rate == NULL);
-
-       if (clk->set_rate == NULL)
-               return -EINVAL;
-
-       mutex_lock(&clocks_mutex);
-       ret = (clk->set_rate)(clk, rate);
-       mutex_unlock(&clocks_mutex);
-
-       return ret;
-}
-
-struct clk *clk_get_parent(struct clk *clk)
-{
-       return clk->parent;
-}
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       int ret = 0;
-
-       if (IS_ERR(clk))
-               return -EINVAL;
-
-       mutex_lock(&clocks_mutex);
-
-       if (clk->set_parent)
-               ret = (clk->set_parent)(clk, parent);
-
-       mutex_unlock(&clocks_mutex);
-
-       return ret;
-}
-
-EXPORT_SYMBOL(clk_get);
-EXPORT_SYMBOL(clk_put);
-EXPORT_SYMBOL(clk_enable);
-EXPORT_SYMBOL(clk_disable);
-EXPORT_SYMBOL(clk_get_rate);
-EXPORT_SYMBOL(clk_round_rate);
-EXPORT_SYMBOL(clk_set_rate);
-EXPORT_SYMBOL(clk_get_parent);
-EXPORT_SYMBOL(clk_set_parent);
-
-/* base clocks */
-
-static int clk_default_setrate(struct clk *clk, unsigned long rate)
-{
-       clk->rate = rate;
-       return 0;
-}
-
-struct clk clk_xtal = {
-       .name           = "xtal",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-};
-
-struct clk clk_mpll = {
-       .name           = "mpll",
-       .id             = -1,
-       .set_rate       = clk_default_setrate,
-};
-
-struct clk clk_upll = {
-       .name           = "upll",
-       .id             = -1,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-};
-
-struct clk clk_f = {
-       .name           = "fclk",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = &clk_mpll,
-       .ctrlbit        = 0,
-       .set_rate       = clk_default_setrate,
-};
-
-struct clk clk_h = {
-       .name           = "hclk",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-       .set_rate       = clk_default_setrate,
-};
-
-struct clk clk_p = {
-       .name           = "pclk",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = NULL,
-       .ctrlbit        = 0,
-       .set_rate       = clk_default_setrate,
-};
-
-struct clk clk_usb_bus = {
-       .name           = "usb-bus",
-       .id             = -1,
-       .rate           = 0,
-       .parent         = &clk_upll,
-};
-
-/* clocks that could be registered by external code */
-
-static int s3c24xx_dclk_enable(struct clk *clk, int enable)
-{
-       unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
-
-       if (enable)
-               dclkcon |= clk->ctrlbit;
-       else
-               dclkcon &= ~clk->ctrlbit;
-
-       __raw_writel(dclkcon, S3C24XX_DCLKCON);
-
-       return 0;
-}
-
-static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
-{
-       unsigned long dclkcon;
-       unsigned int uclk;
-
-       if (parent == &clk_upll)
-               uclk = 1;
-       else if (parent == &clk_p)
-               uclk = 0;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       dclkcon = __raw_readl(S3C24XX_DCLKCON);
-
-       if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
-               if (uclk)
-                       dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
-               else
-                       dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
-       } else {
-               if (uclk)
-                       dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
-               else
-                       dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
-       }
-
-       __raw_writel(dclkcon, S3C24XX_DCLKCON);
-
-       return 0;
-}
-
-static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate)
-{
-       unsigned long div;
-
-       if ((rate == 0) || !clk->parent)
-               return 0;
-
-       div = clk_get_rate(clk->parent) / rate;
-       if (div < 2)
-               div = 2;
-       else if (div > 16)
-               div = 16;
-
-       return div;
-}
-
-static unsigned long s3c24xx_round_dclk_rate(struct clk *clk,
-       unsigned long rate)
-{
-       unsigned long div = s3c24xx_calc_div(clk, rate);
-
-       if (div == 0)
-               return 0;
-
-       return clk_get_rate(clk->parent) / div;
-}
-
-static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned long mask, data, div = s3c24xx_calc_div(clk, rate);
-
-       if (div == 0)
-               return -EINVAL;
-
-       if (clk == &s3c24xx_dclk0) {
-               mask = S3C2410_DCLKCON_DCLK0_DIV_MASK |
-                       S3C2410_DCLKCON_DCLK0_CMP_MASK;
-               data = S3C2410_DCLKCON_DCLK0_DIV(div) |
-                       S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2);
-       } else if (clk == &s3c24xx_dclk1) {
-               mask = S3C2410_DCLKCON_DCLK1_DIV_MASK |
-                       S3C2410_DCLKCON_DCLK1_CMP_MASK;
-               data = S3C2410_DCLKCON_DCLK1_DIV(div) |
-                       S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2);
-       } else
-               return -EINVAL;
-
-       clk->rate = clk_get_rate(clk->parent) / div;
-       __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data),
-               S3C24XX_DCLKCON);
-       return clk->rate;
-}
-
-static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
-{
-       unsigned long mask;
-       unsigned long source;
-
-       /* calculate the MISCCR setting for the clock */
-
-       if (parent == &clk_xtal)
-               source = S3C2410_MISCCR_CLK0_MPLL;
-       else if (parent == &clk_upll)
-               source = S3C2410_MISCCR_CLK0_UPLL;
-       else if (parent == &clk_f)
-               source = S3C2410_MISCCR_CLK0_FCLK;
-       else if (parent == &clk_h)
-               source = S3C2410_MISCCR_CLK0_HCLK;
-       else if (parent == &clk_p)
-               source = S3C2410_MISCCR_CLK0_PCLK;
-       else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
-               source = S3C2410_MISCCR_CLK0_DCLK0;
-       else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
-               source = S3C2410_MISCCR_CLK0_DCLK0;
-       else
-               return -EINVAL;
-
-       clk->parent = parent;
-
-       if (clk == &s3c24xx_clkout0)
-               mask = S3C2410_MISCCR_CLK0_MASK;
-       else {
-               source <<= 4;
-               mask = S3C2410_MISCCR_CLK1_MASK;
-       }
-
-       s3c2410_modify_misccr(mask, source);
-       return 0;
-}
-
-/* external clock definitions */
-
-struct clk s3c24xx_dclk0 = {
-       .name           = "dclk0",
-       .id             = -1,
-       .ctrlbit        = S3C2410_DCLKCON_DCLK0EN,
-       .enable         = s3c24xx_dclk_enable,
-       .set_parent     = s3c24xx_dclk_setparent,
-       .set_rate       = s3c24xx_set_dclk_rate,
-       .round_rate     = s3c24xx_round_dclk_rate,
-};
-
-struct clk s3c24xx_dclk1 = {
-       .name           = "dclk1",
-       .id             = -1,
-       .ctrlbit        = S3C2410_DCLKCON_DCLK1EN,
-       .enable         = s3c24xx_dclk_enable,
-       .set_parent     = s3c24xx_dclk_setparent,
-       .set_rate       = s3c24xx_set_dclk_rate,
-       .round_rate     = s3c24xx_round_dclk_rate,
-};
-
-struct clk s3c24xx_clkout0 = {
-       .name           = "clkout0",
-       .id             = -1,
-       .set_parent     = s3c24xx_clkout_setparent,
-};
-
-struct clk s3c24xx_clkout1 = {
-       .name           = "clkout1",
-       .id             = -1,
-       .set_parent     = s3c24xx_clkout_setparent,
-};
-
-struct clk s3c24xx_uclk = {
-       .name           = "uclk",
-       .id             = -1,
-};
-
-/* initialise the clock system */
-
-int s3c24xx_register_clock(struct clk *clk)
-{
-       clk->owner = THIS_MODULE;
-
-       if (clk->enable == NULL)
-               clk->enable = clk_null_enable;
-
-       /* add to the list of available clocks */
-
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->list, &clocks);
-       mutex_unlock(&clocks_mutex);
-
-       return 0;
-}
-
-int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
-{
-       int fails = 0;
-
-       for (; nr_clks > 0; nr_clks--, clks++) {
-               if (s3c24xx_register_clock(*clks) < 0)
-                       fails++;
-       }
-
-       return fails;
-}
+#include <plat/pll.h>
 
 /* initalise all the clocks */
 
-int __init s3c24xx_setup_clocks(unsigned long xtal,
-                               unsigned long fclk,
-                               unsigned long hclk,
-                               unsigned long pclk)
+void __init_or_cpufreq s3c24xx_setup_clocks(unsigned long fclk,
+                                          unsigned long hclk,
+                                          unsigned long pclk)
 {
-       printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
-
-       /* initialise the main system clocks */
-
-       clk_xtal.rate = xtal;
-       clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
+       clk_upll.rate = s3c24xx_get_pll(__raw_readl(S3C2410_UPLLCON),
+                                       clk_xtal.rate);
 
        clk_mpll.rate = fclk;
        clk_h.rate = hclk;
        clk_p.rate = pclk;
        clk_f.rate = fclk;
-
-       /* assume uart clocks are correctly setup */
-
-       /* register our clocks */
-
-       if (s3c24xx_register_clock(&clk_xtal) < 0)
-               printk(KERN_ERR "failed to register master xtal\n");
-
-       if (s3c24xx_register_clock(&clk_mpll) < 0)
-               printk(KERN_ERR "failed to register mpll clock\n");
-
-       if (s3c24xx_register_clock(&clk_upll) < 0)
-               printk(KERN_ERR "failed to register upll clock\n");
-
-       if (s3c24xx_register_clock(&clk_f) < 0)
-               printk(KERN_ERR "failed to register cpu fclk\n");
-
-       if (s3c24xx_register_clock(&clk_h) < 0)
-               printk(KERN_ERR "failed to register cpu hclk\n");
-
-       if (s3c24xx_register_clock(&clk_p) < 0)
-               printk(KERN_ERR "failed to register cpu pclk\n");
-
-       return 0;
 }
index 3098736c65d99d3bdc90ec83f1ff0c49cd5afd41..3d4837021ac71ee85046b8dca99f08a3e042be64 100644 (file)
@@ -38,7 +38,7 @@
 #include <mach/regs-gpio.h>
 #include <mach/leds-gpio.h>
 
-#include <asm/plat-s3c/nand.h>
+#include <plat/nand.h>
 
 #include <plat/common-smdk.h>
 #include <plat/devs.h>
index 22a329513c0f3ff0149791066ae4d6a5c64515c1..542062f8cbc1da51ba9a3678cd12d79de65be269 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/delay.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <plat/s3c2442.h>
 #include <plat/s3c2443.h>
 
-struct cpu_table {
-       unsigned long   idcode;
-       unsigned long   idmask;
-       void            (*map_io)(struct map_desc *mach_desc, int size);
-       void            (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
-       void            (*init_clocks)(int xtal);
-       int             (*init)(void);
-       const char      *name;
-};
-
 /* table of supported CPUs */
 
 static const char name_s3c2400[]  = "S3C2400";
@@ -169,23 +158,7 @@ static struct map_desc s3c_iodesc[] __initdata = {
        IODESC_ENT(UART)
 };
 
-static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode)
-{
-       struct cpu_table *tab;
-       int count;
-
-       tab = cpu_ids;
-       for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
-               if ((idcode & tab->idmask) == tab->idcode)
-                       return tab;
-       }
-
-       return NULL;
-}
-
-/* cpu information */
-
-static struct cpu_table *cpu;
+/* read cpu identificaiton code */
 
 static unsigned long s3c24xx_read_idcode_v5(void)
 {
@@ -231,6 +204,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
        unsigned long idcode = 0x0;
 
        /* initialise the io descriptors we need for initialisation */
+       iotable_init(mach_desc, size);
        iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
 
        if (cpu_architecture() >= CPU_ARCH_ARMv5) {
@@ -239,117 +213,7 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
                idcode = s3c24xx_read_idcode_v4();
        }
 
-       cpu = s3c_lookup_cpu(idcode);
-
-       if (cpu == NULL) {
-               printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
-               panic("Unknown S3C24XX CPU");
-       }
-
-       printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
-
-       if (cpu->map_io == NULL || cpu->init == NULL) {
-               printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
-               panic("Unsupported S3C24XX CPU");
-       }
-
        arm_pm_restart = s3c24xx_pm_restart;
 
-       (cpu->map_io)(mach_desc, size);
-}
-
-/* s3c24xx_init_clocks
- *
- * Initialise the clock subsystem and associated information from the
- * given master crystal value.
- *
- * xtal  = 0 -> use default PLL crystal value (normally 12MHz)
- *      != 0 -> PLL crystal value in Hz
-*/
-
-void __init s3c24xx_init_clocks(int xtal)
-{
-       if (xtal == 0)
-               xtal = 12*1000*1000;
-
-       if (cpu == NULL)
-               panic("s3c24xx_init_clocks: no cpu setup?\n");
-
-       if (cpu->init_clocks == NULL)
-               panic("s3c24xx_init_clocks: cpu has no clock init\n");
-       else
-               (cpu->init_clocks)(xtal);
+       s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
 }
-
-/* uart management */
-
-static int nr_uarts __initdata = 0;
-
-static struct s3c2410_uartcfg uart_cfgs[3];
-
-/* s3c24xx_init_uartdevs
- *
- * copy the specified platform data and configuration into our central
- * set of devices, before the data is thrown away after the init process.
- *
- * This also fills in the array passed to the serial driver for the
- * early initialisation of the console.
-*/
-
-void __init s3c24xx_init_uartdevs(char *name,
-                                 struct s3c24xx_uart_resources *res,
-                                 struct s3c2410_uartcfg *cfg, int no)
-{
-       struct platform_device *platdev;
-       struct s3c2410_uartcfg *cfgptr = uart_cfgs;
-       struct s3c24xx_uart_resources *resp;
-       int uart;
-
-       memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
-
-       for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
-               platdev = s3c24xx_uart_src[cfgptr->hwport];
-
-               resp = res + cfgptr->hwport;
-
-               s3c24xx_uart_devs[uart] = platdev;
-
-               platdev->name = name;
-               platdev->resource = resp->resources;
-               platdev->num_resources = resp->nr_resources;
-
-               platdev->dev.platform_data = cfgptr;
-       }
-
-       nr_uarts = no;
-}
-
-void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       if (cpu == NULL)
-               return;
-
-       if (cpu->init_uarts == NULL) {
-               printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
-       } else
-               (cpu->init_uarts)(cfg, no);
-}
-
-static int __init s3c_arch_init(void)
-{
-       int ret;
-
-       // do the correct init for cpu
-
-       if (cpu == NULL)
-               panic("s3c_arch_init: NULL cpu\n");
-
-       ret = (cpu->init)();
-       if (ret != 0)
-               return ret;
-
-       ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
-       return ret;
-}
-
-arch_initcall(s3c_arch_init);
index e93f8bf6d3386659e175e1248adfea8178982bf4..16ac01d9b8ab631c023bc309d30e45f9289e1835 100644 (file)
 #include <asm/irq.h>
 
 #include <plat/regs-serial.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/udc.h>
 
 #include <plat/devs.h>
 #include <plat/cpu.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 
 /* Serial port registrations */
 
@@ -76,6 +76,19 @@ static struct resource s3c2410_uart2_resource[] = {
        }
 };
 
+static struct resource s3c2410_uart3_resource[] = {
+       [0] = {
+               .start = S3C2443_PA_UART3,
+               .end   = S3C2443_PA_UART3 + 0x3fff,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_S3CUART_RX3,
+               .end   = IRQ_S3CUART_ERR3,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
 struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {
        [0] = {
                .resources      = s3c2410_uart0_resource,
@@ -89,6 +102,10 @@ struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {
                .resources      = s3c2410_uart2_resource,
                .nr_resources   = ARRAY_SIZE(s3c2410_uart2_resource),
        },
+       [3] = {
+               .resources      = s3c2410_uart3_resource,
+               .nr_resources   = ARRAY_SIZE(s3c2410_uart3_resource),
+       },
 };
 
 /* yart devices */
@@ -105,13 +122,18 @@ static struct platform_device s3c24xx_uart_device2 = {
        .id             = 2,
 };
 
-struct platform_device *s3c24xx_uart_src[3] = {
+static struct platform_device s3c24xx_uart_device3 = {
+       .id             = 3,
+};
+
+struct platform_device *s3c24xx_uart_src[4] = {
        &s3c24xx_uart_device0,
        &s3c24xx_uart_device1,
        &s3c24xx_uart_device2,
+       &s3c24xx_uart_device3,
 };
 
-struct platform_device *s3c24xx_uart_devs[3] = {
+struct platform_device *s3c24xx_uart_devs[4] = {
 };
 
 /* USB Host Controller */
@@ -192,8 +214,8 @@ void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
 
 static struct resource s3c_nand_resource[] = {
        [0] = {
-               .start = S3C2410_PA_NAND,
-               .end   = S3C2410_PA_NAND + S3C24XX_SZ_NAND - 1,
+               .start = S3C24XX_PA_NAND,
+               .end   = S3C24XX_PA_NAND + S3C24XX_SZ_NAND - 1,
                .flags = IORESOURCE_MEM,
        }
 };
@@ -271,31 +293,6 @@ struct platform_device s3c_device_wdt = {
 
 EXPORT_SYMBOL(s3c_device_wdt);
 
-/* I2C */
-
-static struct resource s3c_i2c_resource[] = {
-       [0] = {
-               .start = S3C24XX_PA_IIC,
-               .end   = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = IRQ_IIC,
-               .end   = IRQ_IIC,
-               .flags = IORESOURCE_IRQ,
-       }
-
-};
-
-struct platform_device s3c_device_i2c = {
-       .name             = "s3c2410-i2c",
-       .id               = -1,
-       .num_resources    = ARRAY_SIZE(s3c_i2c_resource),
-       .resource         = s3c_i2c_resource,
-};
-
-EXPORT_SYMBOL(s3c_device_i2c);
-
 /* IIS */
 
 static struct resource s3c_iis_resource[] = {
@@ -372,18 +369,26 @@ static struct resource s3c_adc_resource[] = {
 };
 
 struct platform_device s3c_device_adc = {
-       .name             = "s3c2410-adc",
+       .name             = "s3c24xx-adc",
        .id               = -1,
        .num_resources    = ARRAY_SIZE(s3c_adc_resource),
        .resource         = s3c_adc_resource,
 };
 
+/* HWMON */
+
+struct platform_device s3c_device_hwmon = {
+       .name           = "s3c24xx-hwmon",
+       .id             = -1,
+       .dev.parent     = &s3c_device_adc.dev,
+};
+
 /* SDI */
 
 static struct resource s3c_sdi_resource[] = {
        [0] = {
-               .start = S3C2410_PA_SDI,
-               .end   = S3C2410_PA_SDI + S3C24XX_SZ_SDI - 1,
+               .start = S3C24XX_PA_SDI,
+               .end   = S3C24XX_PA_SDI + S3C24XX_SZ_SDI - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
@@ -403,36 +408,6 @@ struct platform_device s3c_device_sdi = {
 
 EXPORT_SYMBOL(s3c_device_sdi);
 
-/* High-speed MMC/SD */
-
-static struct resource s3c_hsmmc_resource[] = {
-       [0] = {
-               .start = S3C2443_PA_HSMMC,
-               .end   = S3C2443_PA_HSMMC + S3C2443_SZ_HSMMC - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = IRQ_S3C2443_HSMMC,
-               .end   = IRQ_S3C2443_HSMMC,
-               .flags = IORESOURCE_IRQ,
-       }
-};
-
-static u64 s3c_device_hsmmc_dmamask = 0xffffffffUL;
-
-struct platform_device s3c_device_hsmmc = {
-       .name             = "s3c-sdhci",
-       .id               = -1,
-       .num_resources    = ARRAY_SIZE(s3c_hsmmc_resource),
-       .resource         = s3c_hsmmc_resource,
-       .dev              = {
-               .dma_mask = &s3c_device_hsmmc_dmamask,
-               .coherent_dma_mask = 0xffffffffUL
-       }
-};
-
-
-
 /* SPI (0) */
 
 static struct resource s3c_spi0_resource[] = {
index 1baf941d1930b76e94b58b23464e5d71da00ab8d..aee2aeb46c60bf3968dcd93dfae399cf2d3ea185 100644 (file)
 #include <linux/sysdev.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
-#include <linux/delay.h>
 #include <linux/io.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 
-#include <asm/mach/dma.h>
 #include <mach/map.h>
 
 #include <plat/dma.h>
@@ -804,7 +802,7 @@ EXPORT_SYMBOL(s3c2410_dma_request);
  * allowed to go through.
 */
 
-int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
+int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client)
 {
        struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
        unsigned long flags;
@@ -995,7 +993,7 @@ static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
 }
 
 int
-s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
+s3c2410_dma_ctrl(unsigned int channel, enum s3c2410_chan_op op)
 {
        struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
@@ -1043,7 +1041,7 @@ EXPORT_SYMBOL(s3c2410_dma_ctrl);
  * dcon:         base value of the DCONx register
 */
 
-int s3c2410_dma_config(dmach_t channel,
+int s3c2410_dma_config(unsigned int channel,
                       int xferunit,
                       int dcon)
 {
@@ -1092,7 +1090,7 @@ int s3c2410_dma_config(dmach_t channel,
 
 EXPORT_SYMBOL(s3c2410_dma_config);
 
-int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
+int s3c2410_dma_setflags(unsigned int channel, unsigned int flags)
 {
        struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
@@ -1113,7 +1111,7 @@ EXPORT_SYMBOL(s3c2410_dma_setflags);
  * irq?
 */
 
-int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
+int s3c2410_dma_set_opfn(unsigned int channel, s3c2410_dma_opfn_t rtn)
 {
        struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
@@ -1129,7 +1127,7 @@ int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
 
 EXPORT_SYMBOL(s3c2410_dma_set_opfn);
 
-int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
+int s3c2410_dma_set_buffdone_fn(unsigned int channel, s3c2410_dma_cbfn_t rtn)
 {
        struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
@@ -1219,7 +1217,7 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
  * returns the current transfer points for the dma source and destination
 */
 
-int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
+int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *dst)
 {
        struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
 
index 3caec6bad3eb33cd6ebdbc2bd5506eaa29734edd..f95c6c9d9f1a95ad93d64bc17ca8f7f9b894b59f 100644 (file)
 #include <linux/io.h>
 #include <linux/gpio.h>
 
+#include <plat/gpio-core.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
 #include <mach/regs-gpio.h>
 
-struct s3c24xx_gpio_chip {
-       struct gpio_chip        chip;
-       void __iomem            *base;
-};
-
-static inline struct s3c24xx_gpio_chip *to_s3c_chip(struct gpio_chip *gpc)
-{
-       return container_of(gpc, struct s3c24xx_gpio_chip, chip);
-}
-
-/* these routines are exported for use by other parts of the platform
- * and system support, but are not intended to be used directly by the
- * drivers themsevles.
- */
-
-static int s3c24xx_gpiolib_input(struct gpio_chip *chip, unsigned offset)
-{
-       struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
-       void __iomem *base = ourchip->base;
-       unsigned long flags;
-       unsigned long con;
-
-       local_irq_save(flags);
-
-       con = __raw_readl(base + 0x00);
-       con &= ~(3 << (offset * 2));
-       con |= (S3C2410_GPIO_OUTPUT & 0xf) << (offset * 2);
-
-       __raw_writel(con, base + 0x00);
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-static int s3c24xx_gpiolib_output(struct gpio_chip *chip,
-                                 unsigned offset, int value)
-{
-       struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
-       void __iomem *base = ourchip->base;
-       unsigned long flags;
-       unsigned long dat;
-       unsigned long con;
-
-       local_irq_save(flags);
-
-       dat = __raw_readl(base + 0x04);
-       dat &= ~(1 << offset);
-       if (value)
-               dat |= 1 << offset;
-       __raw_writel(dat, base + 0x04);
-
-       con = __raw_readl(base + 0x00);
-       con &= ~(3 << (offset * 2));
-       con |= (S3C2410_GPIO_OUTPUT & 0xf) << (offset * 2);
-
-       __raw_writel(con, base + 0x00);
-       __raw_writel(dat, base + 0x04);
-
-       local_irq_restore(flags);
-       return 0;
-}
-
-static void s3c24xx_gpiolib_set(struct gpio_chip *chip,
-                               unsigned offset, int value)
-{
-       struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
-       void __iomem *base = ourchip->base;
-       unsigned long flags;
-       unsigned long dat;
-
-       local_irq_save(flags);
-
-       dat = __raw_readl(base + 0x04);
-       dat &= ~(1 << offset);
-       if (value)
-               dat |= 1 << offset;
-       __raw_writel(dat, base + 0x04);
-
-       local_irq_restore(flags);
-}
-
-static int s3c24xx_gpiolib_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
-       unsigned long val;
-
-       val = __raw_readl(ourchip->base + 0x04);
-       val >>= offset;
-       val &= 1;
-
-       return val;
-}
-
 static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset)
 {
        return -EINVAL;
@@ -125,7 +33,7 @@ static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset)
 static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
                                        unsigned offset, int value)
 {
-       struct s3c24xx_gpio_chip *ourchip = to_s3c_chip(chip);
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
        void __iomem *base = ourchip->base;
        unsigned long flags;
        unsigned long dat;
@@ -151,7 +59,7 @@ static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip,
        return 0;
 }
 
-static struct s3c24xx_gpio_chip gpios[] = {
+struct s3c_gpio_chip s3c24xx_gpios[] = {
        [0] = {
                .base   = S3C24XX_GPIO_BASE(S3C2410_GPA0),
                .chip   = {
@@ -161,8 +69,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .ngpio                  = 24,
                        .direction_input        = s3c24xx_gpiolib_banka_input,
                        .direction_output       = s3c24xx_gpiolib_banka_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
        [1] = {
@@ -172,10 +78,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOB",
                        .ngpio                  = 16,
-                       .direction_input        = s3c24xx_gpiolib_input,
-                       .direction_output       = s3c24xx_gpiolib_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
        [2] = {
@@ -185,10 +87,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOC",
                        .ngpio                  = 16,
-                       .direction_input        = s3c24xx_gpiolib_input,
-                       .direction_output       = s3c24xx_gpiolib_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
        [3] = {
@@ -198,10 +96,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOD",
                        .ngpio                  = 16,
-                       .direction_input        = s3c24xx_gpiolib_input,
-                       .direction_output       = s3c24xx_gpiolib_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
        [4] = {
@@ -211,10 +105,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .label                  = "GPIOE",
                        .owner                  = THIS_MODULE,
                        .ngpio                  = 16,
-                       .direction_input        = s3c24xx_gpiolib_input,
-                       .direction_output       = s3c24xx_gpiolib_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
        [5] = {
@@ -224,10 +114,6 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOF",
                        .ngpio                  = 8,
-                       .direction_input        = s3c24xx_gpiolib_input,
-                       .direction_output       = s3c24xx_gpiolib_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
        [6] = {
@@ -237,21 +123,17 @@ static struct s3c24xx_gpio_chip gpios[] = {
                        .owner                  = THIS_MODULE,
                        .label                  = "GPIOG",
                        .ngpio                  = 10,
-                       .direction_input        = s3c24xx_gpiolib_input,
-                       .direction_output       = s3c24xx_gpiolib_output,
-                       .set                    = s3c24xx_gpiolib_set,
-                       .get                    = s3c24xx_gpiolib_get,
                },
        },
 };
 
 static __init int s3c24xx_gpiolib_init(void)
 {
-       struct s3c24xx_gpio_chip *chip = gpios;
+       struct s3c_gpio_chip *chip = s3c24xx_gpios;
        int gpn;
 
-       for (gpn = 0; gpn < ARRAY_SIZE(gpios); gpn++, chip++)
-               gpiochip_add(&chip->chip);
+       for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++)
+               s3c_gpiolib_add(chip);
 
        return 0;
 }
diff --git a/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h b/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h
new file mode 100644 (file)
index 0000000..a087de2
--- /dev/null
@@ -0,0 +1,55 @@
+/* linux/arch/arm/plat-s3c24xx/include/mach/pwm-clock.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C24xx - pwm clock and timer support
+ */
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @cfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+       return tcfg == S3C2410_TCFG1_MUX_TCLK;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+       return 1 << (1 + tcfg1);
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+       return 0;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+       return ilog2(div) - 1;
+}
+
+#define S3C_TCFG1_MUX_TCLK S3C2410_TCFG1_MUX_TCLK
diff --git a/arch/arm/plat-s3c24xx/include/plat/map.h b/arch/arm/plat-s3c24xx/include/plat/map.h
new file mode 100644 (file)
index 0000000..fef8ea8
--- /dev/null
@@ -0,0 +1,99 @@
+/* linux/include/asm-arm/plat-s3c24xx/map.h
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX - Memory map definitions
+ *
+ * This program is free software; you can 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_PLAT_S3C24XX_MAP_H
+#define __ASM_PLAT_S3C24XX_MAP_H
+
+/* interrupt controller is the first thing we put in, to make
+ * the assembly code for the irq detection easier
+ */
+#define S3C24XX_VA_IRQ    S3C_VA_IRQ
+#define S3C2410_PA_IRQ    (0x4A000000)
+#define S3C24XX_SZ_IRQ    SZ_1M
+
+/* memory controller registers */
+#define S3C24XX_VA_MEMCTRL S3C_VA_MEM
+#define S3C2410_PA_MEMCTRL (0x48000000)
+#define S3C24XX_SZ_MEMCTRL SZ_1M
+
+/* UARTs */
+#define S3C24XX_VA_UART           S3C_VA_UART
+#define S3C2410_PA_UART           (0x50000000)
+#define S3C24XX_SZ_UART           SZ_1M
+#define S3C_UART_OFFSET           (0x4000)
+
+/* Timers */
+#define S3C24XX_VA_TIMER   S3C_VA_TIMER
+#define S3C2410_PA_TIMER   (0x51000000)
+#define S3C24XX_SZ_TIMER   SZ_1M
+
+/* Clock and Power management */
+#define S3C24XX_VA_CLKPWR  S3C_VA_SYS
+#define S3C24XX_SZ_CLKPWR  SZ_1M
+
+/* USB Device port */
+#define S3C2410_PA_USBDEV  (0x52000000)
+#define S3C24XX_SZ_USBDEV  SZ_1M
+
+/* Watchdog */
+#define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG
+#define S3C2410_PA_WATCHDOG (0x53000000)
+#define S3C24XX_SZ_WATCHDOG SZ_1M
+
+/* Standard size definitions for peripheral blocks. */
+
+#define S3C24XX_SZ_IIS         SZ_1M
+#define S3C24XX_SZ_ADC         SZ_1M
+#define S3C24XX_SZ_SPI         SZ_1M
+#define S3C24XX_SZ_SDI         SZ_1M
+#define S3C24XX_SZ_NAND                SZ_1M
+#define S3C24XX_SZ_USBHOST     SZ_1M
+
+/* GPIO ports */
+
+/* the calculation for the VA of this must ensure that
+ * it is the same distance apart from the UART in the
+ * phsyical address space, as the initial mapping for the IO
+ * is done as a 1:1 maping. This puts it (currently) at
+ * 0xFA800000, which is not in the way of any current mapping
+ * by the base system.
+*/
+
+#define S3C2410_PA_GPIO           (0x56000000)
+#define S3C24XX_VA_GPIO           ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
+#define S3C24XX_SZ_GPIO           SZ_1M
+
+
+/* ISA style IO, for each machine to sort out mappings for, if it
+ * implements it. We reserve two 16M regions for ISA.
+ */
+
+#define S3C24XX_VA_ISA_WORD  S3C2410_ADDR(0x02000000)
+#define S3C24XX_VA_ISA_BYTE  S3C2410_ADDR(0x03000000)
+
+/* deal with the registers that move under the 2412/2413 */
+
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+#ifndef __ASSEMBLY__
+extern void __iomem *s3c24xx_va_gpio2;
+#endif
+#ifdef CONFIG_CPU_S3C2412_ONLY
+#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10)
+#else
+#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2
+#endif
+#else
+#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO
+#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO
+#endif
+
+#endif /* __ASM_PLAT_S3C24XX_MAP_H */
diff --git a/arch/arm/plat-s3c24xx/include/plat/pll.h b/arch/arm/plat-s3c24xx/include/plat/pll.h
new file mode 100644 (file)
index 0000000..7ea8bff
--- /dev/null
@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c24xx/include/plat/pll.h
+ *
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C24xx - common pll registers and code
+ */
+
+#define S3C24XX_PLLCON_MDIVSHIFT       12
+#define S3C24XX_PLLCON_PDIVSHIFT       4
+#define S3C24XX_PLLCON_SDIVSHIFT       0
+#define S3C24XX_PLLCON_MDIVMASK                ((1<<(1+(19-12)))-1)
+#define S3C24XX_PLLCON_PDIVMASK                ((1<<5)-1)
+#define S3C24XX_PLLCON_SDIVMASK                3
+
+#include <asm/div64.h>
+
+static inline unsigned int
+s3c24xx_get_pll(unsigned int pllval, unsigned int baseclk)
+{
+       unsigned int mdiv, pdiv, sdiv;
+       uint64_t fvco;
+
+       mdiv = pllval >> S3C24XX_PLLCON_MDIVSHIFT;
+       pdiv = pllval >> S3C24XX_PLLCON_PDIVSHIFT;
+       sdiv = pllval >> S3C24XX_PLLCON_SDIVSHIFT;
+
+       mdiv &= S3C24XX_PLLCON_MDIVMASK;
+       pdiv &= S3C24XX_PLLCON_PDIVMASK;
+       sdiv &= S3C24XX_PLLCON_SDIVMASK;
+
+       fvco = (uint64_t)baseclk * (mdiv + 8);
+       do_div(fvco, (pdiv + 2) << sdiv);
+
+       return (unsigned int)fvco;
+}
index 3a5a16821af8e5de6cbdcd3c3719847ff39d072a..b3feaea5c70ba20cc6e85bb89487de10837e6fe8 100644 (file)
@@ -17,7 +17,7 @@
 
 extern  int s3c2400_init(void);
 
-extern void s3c2400_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2400_map_io(void);
 
 extern void s3c2400_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
index 3cd1ec677b3ffe00043ebe434016fbf90b1a9461..a9ac9e29759e0d0900594cf1c06b93ec4ad11d1e 100644 (file)
@@ -15,7 +15,7 @@
 
 extern  int s3c2410_init(void);
 
-extern void s3c2410_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2410_map_io(void);
 
 extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
index 3ec97685e7819029c342b0571a541db22c470cd1..bb15d3b68be5ec7c2beac2bee7272f0f9deb647b 100644 (file)
@@ -14,7 +14,7 @@
 
 extern  int s3c2412_init(void);
 
-extern void s3c2412_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2412_map_io(void);
 
 extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
index 11d83b5c84e60683a8e715e13550fd7206553d1f..815b107ed8904b6606fead4e12758ee715ea2709 100644 (file)
@@ -16,7 +16,7 @@ struct s3c2410_uartcfg;
 
 extern  int s3c2443_init(void);
 
-extern void s3c2443_map_io(struct map_desc *mach_desc, int size);
+extern void s3c2443_map_io(void);
 
 extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
index 963f7a4f26f23042611426f4e9245337764b566a..0192ecdc1442d851fa53ee7c1a216341a2286839 100644 (file)
@@ -62,6 +62,7 @@
 
 #include <asm/mach/irq.h>
 
+#include <plat/regs-irqtype.h>
 #include <mach/regs-irq.h>
 #include <mach/regs-gpio.h>
 
index 8efb57ad501948974b0400c3f5ed75910506575d..34ef18e5b2a1f4378b34974193e29b59d4f0b8b1 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/interrupt.h>
 #include <linux/crc32.h>
 #include <linux/ioport.h>
-#include <linux/delay.h>
 #include <linux/serial_core.h>
 #include <linux/io.h>
 
@@ -76,11 +75,13 @@ static struct sleep_save core_save[] = {
        SAVE_ITEM(S3C2410_BANKCON4),
        SAVE_ITEM(S3C2410_BANKCON5),
 
+#ifndef CONFIG_CPU_FREQ
        SAVE_ITEM(S3C2410_CLKDIVN),
        SAVE_ITEM(S3C2410_MPLLCON),
+       SAVE_ITEM(S3C2410_REFRESH),
+#endif
        SAVE_ITEM(S3C2410_UPLLCON),
        SAVE_ITEM(S3C2410_CLKSLOW),
-       SAVE_ITEM(S3C2410_REFRESH),
 };
 
 static struct gpio_sleep {
similarity index 99%
rename from arch/arm/mach-s3c2410/clock.c
rename to arch/arm/plat-s3c24xx/s3c2410-clock.c
index 4e07943c1e29116603aef7427ec41410084949ed..b61bdb7937341931373036d55bd80e6f1919110a 100644 (file)
@@ -272,5 +272,6 @@ int __init s3c2410_baseclk_add(void)
               (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
               (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
 
+       s3c_pwmclk_init();
        return 0;
 }
index 7c09773ff9fcdfe93b48c64707035206f9b48f2f..dde41f171affbee2504a564179d0e46662be1cf6 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/sysdev.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/mutex.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
@@ -102,13 +101,13 @@ static int s3c244x_clk_add(struct sys_device *sysdev)
        if (clk_get_rate(clock_upll) > (94 * MHZ)) {
                clk_usb_bus.rate = clk_get_rate(clock_upll) / 2;
 
-               mutex_lock(&clocks_mutex);
+               spin_lock(&clocks_lock);
 
                clkdivn = __raw_readl(S3C2410_CLKDIVN);
                clkdivn |= S3C2440_CLKDIVN_UCLK;
                __raw_writel(clkdivn, S3C2410_CLKDIVN);
 
-               mutex_unlock(&clocks_mutex);
+               spin_unlock(&clocks_lock);
        }
 
        return 0;
index c0344fac4a9492706609ed7ef5a2a42a4b27c9b0..c1de6bb0101b2fd815fd4dff198ac3baa87a9024 100644 (file)
@@ -29,6 +29,8 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 
+#include <plat/cpu-freq.h>
+
 #include <mach/regs-clock.h>
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
@@ -42,6 +44,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/pm.h>
+#include <plat/pll.h>
 
 static struct map_desc s3c244x_iodesc[] __initdata = {
        IODESC_ENT(CLKPWR),
@@ -56,32 +59,34 @@ void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no)
        s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
 }
 
-void __init s3c244x_map_io(struct map_desc *mach_desc, int size)
+void __init s3c244x_map_io(void)
 {
        /* register our io-tables */
 
        iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
-       iotable_init(mach_desc, size);
 
        /* rename any peripherals used differing from the s3c2410 */
 
        s3c_device_sdi.name  = "s3c2440-sdi";
-       s3c_device_i2c.name  = "s3c2440-i2c";
+       s3c_device_i2c0.name  = "s3c2440-i2c";
        s3c_device_nand.name = "s3c2440-nand";
        s3c_device_usbgadget.name = "s3c2440-usbgadget";
 }
 
-void __init s3c244x_init_clocks(int xtal)
+void __init_or_cpufreq s3c244x_setup_clocks(void)
 {
+       struct clk *xtal_clk;
        unsigned long clkdiv;
        unsigned long camdiv;
+       unsigned long xtal;
        unsigned long hclk, fclk, pclk;
        int hdiv = 1;
 
-       /* now we've got our machine bits initialised, work out what
-        * clocks we've got */
+       xtal_clk = clk_get(NULL, "xtal");
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
 
-       fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
+       fclk = s3c24xx_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
 
        clkdiv = __raw_readl(S3C2410_CLKDIVN);
        camdiv = __raw_readl(S3C2440_CAMDIVN);
@@ -107,18 +112,24 @@ void __init s3c244x_init_clocks(int xtal)
        }
 
        hclk = fclk / hdiv;
-       pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
+       pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN) ? 2 : 1);
 
        /* print brief summary of clocks, etc */
 
        printk("S3C244X: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
               print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
 
+       s3c24xx_setup_clocks(fclk, hclk, pclk);
+}
+
+void __init s3c244x_init_clocks(int xtal)
+{
        /* initialise the clocks here, to allow other things like the
         * console to use them, and to add new ones after the initialisation
         */
 
-       s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+       s3c24xx_register_baseclocks(xtal);
+       s3c244x_setup_clocks();
        s3c2410_baseclk_add();
 }
 
index f8ed17676a355c49a7f5af03818cdc826a85df10..6aab5eaae2b46cb6a7967d75f9235165bd2ac7ca 100644 (file)
@@ -12,7 +12,7 @@
 
 #if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442)
 
-extern void s3c244x_map_io(struct map_desc *mach_desc, int size);
+extern void s3c244x_map_io(void);
 
 extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
diff --git a/arch/arm/plat-s3c24xx/setup-i2c.c b/arch/arm/plat-s3c24xx/setup-i2c.c
new file mode 100644 (file)
index 0000000..d62b7e7
--- /dev/null
@@ -0,0 +1,25 @@
+/* linux/arch/arm/plat-s3c24xx/setup-i2c.c
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX Base setup for i2c device
+ *
+ * This program is free software; you can 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>
+
+struct platform_device;
+
+#include <plat/iic.h>
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+
+void s3c_i2c0_cfg_gpio(struct platform_device *dev)
+{
+       s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
+       s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);
+}
diff --git a/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c b/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
new file mode 100644 (file)
index 0000000..8b403cb
--- /dev/null
@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - gpio configuration for bus 0 on gpe11,12,13
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/kernel.h>
+
+#include <mach/hardware.h>
+
+#include <mach/spi.h>
+#include <mach/regs-gpio.h>
+
+void s3c24xx_spi_gpiocfg_bus0_gpe11_12_13(struct s3c2410_spi_info *spi,
+                                         int enable)
+{
+       if (enable) {
+               s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
+               s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
+               s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
+               s3c2410_gpio_pullup(S3C2410_GPE11, 0);
+               s3c2410_gpio_pullup(S3C2410_GPE13, 0);
+       } else {
+               s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPIO_INPUT);
+               s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPIO_INPUT);
+               s3c2410_gpio_pullup(S3C2410_GPE11, 1);
+               s3c2410_gpio_pullup(S3C2410_GPE12, 1);
+               s3c2410_gpio_pullup(S3C2410_GPE13, 1);
+       }
+}
diff --git a/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c b/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
new file mode 100644 (file)
index 0000000..8fccd4e
--- /dev/null
@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c24xx/spi-bus0-gpg5_6_7.c
+ *
+ * Copyright (c) 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX SPI - gpio configuration for bus 1 on gpg5,6,7
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+*/
+
+#include <linux/kernel.h>
+
+#include <mach/hardware.h>
+
+#include <mach/spi.h>
+#include <mach/regs-gpio.h>
+
+void s3c24xx_spi_gpiocfg_bus1_gpg5_6_7(struct s3c2410_spi_info *spi,
+                                      int enable)
+{
+       if (enable) {
+               s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
+               s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
+               s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
+               s3c2410_gpio_pullup(S3C2410_GPG5, 0);
+               s3c2410_gpio_pullup(S3C2410_GPG6, 0);
+       } else {
+               s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPIO_INPUT);
+               s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPIO_INPUT);
+               s3c2410_gpio_pullup(S3C2410_GPG5, 1);
+               s3c2410_gpio_pullup(S3C2410_GPG6, 1);
+               s3c2410_gpio_pullup(S3C2410_GPG7, 1);
+       }
+}
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig
new file mode 100644 (file)
index 0000000..54375a0
--- /dev/null
@@ -0,0 +1,62 @@
+# arch/arm/plat-s3c64xx/Kconfig
+#
+# Copyright 2008 Openmoko, Inc.
+# Copyright 2008 Simtec Electronics
+#      Ben Dooks <ben@simtec.co.uk>
+#
+# Licensed under GPLv2
+
+config PLAT_S3C64XX
+       bool
+       depends on ARCH_S3C64XX
+       default y
+       select CPU_V6
+       select PLAT_S3C
+       select ARM_VIC
+       select NO_IOPORT
+       select ARCH_REQUIRE_GPIOLIB
+       select S3C_GPIO_TRACK
+       select S3C_GPIO_PULL_UPDOWN
+       select S3C_GPIO_CFG_S3C24XX
+       select S3C_GPIO_CFG_S3C64XX
+       help
+         Base platform code for any Samsung S3C64XX device
+
+if PLAT_S3C64XX
+
+# Configuration options shared by all S3C64XX implementations
+
+config CPU_S3C6400_INIT
+       bool
+       help
+         Common initialisation code for the S3C6400 that is shared
+         by other CPUs in the series, such as the S3C6410.
+
+config CPU_S3C6400_CLOCK
+       bool
+       help
+         Common clock support code for the S3C6400 that is shared
+         by other CPUs in the series, such as the S3C6410.
+
+# platform specific device setup
+
+config S3C64XX_SETUP_I2C0
+       bool
+       default y
+       help
+         Common setup code for i2c bus 0.
+
+         Note, currently since i2c0 is always compiled, this setup helper
+         is always compiled with it.
+
+config S3C64XX_SETUP_I2C1
+       bool
+       help
+         Common setup code for i2c bus 1.
+
+config S3C64XX_SETUP_FB_24BPP
+       bool
+       help
+         Common setup code for S3C64XX with an 24bpp RGB display helper.
+
+endif
diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile
new file mode 100644 (file)
index 0000000..2e6d79b
--- /dev/null
@@ -0,0 +1,31 @@
+# arch/arm/plat-s3c64xx/Makefile
+#
+# Copyright 2008 Openmoko, Inc.
+# Copyright 2008 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y                          :=
+obj-m                          :=
+obj-n                          := dummy.o
+obj-                           :=
+
+# Core files
+
+obj-y                          += dev-uart.o
+obj-y                          += cpu.o
+obj-y                          += irq.o
+obj-y                          += irq-eint.o
+obj-y                          += clock.o
+obj-y                          += gpiolib.o
+
+# CPU support
+
+obj-$(CONFIG_CPU_S3C6400_INIT) += s3c6400-init.o
+obj-$(CONFIG_CPU_S3C6400_CLOCK)        += s3c6400-clock.o
+
+# Device setup
+
+obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o
+obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o
+obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c
new file mode 100644 (file)
index 0000000..136c982
--- /dev/null
@@ -0,0 +1,281 @@
+/* linux/arch/arm/plat-s3c64xx/clock.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX Base clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/regs-sys.h>
+#include <plat/regs-clock.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+
+struct clk clk_27m = {
+       .name           = "clk_27m",
+       .id             = -1,
+       .rate           = 27000000,
+};
+
+static int clk_48m_ctrl(struct clk *clk, int enable)
+{
+       unsigned long flags;
+       u32 val;
+
+       /* can't rely on clock lock, this register has other usages */
+       local_irq_save(flags);
+
+       val = __raw_readl(S3C64XX_OTHERS);
+       if (enable)
+               val |= S3C64XX_OTHERS_USBMASK;
+       else
+               val &= ~S3C64XX_OTHERS_USBMASK;
+
+       __raw_writel(val, S3C64XX_OTHERS);
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+struct clk clk_48m = {
+       .name           = "clk_48m",
+       .id             = -1,
+       .rate           = 48000000,
+       .enable         = clk_48m_ctrl,
+};
+
+static int inline s3c64xx_gate(void __iomem *reg,
+                               struct clk *clk,
+                               int enable)
+{
+       unsigned int ctrlbit = clk->ctrlbit;
+       u32 con;
+
+       con = __raw_readl(reg);
+
+       if (enable)
+               con |= ctrlbit;
+       else
+               con &= ~ctrlbit;
+
+       __raw_writel(con, reg);
+       return 0;
+}
+
+static int s3c64xx_pclk_ctrl(struct clk *clk, int enable)
+{
+       return s3c64xx_gate(S3C_PCLK_GATE, clk, enable);
+}
+
+static int s3c64xx_hclk_ctrl(struct clk *clk, int enable)
+{
+       return s3c64xx_gate(S3C_HCLK_GATE, clk, enable);
+}
+
+int s3c64xx_sclk_ctrl(struct clk *clk, int enable)
+{
+       return s3c64xx_gate(S3C_SCLK_GATE, clk, enable);
+}
+
+static struct clk init_clocks_disable[] = {
+       {
+               .name           = "nand",
+               .id             = -1,
+               .parent         = &clk_h,
+       }, {
+               .name           = "adc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_TSADC,
+       }, {
+               .name           = "i2c",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_IIC,
+       }, {
+               .name           = "iis",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_IIS0,
+       }, {
+               .name           = "iis",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_IIS1,
+       }, {
+               .name           = "spi",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_SPI0,
+       }, {
+               .name           = "spi",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_SPI1,
+       }, {
+               .name           = "48m",
+               .id             = 0,
+               .parent         = &clk_48m,
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_MMC0_48,
+       }, {
+               .name           = "48m",
+               .id             = 1,
+               .parent         = &clk_48m,
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_MMC1_48,
+       }, {
+               .name           = "48m",
+               .id             = 2,
+               .parent         = &clk_48m,
+               .enable         = s3c64xx_sclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_MMC2_48,
+       },
+};
+
+static struct clk init_clocks[] = {
+       {
+               .name           = "lcd",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_LCD,
+       }, {
+               .name           = "gpio",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_GPIO,
+       }, {
+               .name           = "usb-host",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_SCLK_UHOST,
+       }, {
+               .name           = "hsmmc",
+               .id             = 0,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_HSMMC0,
+       }, {
+               .name           = "hsmmc",
+               .id             = 1,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_HSMMC1,
+       }, {
+               .name           = "hsmmc",
+               .id             = 2,
+               .parent         = &clk_h,
+               .enable         = s3c64xx_hclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_HCLK_HSMMC2,
+       }, {
+               .name           = "timers",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_PWM,
+       }, {
+               .name           = "uart",
+               .id             = 0,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_UART0,
+       }, {
+               .name           = "uart",
+               .id             = 1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_UART1,
+       }, {
+               .name           = "uart",
+               .id             = 2,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_UART2,
+       }, {
+               .name           = "uart",
+               .id             = 3,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_UART3,
+       }, {
+               .name           = "rtc",
+               .id             = -1,
+               .parent         = &clk_p,
+               .enable         = s3c64xx_pclk_ctrl,
+               .ctrlbit        = S3C_CLKCON_PCLK_RTC,
+       }, {
+               .name           = "watchdog",
+               .id             = -1,
+               .parent         = &clk_p,
+               .ctrlbit        = S3C_CLKCON_PCLK_WDT,
+       }, {
+               .name           = "ac97",
+               .id             = -1,
+               .parent         = &clk_p,
+               .ctrlbit        = S3C_CLKCON_PCLK_AC97,
+       }
+};
+
+static struct clk *clks[] __initdata = {
+       &clk_ext,
+       &clk_epll,
+       &clk_27m,
+       &clk_48m,
+};
+
+void s3c64xx_register_clocks(void)
+{
+       struct clk *clkp;
+       int ret;
+       int ptr;
+
+       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+       clkp = init_clocks;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       clkp = init_clocks_disable;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+
+               (clkp->enable)(clkp, 0);
+       }
+
+       s3c_pwmclk_init();
+}
diff --git a/arch/arm/plat-s3c64xx/cpu.c b/arch/arm/plat-s3c64xx/cpu.c
new file mode 100644 (file)
index 0000000..fbde183
--- /dev/null
@@ -0,0 +1,114 @@
+/* linux/arch/arm/plat-s3c64xx/cpu.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX CPU Support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/regs-serial.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+
+#include <plat/s3c6400.h>
+#include <plat/s3c6410.h>
+
+/* table of supported CPUs */
+
+static const char name_s3c6400[] = "S3C6400";
+static const char name_s3c6410[] = "S3C6410";
+
+static struct cpu_table cpu_ids[] __initdata = {
+       {
+               .idcode         = 0x36400000,
+               .idmask         = 0xfffff000,
+               .map_io         = s3c6400_map_io,
+               .init_clocks    = s3c6400_init_clocks,
+               .init_uarts     = s3c6400_init_uarts,
+               .init           = s3c6400_init,
+               .name           = name_s3c6400,
+       }, {
+               .idcode         = 0x36410100,
+               .idmask         = 0xffffff00,
+               .map_io         = s3c6410_map_io,
+               .init_clocks    = s3c6410_init_clocks,
+               .init_uarts     = s3c6410_init_uarts,
+               .init           = s3c6410_init,
+               .name           = name_s3c6410,
+       },
+};
+
+/* minimal IO mapping */
+
+/* see notes on uart map in arch/arm/mach-s3c6400/include/mach/debug-macro.S */
+#define UART_OFFS (S3C_PA_UART & 0xfffff)
+
+static struct map_desc s3c_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)S3C_VA_SYS,
+               .pfn            = __phys_to_pfn(S3C64XX_PA_SYSCON),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)(S3C_VA_UART + UART_OFFS),
+               .pfn            = __phys_to_pfn(S3C_PA_UART),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_VIC0,
+               .pfn            = __phys_to_pfn(S3C64XX_PA_VIC0),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_VIC1,
+               .pfn            = __phys_to_pfn(S3C64XX_PA_VIC1),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_TIMER,
+               .pfn            = __phys_to_pfn(S3C_PA_TIMER),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C64XX_VA_GPIO,
+               .pfn            = __phys_to_pfn(S3C64XX_PA_GPIO),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+};
+
+/* read cpu identification code */
+
+void __init s3c64xx_init_io(struct map_desc *mach_desc, int size)
+{
+       unsigned long idcode;
+
+       /* initialise the io descriptors we need for initialisation */
+       iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
+       iotable_init(mach_desc, size);
+
+       idcode = __raw_readl(S3C_VA_SYS + 0x118);
+       s3c_init_cpu(idcode, cpu_ids, ARRAY_SIZE(cpu_ids));
+}
diff --git a/arch/arm/plat-s3c64xx/dev-uart.c b/arch/arm/plat-s3c64xx/dev-uart.c
new file mode 100644 (file)
index 0000000..62c11a6
--- /dev/null
@@ -0,0 +1,176 @@
+/* linux/arch/arm/plat-s3c64xx/dev-uart.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Base S3C64XX UART resource and device definitions
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+/* Serial port registrations */
+
+/* 64xx uarts are closer together */
+
+static struct resource s3c64xx_uart0_resource[] = {
+       [0] = {
+               .start  = S3C_PA_UART0,
+               .end    = S3C_PA_UART0 + 0x100,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_S3CUART_RX0,
+               .end    = IRQ_S3CUART_RX0,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_S3CUART_TX0,
+               .end    = IRQ_S3CUART_TX0,
+               .flags  = IORESOURCE_IRQ,
+
+       },
+       [3] = {
+               .start  = IRQ_S3CUART_ERR0,
+               .end    = IRQ_S3CUART_ERR0,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource s3c64xx_uart1_resource[] = {
+       [0] = {
+               .start = S3C_PA_UART1,
+               .end   = S3C_PA_UART1 + 0x100,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_S3CUART_RX1,
+               .end    = IRQ_S3CUART_RX1,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_S3CUART_TX1,
+               .end    = IRQ_S3CUART_TX1,
+               .flags  = IORESOURCE_IRQ,
+
+       },
+       [3] = {
+               .start  = IRQ_S3CUART_ERR1,
+               .end    = IRQ_S3CUART_ERR1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource s3c6xx_uart2_resource[] = {
+       [0] = {
+               .start = S3C_PA_UART2,
+               .end   = S3C_PA_UART2 + 0x100,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_S3CUART_RX2,
+               .end    = IRQ_S3CUART_RX2,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_S3CUART_TX2,
+               .end    = IRQ_S3CUART_TX2,
+               .flags  = IORESOURCE_IRQ,
+
+       },
+       [3] = {
+               .start  = IRQ_S3CUART_ERR2,
+               .end    = IRQ_S3CUART_ERR2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource s3c64xx_uart3_resource[] = {
+       [0] = {
+               .start = S3C_PA_UART3,
+               .end   = S3C_PA_UART3 + 0x100,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_S3CUART_RX3,
+               .end    = IRQ_S3CUART_RX3,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_S3CUART_TX3,
+               .end    = IRQ_S3CUART_TX3,
+               .flags  = IORESOURCE_IRQ,
+
+       },
+       [3] = {
+               .start  = IRQ_S3CUART_ERR3,
+               .end    = IRQ_S3CUART_ERR3,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+
+struct s3c24xx_uart_resources s3c64xx_uart_resources[] __initdata = {
+       [0] = {
+               .resources      = s3c64xx_uart0_resource,
+               .nr_resources   = ARRAY_SIZE(s3c64xx_uart0_resource),
+       },
+       [1] = {
+               .resources      = s3c64xx_uart1_resource,
+               .nr_resources   = ARRAY_SIZE(s3c64xx_uart1_resource),
+       },
+       [2] = {
+               .resources      = s3c6xx_uart2_resource,
+               .nr_resources   = ARRAY_SIZE(s3c6xx_uart2_resource),
+       },
+       [3] = {
+               .resources      = s3c64xx_uart3_resource,
+               .nr_resources   = ARRAY_SIZE(s3c64xx_uart3_resource),
+       },
+};
+
+/* uart devices */
+
+static struct platform_device s3c24xx_uart_device0 = {
+       .id             = 0,
+};
+
+static struct platform_device s3c24xx_uart_device1 = {
+       .id             = 1,
+};
+
+static struct platform_device s3c24xx_uart_device2 = {
+       .id             = 2,
+};
+
+static struct platform_device s3c24xx_uart_device3 = {
+       .id             = 3,
+};
+
+struct platform_device *s3c24xx_uart_src[4] = {
+       &s3c24xx_uart_device0,
+       &s3c24xx_uart_device1,
+       &s3c24xx_uart_device2,
+       &s3c24xx_uart_device3,
+};
+
+struct platform_device *s3c24xx_uart_devs[4] = {
+};
+
diff --git a/arch/arm/plat-s3c64xx/gpiolib.c b/arch/arm/plat-s3c64xx/gpiolib.c
new file mode 100644 (file)
index 0000000..cc62941
--- /dev/null
@@ -0,0 +1,420 @@
+/* arch/arm/plat-s3c64xx/gpiolib.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - GPIOlib support 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+#include <mach/gpio.h>
+#include <mach/gpio-core.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+#include <plat/regs-gpio.h>
+
+/* GPIO bank summary:
+ *
+ * Bank        GPIOs   Style   SlpCon  ExtInt Group
+ * A   8       4Bit    Yes     1
+ * B   7       4Bit    Yes     1
+ * C   8       4Bit    Yes     2
+ * D   5       4Bit    Yes     3
+ * E   5       4Bit    Yes     None
+ * F   16      2Bit    Yes     4 [1]
+ * G   7       4Bit    Yes     5
+ * H   10      4Bit[2] Yes     6
+ * I   16      2Bit    Yes     None
+ * J   12      2Bit    Yes     None
+ * K   16      4Bit[2] No      None
+ * L   15      4Bit[2] No      None
+ * M   6       4Bit    No      IRQ_EINT
+ * N   16      2Bit    No      IRQ_EINT
+ * O   16      2Bit    Yes     7
+ * P   15      2Bit    Yes     8
+ * Q   9       2Bit    Yes     9
+ *
+ * [1] BANKF pins 14,15 do not form part of the external interrupt sources
+ * [2] BANK has two control registers, GPxCON0 and GPxCON1
+ */
+
+#define OFF_GPCON      (0x00)
+#define OFF_GPDAT      (0x04)
+
+#define con_4bit_shift(__off) ((__off) * 4)
+
+#if 1
+#define gpio_dbg(x...) do { } while(0)
+#else
+#define gpio_dbg(x...) printk(KERN_DEBUG ## x)
+#endif
+
+/* The s3c64xx_gpiolib_4bit routines are to control the gpio banks where
+ * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
+ * following example:
+ *
+ * base + 0x00: Control register, 4 bits per gpio
+ *             gpio n: 4 bits starting at (4*n)
+ *             0000 = input, 0001 = output, others mean special-function
+ * base + 0x04: Data register, 1 bit per gpio
+ *             bit n: data bit n
+ *
+ * Note, since the data register is one bit per gpio and is at base + 0x4
+ * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
+ * the output.
+*/
+
+static int s3c64xx_gpiolib_4bit_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long con;
+
+       con = __raw_readl(base + OFF_GPCON);
+       con &= ~(0xf << con_4bit_shift(offset));
+       __raw_writel(con, base + OFF_GPCON);
+
+       gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
+
+       return 0;
+}
+
+static int s3c64xx_gpiolib_4bit_output(struct gpio_chip *chip,
+                                      unsigned offset, int value)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       unsigned long con;
+       unsigned long dat;
+
+       con = __raw_readl(base + OFF_GPCON);
+       con &= ~(0xf << con_4bit_shift(offset));
+       con |= 0x1 << con_4bit_shift(offset);
+
+       dat = __raw_readl(base + OFF_GPDAT);
+       if (value)
+               dat |= 1 << offset;
+       else
+               dat &= ~(1 << offset);
+
+       __raw_writel(dat, base + OFF_GPDAT);
+       __raw_writel(con, base + OFF_GPCON);
+       __raw_writel(dat, base + OFF_GPDAT);
+
+       gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+
+       return 0;
+}
+
+/* The next set of routines are for the case where the GPIO configuration
+ * registers are 4 bits per GPIO but there is more than one register (the
+ * bank has more than 8 GPIOs.
+ *
+ * This case is the similar to the 4 bit case, but the registers are as
+ * follows:
+ *
+ * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
+ *             gpio n: 4 bits starting at (4*n)
+ *             0000 = input, 0001 = output, others mean special-function
+ * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
+ *             gpio n: 4 bits starting at (4*n)
+ *             0000 = input, 0001 = output, others mean special-function
+ * base + 0x08: Data register, 1 bit per gpio
+ *             bit n: data bit n
+ *
+ * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
+ * store the 'base + 0x4' address so that these routines see the data
+ * register at ourchip->base + 0x04.
+*/
+
+static int s3c64xx_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       void __iomem *regcon = base;
+       unsigned long con;
+
+       if (offset > 7)
+               offset -= 8;
+       else
+               regcon -= 4;
+
+       con = __raw_readl(regcon);
+       con &= ~(0xf << con_4bit_shift(offset));
+       __raw_writel(con, regcon);
+
+       gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
+
+       return 0;
+
+}
+
+static int s3c64xx_gpiolib_4bit2_output(struct gpio_chip *chip,
+                                      unsigned offset, int value)
+{
+       struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+       void __iomem *base = ourchip->base;
+       void __iomem *regcon = base;
+       unsigned long con;
+       unsigned long dat;
+
+       if (offset > 7)
+               offset -= 8;
+       else
+               regcon -= 4;
+
+       con = __raw_readl(regcon);
+       con &= ~(0xf << con_4bit_shift(offset));
+       con |= 0x1 << con_4bit_shift(offset);
+
+       dat = __raw_readl(base + OFF_GPDAT);
+       if (value)
+               dat |= 1 << offset;
+       else
+               dat &= ~(1 << offset);
+
+       __raw_writel(dat, base + OFF_GPDAT);
+       __raw_writel(con, regcon);
+       __raw_writel(dat, base + OFF_GPDAT);
+
+       gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+
+       return 0;
+}
+
+static struct s3c_gpio_cfg gpio_4bit_cfg_noint = {
+       .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_4bit_cfg_eint0111 = {
+       .cfg_eint       = 7,
+       .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
+       .cfg_eint       = 3,
+       .set_config     = s3c_gpio_setcfg_s3c64xx_4bit,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_chip gpio_4bit[] = {
+       {
+               .base   = S3C64XX_GPA_BASE,
+               .config = &gpio_4bit_cfg_eint0111,
+               .chip   = {
+                       .base   = S3C64XX_GPA(0),
+                       .ngpio  = S3C64XX_GPIO_A_NR,
+                       .label  = "GPA",
+               },
+       }, {
+               .base   = S3C64XX_GPB_BASE,
+               .config = &gpio_4bit_cfg_eint0111,
+               .chip   = {
+                       .base   = S3C64XX_GPB(0),
+                       .ngpio  = S3C64XX_GPIO_B_NR,
+                       .label  = "GPB",
+               },
+       }, {
+               .base   = S3C64XX_GPC_BASE,
+               .config = &gpio_4bit_cfg_eint0111,
+               .chip   = {
+                       .base   = S3C64XX_GPC(0),
+                       .ngpio  = S3C64XX_GPIO_C_NR,
+                       .label  = "GPC",
+               },
+       }, {
+               .base   = S3C64XX_GPD_BASE,
+               .config = &gpio_4bit_cfg_eint0111,
+               .chip   = {
+                       .base   = S3C64XX_GPD(0),
+                       .ngpio  = S3C64XX_GPIO_D_NR,
+                       .label  = "GPD",
+               },
+       }, {
+               .base   = S3C64XX_GPE_BASE,
+               .config = &gpio_4bit_cfg_noint,
+               .chip   = {
+                       .base   = S3C64XX_GPE(0),
+                       .ngpio  = S3C64XX_GPIO_E_NR,
+                       .label  = "GPE",
+               },
+       }, {
+               .base   = S3C64XX_GPG_BASE,
+               .config = &gpio_4bit_cfg_eint0111,
+               .chip   = {
+                       .base   = S3C64XX_GPG(0),
+                       .ngpio  = S3C64XX_GPIO_G_NR,
+                       .label  = "GPG",
+               },
+       }, {
+               .base   = S3C64XX_GPM_BASE,
+               .config = &gpio_4bit_cfg_eint0011,
+               .chip   = {
+                       .base   = S3C64XX_GPM(0),
+                       .ngpio  = S3C64XX_GPIO_M_NR,
+                       .label  = "GPM",
+               },
+       },
+};
+
+static struct s3c_gpio_chip gpio_4bit2[] = {
+       {
+               .base   = S3C64XX_GPH_BASE + 0x4,
+               .config = &gpio_4bit_cfg_eint0111,
+               .chip   = {
+                       .base   = S3C64XX_GPH(0),
+                       .ngpio  = S3C64XX_GPIO_H_NR,
+                       .label  = "GPH",
+               },
+       }, {
+               .base   = S3C64XX_GPK_BASE + 0x4,
+               .config = &gpio_4bit_cfg_noint,
+               .chip   = {
+                       .base   = S3C64XX_GPK(0),
+                       .ngpio  = S3C64XX_GPIO_K_NR,
+                       .label  = "GPK",
+               },
+       }, {
+               .base   = S3C64XX_GPL_BASE + 0x4,
+               .config = &gpio_4bit_cfg_eint0011,
+               .chip   = {
+                       .base   = S3C64XX_GPL(0),
+                       .ngpio  = S3C64XX_GPIO_L_NR,
+                       .label  = "GPL",
+               },
+       },
+};
+
+static struct s3c_gpio_cfg gpio_2bit_cfg_noint = {
+       .set_config     = s3c_gpio_setcfg_s3c24xx,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_2bit_cfg_eint10 = {
+       .cfg_eint       = 2,
+       .set_config     = s3c_gpio_setcfg_s3c24xx,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_2bit_cfg_eint11 = {
+       .cfg_eint       = 3,
+       .set_config     = s3c_gpio_setcfg_s3c24xx,
+       .set_pull       = s3c_gpio_setpull_updown,
+       .get_pull       = s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_chip gpio_2bit[] = {
+       {
+               .base   = S3C64XX_GPF_BASE,
+               .config = &gpio_2bit_cfg_eint11,
+               .chip   = {
+                       .base   = S3C64XX_GPF(0),
+                       .ngpio  = S3C64XX_GPIO_F_NR,
+                       .label  = "GPF",
+               },
+       }, {
+               .base   = S3C64XX_GPI_BASE,
+               .config = &gpio_2bit_cfg_noint,
+               .chip   = {
+                       .base   = S3C64XX_GPI(0),
+                       .ngpio  = S3C64XX_GPIO_I_NR,
+                       .label  = "GPI",
+               },
+       }, {
+               .base   = S3C64XX_GPJ_BASE,
+               .config = &gpio_2bit_cfg_noint,
+               .chip   = {
+                       .base   = S3C64XX_GPJ(0),
+                       .ngpio  = S3C64XX_GPIO_J_NR,
+                       .label  = "GPJ",
+               },
+       }, {
+               .base   = S3C64XX_GPN_BASE,
+               .config = &gpio_2bit_cfg_eint10,
+               .chip   = {
+                       .base   = S3C64XX_GPN(0),
+                       .ngpio  = S3C64XX_GPIO_N_NR,
+                       .label  = "GPN",
+               },
+       }, {
+               .base   = S3C64XX_GPO_BASE,
+               .config = &gpio_2bit_cfg_eint11,
+               .chip   = {
+                       .base   = S3C64XX_GPO(0),
+                       .ngpio  = S3C64XX_GPIO_O_NR,
+                       .label  = "GPO",
+               },
+       }, {
+               .base   = S3C64XX_GPP_BASE,
+               .config = &gpio_2bit_cfg_eint11,
+               .chip   = {
+                       .base   = S3C64XX_GPP(0),
+                       .ngpio  = S3C64XX_GPIO_P_NR,
+                       .label  = "GPP",
+               },
+       }, {
+               .base   = S3C64XX_GPQ_BASE,
+               .config = &gpio_2bit_cfg_eint11,
+               .chip   = {
+                       .base   = S3C64XX_GPQ(0),
+                       .ngpio  = S3C64XX_GPIO_Q_NR,
+                       .label  = "GPQ",
+               },
+       },
+};
+
+static __init void s3c64xx_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
+{
+       chip->chip.direction_input = s3c64xx_gpiolib_4bit_input;
+       chip->chip.direction_output = s3c64xx_gpiolib_4bit_output;
+}
+
+static __init void s3c64xx_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
+{
+       chip->chip.direction_input = s3c64xx_gpiolib_4bit2_input;
+       chip->chip.direction_output = s3c64xx_gpiolib_4bit2_output;
+}
+
+static __init void s3c64xx_gpiolib_add(struct s3c_gpio_chip *chips,
+                                      int nr_chips,
+                                      void (*fn)(struct s3c_gpio_chip *))
+{
+       for (; nr_chips > 0; nr_chips--, chips++) {
+               if (fn)
+                       (fn)(chips);
+               s3c_gpiolib_add(chips);
+       }
+}
+
+static __init int s3c64xx_gpiolib_init(void)
+{
+       s3c64xx_gpiolib_add(gpio_4bit, ARRAY_SIZE(gpio_4bit),
+                           s3c64xx_gpiolib_add_4bit);
+
+       s3c64xx_gpiolib_add(gpio_4bit2, ARRAY_SIZE(gpio_4bit2),
+                           s3c64xx_gpiolib_add_4bit2);
+
+       s3c64xx_gpiolib_add(gpio_2bit, ARRAY_SIZE(gpio_2bit), NULL);
+
+       return 0;
+}
+
+arch_initcall(s3c64xx_gpiolib_init);
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-a.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-a.h
new file mode 100644 (file)
index 0000000..9aa0e42
--- /dev/null
@@ -0,0 +1,48 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-a.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank A register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPACON                 (S3C64XX_GPA_BASE + 0x00)
+#define S3C64XX_GPADAT                 (S3C64XX_GPA_BASE + 0x04)
+#define S3C64XX_GPAPUD                 (S3C64XX_GPA_BASE + 0x08)
+#define S3C64XX_GPACONSLP              (S3C64XX_GPA_BASE + 0x0c)
+#define S3C64XX_GPAPUDSLP              (S3C64XX_GPA_BASE + 0x10)
+
+#define S3C64XX_GPA_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPA_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPA_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPA0_UART_RXD0         (0x02 << 0)
+#define S3C64XX_GPA0_EINT_G1_0         (0x07 << 0)
+
+#define S3C64XX_GPA1_UART_TXD0         (0x02 << 4)
+#define S3C64XX_GPA1_EINT_G1_1         (0x07 << 4)
+
+#define S3C64XX_GPA2_UART_nCTS0                (0x02 << 8)
+#define S3C64XX_GPA2_EINT_G1_2         (0x07 << 8)
+
+#define S3C64XX_GPA3_UART_nRTS0                (0x02 << 12)
+#define S3C64XX_GPA3_EINT_G1_3         (0x07 << 12)
+
+#define S3C64XX_GPA4_UART_RXD1         (0x02 << 16)
+#define S3C64XX_GPA4_EINT_G1_4         (0x07 << 16)
+
+#define S3C64XX_GPA5_UART_TXD1         (0x02 << 20)
+#define S3C64XX_GPA5_EINT_G1_5         (0x07 << 20)
+
+#define S3C64XX_GPA6_UART_nCTS1                (0x02 << 24)
+#define S3C64XX_GPA6_EINT_G1_6         (0x07 << 24)
+
+#define S3C64XX_GPA7_UART_nRTS1                (0x02 << 28)
+#define S3C64XX_GPA7_EINT_G1_7         (0x07 << 28)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-b.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-b.h
new file mode 100644 (file)
index 0000000..3933adb
--- /dev/null
@@ -0,0 +1,60 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-b.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank B register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPBCON                 (S3C64XX_GPB_BASE + 0x00)
+#define S3C64XX_GPBDAT                 (S3C64XX_GPB_BASE + 0x04)
+#define S3C64XX_GPBPUD                 (S3C64XX_GPB_BASE + 0x08)
+#define S3C64XX_GPBCONSLP              (S3C64XX_GPB_BASE + 0x0c)
+#define S3C64XX_GPBPUDSLP              (S3C64XX_GPB_BASE + 0x10)
+
+#define S3C64XX_GPB_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPB_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPB_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPB0_UART_RXD2         (0x02 << 0)
+#define S3C64XX_GPB0_EXTDMA_REQ                (0x03 << 0)
+#define S3C64XX_GPB0_IrDA_RXD          (0x04 << 0)
+#define S3C64XX_GPB0_ADDR_CF0          (0x05 << 0)
+#define S3C64XX_GPB0_EINT_G1_8         (0x07 << 0)
+
+#define S3C64XX_GPB1_UART_TXD2         (0x02 << 4)
+#define S3C64XX_GPB1_EXTDMA_ACK                (0x03 << 4)
+#define S3C64XX_GPB1_IrDA_TXD          (0x04 << 4)
+#define S3C64XX_GPB1_ADDR_CF1          (0x05 << 4)
+#define S3C64XX_GPB1_EINT_G1_9         (0x07 << 4)
+
+#define S3C64XX_GPB2_UART_RXD3         (0x02 << 8)
+#define S3C64XX_GPB2_IrDA_RXD          (0x03 << 8)
+#define S3C64XX_GPB2_EXTDMA_REQ                (0x04 << 8)
+#define S3C64XX_GPB2_ADDR_CF2          (0x05 << 8)
+#define S3C64XX_GPB2_I2C_SCL1          (0x06 << 8)
+#define S3C64XX_GPB2_EINT_G1_10                (0x07 << 8)
+
+#define S3C64XX_GPB3_UART_TXD3         (0x02 << 12)
+#define S3C64XX_GPB3_IrDA_TXD          (0x03 << 12)
+#define S3C64XX_GPB3_EXTDMA_ACK                (0x04 << 12)
+#define S3C64XX_GPB3_I2C_SDA1          (0x06 << 12)
+#define S3C64XX_GPB3_EINT_G1_11                (0x07 << 12)
+
+#define S3C64XX_GPB4_IrDA_SDBW         (0x02 << 16)
+#define S3C64XX_GPB4_CAM_FIELD         (0x03 << 16)
+#define S3C64XX_GPB4_CF_DATA_DIR       (0x04 << 16)
+#define S3C64XX_GPB4_EINT_G1_12                (0x07 << 16)
+
+#define S3C64XX_GPB5_I2C_SCL0          (0x02 << 20)
+#define S3C64XX_GPB5_EINT_G1_13                (0x07 << 20)
+
+#define S3C64XX_GPB6_I2C_SDA0          (0x02 << 24)
+#define S3C64XX_GPB6_EINT_G1_14                (0x07 << 24)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-c.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-c.h
new file mode 100644 (file)
index 0000000..c47daf7
--- /dev/null
@@ -0,0 +1,53 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-c.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank C register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPCCON                 (S3C64XX_GPC_BASE + 0x00)
+#define S3C64XX_GPCDAT                 (S3C64XX_GPC_BASE + 0x04)
+#define S3C64XX_GPCPUD                 (S3C64XX_GPC_BASE + 0x08)
+#define S3C64XX_GPCCONSLP              (S3C64XX_GPC_BASE + 0x0c)
+#define S3C64XX_GPCPUDSLP              (S3C64XX_GPC_BASE + 0x10)
+
+#define S3C64XX_GPC_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPC_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPC_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPC0_SPI_MISO0         (0x02 << 0)
+#define S3C64XX_GPC0_EINT_G2_0         (0x07 << 0)
+
+#define S3C64XX_GPC1_SPI_CLKO          (0x02 << 4)
+#define S3C64XX_GPC1_EINT_G2_1         (0x07 << 4)
+
+#define S3C64XX_GPC2_SPI_MOSIO         (0x02 << 8)
+#define S3C64XX_GPC2_EINT_G2_2         (0x07 << 8)
+
+#define S3C64XX_GPC3_SPI_nCSO          (0x02 << 12)
+#define S3C64XX_GPC3_EINT_G2_3         (0x07 << 12)
+
+#define S3C64XX_GPC4_SPI_MISO1         (0x02 << 16)
+#define S3C64XX_GPC4_MMC2_CMD          (0x03 << 16)
+#define S3C64XX_GPC4_I2S0_V40_DO       (0x05 << 16)
+#define S3C64XX_GPC4_EINT_G2_4         (0x07 << 16)
+
+#define S3C64XX_GPC5_SPI_CLK1          (0x02 << 20)
+#define S3C64XX_GPC5_MMC2_CLK          (0x03 << 20)
+#define S3C64XX_GPC5_I2S1_V40_DO       (0x05 << 20)
+#define S3C64XX_GPC5_EINT_G2_5         (0x07 << 20)
+
+#define S3C64XX_GPC6_SPI_MOSI1         (0x02 << 24)
+#define S3C64XX_GPC6_EINT_G2_6         (0x07 << 24)
+
+#define S3C64XX_GPC7_SPI_nCS1          (0x02 << 28)
+#define S3C64XX_GPC7_I2S2_V40_DO       (0x05 << 28)
+#define S3C64XX_GPC7_EINT_G2_7         (0x07 << 28)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-d.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-d.h
new file mode 100644 (file)
index 0000000..6fe4a49
--- /dev/null
@@ -0,0 +1,49 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-d.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank D register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPDCON                 (S3C64XX_GPD_BASE + 0x00)
+#define S3C64XX_GPDDAT                 (S3C64XX_GPD_BASE + 0x04)
+#define S3C64XX_GPDPUD                 (S3C64XX_GPD_BASE + 0x08)
+#define S3C64XX_GPDCONSLP              (S3C64XX_GPD_BASE + 0x0c)
+#define S3C64XX_GPDPUDSLP              (S3C64XX_GPD_BASE + 0x10)
+
+#define S3C64XX_GPD_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPD_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPD_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPD0_PCM0_SCLK         (0x02 << 0)
+#define S3C64XX_GPD0_I2S0_CLK          (0x03 << 0)
+#define S3C64XX_GPD0_AC97_BITCLK       (0x04 << 0)
+#define S3C64XX_GPD0_EINT_G3_0         (0x07 << 0)
+
+#define S3C64XX_GPD1_PCM0_EXTCLK       (0x02 << 4)
+#define S3C64XX_GPD1_I2S0_CDCLK                (0x03 << 4)
+#define S3C64XX_GPD1_AC97_nRESET       (0x04 << 4)
+#define S3C64XX_GPD1_EINT_G3_1         (0x07 << 4)
+
+#define S3C64XX_GPD2_PCM0_FSYNC                (0x02 << 8)
+#define S3C64XX_GPD2_I2S0_LRCLK                (0x03 << 8)
+#define S3C64XX_GPD2_AC97_SYNC         (0x04 << 8)
+#define S3C64XX_GPD2_EINT_G3_2         (0x07 << 8)
+
+#define S3C64XX_GPD3_PCM0_SIN          (0x02 << 12)
+#define S3C64XX_GPD3_I2S0_DI           (0x03 << 12)
+#define S3C64XX_GPD3_AC97_SDI          (0x04 << 12)
+#define S3C64XX_GPD3_EINT_G3_3         (0x07 << 12)
+
+#define S3C64XX_GPD4_PCM0_SOUT         (0x02 << 16)
+#define S3C64XX_GPD4_I2S0_D0           (0x03 << 16)
+#define S3C64XX_GPD4_AC97_SDO          (0x04 << 16)
+#define S3C64XX_GPD4_EINT_G3_4         (0x07 << 16)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-e.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-e.h
new file mode 100644 (file)
index 0000000..7fcf3d8
--- /dev/null
@@ -0,0 +1,44 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-e.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank E register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPECON                 (S3C64XX_GPE_BASE + 0x00)
+#define S3C64XX_GPEDAT                 (S3C64XX_GPE_BASE + 0x04)
+#define S3C64XX_GPEPUD                 (S3C64XX_GPE_BASE + 0x08)
+#define S3C64XX_GPECONSLP              (S3C64XX_GPE_BASE + 0x0c)
+#define S3C64XX_GPEPUDSLP              (S3C64XX_GPE_BASE + 0x10)
+
+#define S3C64XX_GPE_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPE_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPE_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPE0_PCM1_SCLK         (0x02 << 0)
+#define S3C64XX_GPE0_I2S1_CLK          (0x03 << 0)
+#define S3C64XX_GPE0_AC97_BITCLK       (0x04 << 0)
+
+#define S3C64XX_GPE1_PCM1_EXTCLK       (0x02 << 4)
+#define S3C64XX_GPE1_I2S1_CDCLK                (0x03 << 4)
+#define S3C64XX_GPE1_AC97_nRESET       (0x04 << 4)
+
+#define S3C64XX_GPE2_PCM1_FSYNC                (0x02 << 8)
+#define S3C64XX_GPE2_I2S1_LRCLK                (0x03 << 8)
+#define S3C64XX_GPE2_AC97_SYNC         (0x04 << 8)
+
+#define S3C64XX_GPE3_PCM1_SIN          (0x02 << 12)
+#define S3C64XX_GPE3_I2S1_DI           (0x03 << 12)
+#define S3C64XX_GPE3_AC97_SDI          (0x04 << 12)
+
+#define S3C64XX_GPE4_PCM1_SOUT         (0x02 << 16)
+#define S3C64XX_GPE4_I2S1_D0           (0x03 << 16)
+#define S3C64XX_GPE4_AC97_SDO          (0x04 << 16)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-f.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-f.h
new file mode 100644 (file)
index 0000000..f3faff9
--- /dev/null
@@ -0,0 +1,71 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-f.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank F register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPFCON                 (S3C64XX_GPF_BASE + 0x00)
+#define S3C64XX_GPFDAT                 (S3C64XX_GPF_BASE + 0x04)
+#define S3C64XX_GPFPUD                 (S3C64XX_GPF_BASE + 0x08)
+#define S3C64XX_GPFCONSLP              (S3C64XX_GPF_BASE + 0x0c)
+#define S3C64XX_GPFPUDSLP              (S3C64XX_GPF_BASE + 0x10)
+
+#define S3C64XX_GPF_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPF_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPF_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPF0_CAMIF_CLK         (0x02 << 0)
+#define S3C64XX_GPF0_EINT_G4_0         (0x03 << 0)
+
+#define S3C64XX_GPF1_CAMIF_HREF                (0x02 << 2)
+#define S3C64XX_GPF1_EINT_G4_1         (0x03 << 2)
+
+#define S3C64XX_GPF2_CAMIF_PCLK                (0x02 << 4)
+#define S3C64XX_GPF2_EINT_G4_2         (0x03 << 4)
+
+#define S3C64XX_GPF3_CAMIF_nRST                (0x02 << 6)
+#define S3C64XX_GPF3_EINT_G4_3         (0x03 << 6)
+
+#define S3C64XX_GPF4_CAMIF_VSYNC       (0x02 << 8)
+#define S3C64XX_GPF4_EINT_G4_4         (0x03 << 8)
+
+#define S3C64XX_GPF5_CAMIF_YDATA0      (0x02 << 10)
+#define S3C64XX_GPF5_EINT_G4_5         (0x03 << 10)
+
+#define S3C64XX_GPF6_CAMIF_YDATA1      (0x02 << 12)
+#define S3C64XX_GPF6_EINT_G4_6         (0x03 << 12)
+
+#define S3C64XX_GPF7_CAMIF_YDATA2      (0x02 << 14)
+#define S3C64XX_GPF7_EINT_G4_7         (0x03 << 14)
+
+#define S3C64XX_GPF8_CAMIF_YDATA3      (0x02 << 16)
+#define S3C64XX_GPF8_EINT_G4_8         (0x03 << 16)
+
+#define S3C64XX_GPF9_CAMIF_YDATA4      (0x02 << 18)
+#define S3C64XX_GPF9_EINT_G4_9         (0x03 << 18)
+
+#define S3C64XX_GPF10_CAMIF_YDATA5     (0x02 << 20)
+#define S3C64XX_GPF10_EINT_G4_10       (0x03 << 20)
+
+#define S3C64XX_GPF11_CAMIF_YDATA6     (0x02 << 22)
+#define S3C64XX_GPF11_EINT_G4_11       (0x03 << 22)
+
+#define S3C64XX_GPF12_CAMIF_YDATA7     (0x02 << 24)
+#define S3C64XX_GPF12_EINT_G4_12       (0x03 << 24)
+
+#define S3C64XX_GPF13_PWM_ECLK         (0x02 << 26)
+#define S3C64XX_GPF13_EINT_G4_13       (0x03 << 26)
+
+#define S3C64XX_GPF14_PWM_TOUT0                (0x02 << 28)
+#define S3C64XX_GPF14_CLKOUT0          (0x03 << 28)
+
+#define S3C64XX_GPF15_PWM_TOUT1                (0x02 << 30)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-g.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-g.h
new file mode 100644 (file)
index 0000000..35bbd23
--- /dev/null
@@ -0,0 +1,42 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-g.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank G register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPGCON                 (S3C64XX_GPG_BASE + 0x00)
+#define S3C64XX_GPGDAT                 (S3C64XX_GPG_BASE + 0x04)
+#define S3C64XX_GPGPUD                 (S3C64XX_GPG_BASE + 0x08)
+#define S3C64XX_GPGCONSLP              (S3C64XX_GPG_BASE + 0x0c)
+#define S3C64XX_GPGPUDSLP              (S3C64XX_GPG_BASE + 0x10)
+
+#define S3C64XX_GPG_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPG_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPG_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPG0_MMC0_CLK          (0x02 << 0)
+#define S3C64XX_GPG0_EINT_G5_0         (0x07 << 0)
+
+#define S3C64XX_GPG1_MMC0_CMD          (0x02 << 4)
+#define S3C64XX_GPG1_EINT_G5_1         (0x07 << 4)
+
+#define S3C64XX_GPG2_MMC0_DATA0                (0x02 << 8)
+#define S3C64XX_GPG2_EINT_G5_2         (0x07 << 8)
+
+#define S3C64XX_GPG3_MMC0_DATA1                (0x02 << 12)
+#define S3C64XX_GPG3_EINT_G5_3         (0x07 << 12)
+
+#define S3C64XX_GPG4_MMC0_DATA2                (0x02 << 16)
+#define S3C64XX_GPG4_EINT_G5_4         (0x07 << 16)
+
+#define S3C64XX_GPG5_MMC0_DATA3                (0x02 << 20)
+#define S3C64XX_GPG5_EINT_G5_5         (0x07 << 20)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-h.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-h.h
new file mode 100644 (file)
index 0000000..8154951
--- /dev/null
@@ -0,0 +1,74 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-h.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank H register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPHCON0                        (S3C64XX_GPH_BASE + 0x00)
+#define S3C64XX_GPHCON1                        (S3C64XX_GPH_BASE + 0x04)
+#define S3C64XX_GPHDAT                 (S3C64XX_GPH_BASE + 0x08)
+#define S3C64XX_GPHPUD                 (S3C64XX_GPH_BASE + 0x0c)
+#define S3C64XX_GPHCONSLP              (S3C64XX_GPH_BASE + 0x10)
+#define S3C64XX_GPHPUDSLP              (S3C64XX_GPH_BASE + 0x14)
+
+#define S3C64XX_GPH_CONMASK(__gpio)    (0xf << ((__gpio) * 4))
+#define S3C64XX_GPH_INPUT(__gpio)      (0x0 << ((__gpio) * 4))
+#define S3C64XX_GPH_OUTPUT(__gpio)     (0x1 << ((__gpio) * 4))
+
+#define S3C64XX_GPH0_MMC1_CLK          (0x02 << 0)
+#define S3C64XX_GPH0_KP_COL0           (0x04 << 0)
+#define S3C64XX_GPH0_EINT_G6_0         (0x07 << 0)
+
+#define S3C64XX_GPH1_MMC1_CMD          (0x02 << 4)
+#define S3C64XX_GPH1_KP_COL1           (0x04 << 4)
+#define S3C64XX_GPH1_EINT_G6_1         (0x07 << 4)
+
+#define S3C64XX_GPH2_MMC1_DATA0                (0x02 << 8)
+#define S3C64XX_GPH2_KP_COL2           (0x04 << 8)
+#define S3C64XX_GPH2_EINT_G6_2         (0x07 << 8)
+
+#define S3C64XX_GPH3_MMC1_DATA1                (0x02 << 12)
+#define S3C64XX_GPH3_KP_COL3           (0x04 << 12)
+#define S3C64XX_GPH3_EINT_G6_3         (0x07 << 12)
+
+#define S3C64XX_GPH4_MMC1_DATA2                (0x02 << 16)
+#define S3C64XX_GPH4_KP_COL4           (0x04 << 16)
+#define S3C64XX_GPH4_EINT_G6_4         (0x07 << 16)
+
+#define S3C64XX_GPH5_MMC1_DATA3                (0x02 << 20)
+#define S3C64XX_GPH5_KP_COL5           (0x04 << 20)
+#define S3C64XX_GPH5_EINT_G6_5         (0x07 << 20)
+
+#define S3C64XX_GPH6_MMC1_DATA4                (0x02 << 24)
+#define S3C64XX_GPH6_MMC2_DATA0                (0x03 << 24)
+#define S3C64XX_GPH6_KP_COL6           (0x04 << 24)
+#define S3C64XX_GPH6_I2S_V40_BCLK      (0x05 << 24)
+#define S3C64XX_GPH6_ADDR_CF0          (0x06 << 24)
+#define S3C64XX_GPH6_EINT_G6_6         (0x07 << 24)
+
+#define S3C64XX_GPH7_MMC1_DATA5                (0x02 << 28)
+#define S3C64XX_GPH7_MMC2_DATA1                (0x03 << 28)
+#define S3C64XX_GPH7_KP_COL7           (0x04 << 28)
+#define S3C64XX_GPH7_I2S_V40_CDCLK     (0x05 << 28)
+#define S3C64XX_GPH7_ADDR_CF1          (0x06 << 28)
+#define S3C64XX_GPH7_EINT_G6_7         (0x07 << 28)
+
+#define S3C64XX_GPH8_MMC1_DATA6                (0x02 << 32)
+#define S3C64XX_GPH8_MMC2_DATA2                (0x03 << 32)
+#define S3C64XX_GPH8_I2S_V40_LRCLK     (0x05 << 32)
+#define S3C64XX_GPH8_ADDR_CF2          (0x06 << 32)
+#define S3C64XX_GPH8_EINT_G6_8         (0x07 << 32)
+
+#define S3C64XX_GPH9_MMC1_DATA7                (0x02 << 36)
+#define S3C64XX_GPH9_MMC2_DATA3                (0x03 << 36)
+#define S3C64XX_GPH9_I2S_V40_DI                (0x05 << 36)
+#define S3C64XX_GPH9_EINT_G6_9         (0x07 << 36)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-i.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-i.h
new file mode 100644 (file)
index 0000000..ce9ebe3
--- /dev/null
@@ -0,0 +1,40 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-i.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank I register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPICON                 (S3C64XX_GPI_BASE + 0x00)
+#define S3C64XX_GPIDAT                 (S3C64XX_GPI_BASE + 0x04)
+#define S3C64XX_GPIPUD                 (S3C64XX_GPI_BASE + 0x08)
+#define S3C64XX_GPICONSLP              (S3C64XX_GPI_BASE + 0x0c)
+#define S3C64XX_GPIPUDSLP              (S3C64XX_GPI_BASE + 0x10)
+
+#define S3C64XX_GPI_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPI_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPI_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPI0_VD0               (0x02 << 0)
+#define S3C64XX_GPI1_VD1               (0x02 << 2)
+#define S3C64XX_GPI2_VD2               (0x02 << 4)
+#define S3C64XX_GPI3_VD3               (0x02 << 6)
+#define S3C64XX_GPI4_VD4               (0x02 << 8)
+#define S3C64XX_GPI5_VD5               (0x02 << 10)
+#define S3C64XX_GPI6_VD6               (0x02 << 12)
+#define S3C64XX_GPI7_VD7               (0x02 << 14)
+#define S3C64XX_GPI8_VD8               (0x02 << 16)
+#define S3C64XX_GPI9_VD9               (0x02 << 18)
+#define S3C64XX_GPI10_VD10             (0x02 << 20)
+#define S3C64XX_GPI11_VD11             (0x02 << 22)
+#define S3C64XX_GPI12_VD12             (0x02 << 24)
+#define S3C64XX_GPI13_VD13             (0x02 << 26)
+#define S3C64XX_GPI14_VD14             (0x02 << 28)
+#define S3C64XX_GPI15_VD15             (0x02 << 30)
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-j.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-j.h
new file mode 100644 (file)
index 0000000..21a9062
--- /dev/null
@@ -0,0 +1,36 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-j.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank J register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPJCON                 (S3C64XX_GPJ_BASE + 0x00)
+#define S3C64XX_GPJDAT                 (S3C64XX_GPJ_BASE + 0x04)
+#define S3C64XX_GPJPUD                 (S3C64XX_GPJ_BASE + 0x08)
+#define S3C64XX_GPJCONSLP              (S3C64XX_GPJ_BASE + 0x0c)
+#define S3C64XX_GPJPUDSLP              (S3C64XX_GPJ_BASE + 0x10)
+
+#define S3C64XX_GPJ_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPJ_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPJ_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPJ0_VD16              (0x02 << 0)
+#define S3C64XX_GPJ1_VD17              (0x02 << 2)
+#define S3C64XX_GPJ2_VD18              (0x02 << 4)
+#define S3C64XX_GPJ3_VD19              (0x02 << 6)
+#define S3C64XX_GPJ4_VD20              (0x02 << 8)
+#define S3C64XX_GPJ5_VD21              (0x02 << 10)
+#define S3C64XX_GPJ6_VD22              (0x02 << 12)
+#define S3C64XX_GPJ7_VD23              (0x02 << 14)
+#define S3C64XX_GPJ8_LCD_HSYNC         (0x02 << 16)
+#define S3C64XX_GPJ9_LCD_VSYNC         (0x02 << 18)
+#define S3C64XX_GPJ10_LCD_VDEN         (0x02 << 20)
+#define S3C64XX_GPJ11_LCD_VCLK         (0x02 << 22)
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-n.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-n.h
new file mode 100644 (file)
index 0000000..569e761
--- /dev/null
@@ -0,0 +1,54 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-n.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank N register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPNCON                 (S3C64XX_GPN_BASE + 0x00)
+#define S3C64XX_GPNDAT                 (S3C64XX_GPN_BASE + 0x04)
+#define S3C64XX_GPNPUD                 (S3C64XX_GPN_BASE + 0x08)
+
+#define S3C64XX_GPN_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPN_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPN_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPN0_EINT0             (0x02 << 0)
+#define S3C64XX_GPN0_KP_ROW0           (0x03 << 0)
+
+#define S3C64XX_GPN1_EINT1             (0x02 << 2)
+#define S3C64XX_GPN1_KP_ROW1           (0x03 << 2)
+
+#define S3C64XX_GPN2_EINT2             (0x02 << 4)
+#define S3C64XX_GPN2_KP_ROW2           (0x03 << 4)
+
+#define S3C64XX_GPN3_EINT3             (0x02 << 6)
+#define S3C64XX_GPN3_KP_ROW3           (0x03 << 6)
+
+#define S3C64XX_GPN4_EINT4             (0x02 << 8)
+#define S3C64XX_GPN4_KP_ROW4           (0x03 << 8)
+
+#define S3C64XX_GPN5_EINT5             (0x02 << 10)
+#define S3C64XX_GPN5_KP_ROW5           (0x03 << 10)
+
+#define S3C64XX_GPN6_EINT6             (0x02 << 12)
+#define S3C64XX_GPN6_KP_ROW6           (0x03 << 12)
+
+#define S3C64XX_GPN7_EINT7             (0x02 << 14)
+#define S3C64XX_GPN7_KP_ROW7           (0x03 << 14)
+
+#define S3C64XX_GPN8_EINT8             (0x02 << 16)
+#define S3C64XX_GPN9_EINT9             (0x02 << 18)
+#define S3C64XX_GPN10_EINT10           (0x02 << 20)
+#define S3C64XX_GPN11_EINT11           (0x02 << 22)
+#define S3C64XX_GPN12_EINT12           (0x02 << 24)
+#define S3C64XX_GPN13_EINT13           (0x02 << 26)
+#define S3C64XX_GPN14_EINT14           (0x02 << 28)
+#define S3C64XX_GPN15_EINT15           (0x02 << 30)
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-o.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-o.h
new file mode 100644 (file)
index 0000000..b09e129
--- /dev/null
@@ -0,0 +1,70 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-o.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank O register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPOCON                 (S3C64XX_GPO_BASE + 0x00)
+#define S3C64XX_GPODAT                 (S3C64XX_GPO_BASE + 0x04)
+#define S3C64XX_GPOPUD                 (S3C64XX_GPO_BASE + 0x08)
+#define S3C64XX_GPOCONSLP              (S3C64XX_GPO_BASE + 0x0c)
+#define S3C64XX_GPOPUDSLP              (S3C64XX_GPO_BASE + 0x10)
+
+#define S3C64XX_GPO_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPO_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPO_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPO0_MEM0_nCS2         (0x02 << 0)
+#define S3C64XX_GPO0_EINT_G7_0         (0x03 << 0)
+
+#define S3C64XX_GPO1_MEM0_nCS3         (0x02 << 2)
+#define S3C64XX_GPO1_EINT_G7_1         (0x03 << 2)
+
+#define S3C64XX_GPO2_MEM0_nCS4         (0x02 << 4)
+#define S3C64XX_GPO2_EINT_G7_2         (0x03 << 4)
+
+#define S3C64XX_GPO3_MEM0_nCS5         (0x02 << 6)
+#define S3C64XX_GPO3_EINT_G7_3         (0x03 << 6)
+
+#define S3C64XX_GPO4_EINT_G7_4         (0x03 << 8)
+
+#define S3C64XX_GPO5_EINT_G7_5         (0x03 << 10)
+
+#define S3C64XX_GPO6_MEM0_ADDR6                (0x02 << 12)
+#define S3C64XX_GPO6_EINT_G7_6         (0x03 << 12)
+
+#define S3C64XX_GPO7_MEM0_ADDR7                (0x02 << 14)
+#define S3C64XX_GPO7_EINT_G7_7         (0x03 << 14)
+
+#define S3C64XX_GPO8_MEM0_ADDR8                (0x02 << 16)
+#define S3C64XX_GPO8_EINT_G7_8         (0x03 << 16)
+
+#define S3C64XX_GPO9_MEM0_ADDR9                (0x02 << 18)
+#define S3C64XX_GPO9_EINT_G7_9         (0x03 << 18)
+
+#define S3C64XX_GPO10_MEM0_ADDR10      (0x02 << 20)
+#define S3C64XX_GPO10_EINT_G7_10       (0x03 << 20)
+
+#define S3C64XX_GPO11_MEM0_ADDR11      (0x02 << 22)
+#define S3C64XX_GPO11_EINT_G7_11       (0x03 << 22)
+
+#define S3C64XX_GPO12_MEM0_ADDR12      (0x02 << 24)
+#define S3C64XX_GPO12_EINT_G7_12       (0x03 << 24)
+
+#define S3C64XX_GPO13_MEM0_ADDR13      (0x02 << 26)
+#define S3C64XX_GPO13_EINT_G7_13       (0x03 << 26)
+
+#define S3C64XX_GPO14_MEM0_ADDR14      (0x02 << 28)
+#define S3C64XX_GPO14_EINT_G7_14       (0x03 << 28)
+
+#define S3C64XX_GPO15_MEM0_ADDR15      (0x02 << 30)
+#define S3C64XX_GPO15_EINT_G7_15       (0x03 << 30)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-p.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-p.h
new file mode 100644 (file)
index 0000000..92f0051
--- /dev/null
@@ -0,0 +1,69 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-p.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank P register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPPCON                 (S3C64XX_GPP_BASE + 0x00)
+#define S3C64XX_GPPDAT                 (S3C64XX_GPP_BASE + 0x04)
+#define S3C64XX_GPPPUD                 (S3C64XX_GPP_BASE + 0x08)
+#define S3C64XX_GPPCONSLP              (S3C64XX_GPP_BASE + 0x0c)
+#define S3C64XX_GPPPUDSLP              (S3C64XX_GPP_BASE + 0x10)
+
+#define S3C64XX_GPP_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPP_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPP_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPP0_MEM0_ADDRV                (0x02 << 0)
+#define S3C64XX_GPP0_EINT_G8_0         (0x03 << 0)
+
+#define S3C64XX_GPP1_MEM0_SMCLK                (0x02 << 2)
+#define S3C64XX_GPP1_EINT_G8_1         (0x03 << 2)
+
+#define S3C64XX_GPP2_MEM0_nWAIT                (0x02 << 4)
+#define S3C64XX_GPP2_EINT_G8_2         (0x03 << 4)
+
+#define S3C64XX_GPP3_MEM0_RDY0_ALE     (0x02 << 6)
+#define S3C64XX_GPP3_EINT_G8_3         (0x03 << 6)
+
+#define S3C64XX_GPP4_MEM0_RDY1_CLE     (0x02 << 8)
+#define S3C64XX_GPP4_EINT_G8_4         (0x03 << 8)
+
+#define S3C64XX_GPP5_MEM0_INTsm0_FWE   (0x02 << 10)
+#define S3C64XX_GPP5_EINT_G8_5         (0x03 << 10)
+
+#define S3C64XX_GPP6_MEM0_(null)       (0x02 << 12)
+#define S3C64XX_GPP6_EINT_G8_6         (0x03 << 12)
+
+#define S3C64XX_GPP7_MEM0_INTsm1_FRE   (0x02 << 14)
+#define S3C64XX_GPP7_EINT_G8_7         (0x03 << 14)
+
+#define S3C64XX_GPP8_MEM0_RPn_RnB      (0x02 << 16)
+#define S3C64XX_GPP8_EINT_G8_8         (0x03 << 16)
+
+#define S3C64XX_GPP9_MEM0_ATA_RESET    (0x02 << 18)
+#define S3C64XX_GPP9_EINT_G8_9         (0x03 << 18)
+
+#define S3C64XX_GPP10_MEM0_ATA_INPACK  (0x02 << 20)
+#define S3C64XX_GPP10_EINT_G8_10       (0x03 << 20)
+
+#define S3C64XX_GPP11_MEM0_ATA_REG     (0x02 << 22)
+#define S3C64XX_GPP11_EINT_G8_11       (0x03 << 22)
+
+#define S3C64XX_GPP12_MEM0_ATA_WE      (0x02 << 24)
+#define S3C64XX_GPP12_EINT_G8_12       (0x03 << 24)
+
+#define S3C64XX_GPP13_MEM0_ATA_OE      (0x02 << 26)
+#define S3C64XX_GPP13_EINT_G8_13       (0x03 << 26)
+
+#define S3C64XX_GPP14_MEM0_ATA_CD      (0x02 << 28)
+#define S3C64XX_GPP14_EINT_G8_14       (0x03 << 28)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/gpio-bank-q.h b/arch/arm/plat-s3c64xx/include/plat/gpio-bank-q.h
new file mode 100644 (file)
index 0000000..565e60a
--- /dev/null
@@ -0,0 +1,46 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-q.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * GPIO Bank Q register and configuration definitions
+ *
+ * This program is free software; you can 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 S3C64XX_GPQCON                 (S3C64XX_GPQ_BASE + 0x00)
+#define S3C64XX_GPQDAT                 (S3C64XX_GPQ_BASE + 0x04)
+#define S3C64XX_GPQPUD                 (S3C64XX_GPQ_BASE + 0x08)
+#define S3C64XX_GPQCONSLP              (S3C64XX_GPQ_BASE + 0x0c)
+#define S3C64XX_GPQPUDSLP              (S3C64XX_GPQ_BASE + 0x10)
+
+#define S3C64XX_GPQ_CONMASK(__gpio)    (0x3 << ((__gpio) * 2))
+#define S3C64XX_GPQ_INPUT(__gpio)      (0x0 << ((__gpio) * 2))
+#define S3C64XX_GPQ_OUTPUT(__gpio)     (0x1 << ((__gpio) * 2))
+
+#define S3C64XX_GPQ0_MEM0_ADDR18_RAS   (0x02 << 0)
+#define S3C64XX_GPQ0_EINT_G9_0         (0x03 << 0)
+
+#define S3C64XX_GPQ1_MEM0_ADDR19_CAS   (0x02 << 2)
+#define S3C64XX_GPQ1_EINT_G9_1         (0x03 << 2)
+
+#define S3C64XX_GPQ2_EINT_G9_2         (0x03 << 4)
+
+#define S3C64XX_GPQ3_EINT_G9_3         (0x03 << 6)
+
+#define S3C64XX_GPQ4_EINT_G9_4         (0x03 << 8)
+
+#define S3C64XX_GPQ5_EINT_G9_5         (0x03 << 10)
+
+#define S3C64XX_GPQ6_EINT_G9_6         (0x03 << 12)
+
+#define S3C64XX_GPQ7_MEM0_ADDR17_WENDMC        (0x02 << 14)
+#define S3C64XX_GPQ7_EINT_G9_7         (0x03 << 14)
+
+#define S3C64XX_GPQ8_MEM0_ADDR16_APDMC (0x02 << 16)
+#define S3C64XX_GPQ8_EINT_G9_8         (0x03 << 16)
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/irqs.h b/arch/arm/plat-s3c64xx/include/plat/irqs.h
new file mode 100644 (file)
index 0000000..02e8dd4
--- /dev/null
@@ -0,0 +1,201 @@
+/* linux/arch/arm/plat-s3c64xx/include/mach/irqs.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Common IRQ support
+ */
+
+#ifndef __ASM_PLAT_S3C64XX_IRQS_H
+#define __ASM_PLAT_S3C64XX_IRQS_H __FILE__
+
+/* we keep the first set of CPU IRQs out of the range of
+ * the ISA space, so that the PC104 has them to itself
+ * and we don't end up having to do horrible things to the
+ * standard ISA drivers....
+ *
+ * note, since we're using the VICs, our start must be a
+ * mulitple of 32 to allow the common code to work
+ */
+
+#define S3C_IRQ_OFFSET (32)
+
+#define S3C_IRQ(x)     ((x) + S3C_IRQ_OFFSET)
+
+#define S3C_VIC0_BASE  S3C_IRQ(0)
+#define S3C_VIC1_BASE  S3C_IRQ(32)
+
+/* UART interrupts, each UART has 4 intterupts per channel so
+ * use the space between the ISA and S3C main interrupts. Note, these
+ * are not in the same order as the S3C24XX series! */
+
+#define IRQ_S3CUART_BASE0      (16)
+#define IRQ_S3CUART_BASE1      (20)
+#define IRQ_S3CUART_BASE2      (24)
+#define IRQ_S3CUART_BASE3      (28)
+
+#define UART_IRQ_RXD           (0)
+#define UART_IRQ_ERR           (1)
+#define UART_IRQ_TXD           (2)
+#define UART_IRQ_MODEM         (3)
+
+#define IRQ_S3CUART_RX0                (IRQ_S3CUART_BASE0 + UART_IRQ_RXD)
+#define IRQ_S3CUART_TX0                (IRQ_S3CUART_BASE0 + UART_IRQ_TXD)
+#define IRQ_S3CUART_ERR0       (IRQ_S3CUART_BASE0 + UART_IRQ_ERR)
+
+#define IRQ_S3CUART_RX1                (IRQ_S3CUART_BASE1 + UART_IRQ_RXD)
+#define IRQ_S3CUART_TX1                (IRQ_S3CUART_BASE1 + UART_IRQ_TXD)
+#define IRQ_S3CUART_ERR1       (IRQ_S3CUART_BASE1 + UART_IRQ_ERR)
+
+#define IRQ_S3CUART_RX2                (IRQ_S3CUART_BASE2 + UART_IRQ_RXD)
+#define IRQ_S3CUART_TX2                (IRQ_S3CUART_BASE2 + UART_IRQ_TXD)
+#define IRQ_S3CUART_ERR2       (IRQ_S3CUART_BASE2 + UART_IRQ_ERR)
+
+#define IRQ_S3CUART_RX3                (IRQ_S3CUART_BASE3 + UART_IRQ_RXD)
+#define IRQ_S3CUART_TX3                (IRQ_S3CUART_BASE3 + UART_IRQ_TXD)
+#define IRQ_S3CUART_ERR3       (IRQ_S3CUART_BASE3 + UART_IRQ_ERR)
+
+/* VIC based IRQs */
+
+#define S3C64XX_IRQ_VIC0(x)    (S3C_VIC0_BASE + (x))
+#define S3C64XX_IRQ_VIC1(x)    (S3C_VIC1_BASE + (x))
+
+/* VIC0 */
+
+#define IRQ_EINT0_3            S3C64XX_IRQ_VIC0(0)
+#define IRQ_EINT4_11           S3C64XX_IRQ_VIC0(1)
+#define IRQ_RTC_TIC            S3C64XX_IRQ_VIC0(2)
+#define IRQ_CAMIF_C            S3C64XX_IRQ_VIC0(3)
+#define IRQ_CAMIF_P            S3C64XX_IRQ_VIC0(4)
+#define IRQ_CAMIF_MC           S3C64XX_IRQ_VIC0(5)
+#define IRQ_S3C6410_IIC1       S3C64XX_IRQ_VIC0(5)
+#define IRQ_S3C6410_IIS                S3C64XX_IRQ_VIC0(6)
+#define IRQ_S3C6400_CAMIF_MP   S3C64XX_IRQ_VIC0(6)
+#define IRQ_CAMIF_WE_C         S3C64XX_IRQ_VIC0(7)
+#define IRQ_S3C6410_G3D                S3C64XX_IRQ_VIC0(8)
+#define IRQ_S3C6400_CAMIF_WE_P S3C64XX_IRQ_VIC0(8)
+#define IRQ_POST0              S3C64XX_IRQ_VIC0(9)
+#define IRQ_ROTATOR            S3C64XX_IRQ_VIC0(10)
+#define IRQ_2D                 S3C64XX_IRQ_VIC0(11)
+#define IRQ_TVENC              S3C64XX_IRQ_VIC0(12)
+#define IRQ_SCALER             S3C64XX_IRQ_VIC0(13)
+#define IRQ_BATF               S3C64XX_IRQ_VIC0(14)
+#define IRQ_JPEG               S3C64XX_IRQ_VIC0(15)
+#define IRQ_MFC                        S3C64XX_IRQ_VIC0(16)
+#define IRQ_SDMA0              S3C64XX_IRQ_VIC0(17)
+#define IRQ_SDMA1              S3C64XX_IRQ_VIC0(18)
+#define IRQ_ARM_DMAERR         S3C64XX_IRQ_VIC0(19)
+#define IRQ_ARM_DMA            S3C64XX_IRQ_VIC0(20)
+#define IRQ_ARM_DMAS           S3C64XX_IRQ_VIC0(21)
+#define IRQ_KEYPAD             S3C64XX_IRQ_VIC0(22)
+#define IRQ_TIMER0_VIC         S3C64XX_IRQ_VIC0(23)
+#define IRQ_TIMER1_VIC         S3C64XX_IRQ_VIC0(24)
+#define IRQ_TIMER2_VIC         S3C64XX_IRQ_VIC0(25)
+#define IRQ_WDT                        S3C64XX_IRQ_VIC0(26)
+#define IRQ_TIMER3_VIC         S3C64XX_IRQ_VIC0(27)
+#define IRQ_TIMER4_VIC         S3C64XX_IRQ_VIC0(28)
+#define IRQ_LCD_FIFO           S3C64XX_IRQ_VIC0(29)
+#define IRQ_LCD_VSYNC          S3C64XX_IRQ_VIC0(30)
+#define IRQ_LCD_SYSTEM         S3C64XX_IRQ_VIC0(31)
+
+/* VIC1 */
+
+#define IRQ_EINT12_19          S3C64XX_IRQ_VIC1(0)
+#define IRQ_EINT20_27          S3C64XX_IRQ_VIC1(1)
+#define IRQ_PCM0               S3C64XX_IRQ_VIC1(2)
+#define IRQ_PCM1               S3C64XX_IRQ_VIC1(3)
+#define IRQ_AC97               S3C64XX_IRQ_VIC1(4)
+#define IRQ_UART0              S3C64XX_IRQ_VIC1(5)
+#define IRQ_UART1              S3C64XX_IRQ_VIC1(6)
+#define IRQ_UART2              S3C64XX_IRQ_VIC1(7)
+#define IRQ_UART3              S3C64XX_IRQ_VIC1(8)
+#define IRQ_DMA0               S3C64XX_IRQ_VIC1(9)
+#define IRQ_DMA1               S3C64XX_IRQ_VIC1(10)
+#define IRQ_ONENAND0           S3C64XX_IRQ_VIC1(11)
+#define IRQ_ONENAND1           S3C64XX_IRQ_VIC1(12)
+#define IRQ_NFC                        S3C64XX_IRQ_VIC1(13)
+#define IRQ_CFCON              S3C64XX_IRQ_VIC1(14)
+#define IRQ_UHOST              S3C64XX_IRQ_VIC1(15)
+#define IRQ_SPI0               S3C64XX_IRQ_VIC1(16)
+#define IRQ_SPI1               S3C64XX_IRQ_VIC1(17)
+#define IRQ_IIC                        S3C64XX_IRQ_VIC1(18)
+#define IRQ_HSItx              S3C64XX_IRQ_VIC1(19)
+#define IRQ_HSIrx              S3C64XX_IRQ_VIC1(20)
+#define IRQ_RESERVED           S3C64XX_IRQ_VIC1(21)
+#define IRQ_MSM                        S3C64XX_IRQ_VIC1(22)
+#define IRQ_HOSTIF             S3C64XX_IRQ_VIC1(23)
+#define IRQ_HSMMC0             S3C64XX_IRQ_VIC1(24)
+#define IRQ_HSMMC1             S3C64XX_IRQ_VIC1(25)
+#define IRQ_HSMMC2             IRQ_SPI1        /* shared with SPI1 */
+#define IRQ_OTG                        S3C64XX_IRQ_VIC1(26)
+#define IRQ_IRDA               S3C64XX_IRQ_VIC1(27)
+#define IRQ_RTC_ALARM          S3C64XX_IRQ_VIC1(28)
+#define IRQ_SEC                        S3C64XX_IRQ_VIC1(29)
+#define IRQ_PENDN              S3C64XX_IRQ_VIC1(30)
+#define IRQ_TC                 IRQ_PENDN
+#define IRQ_ADC                        S3C64XX_IRQ_VIC1(31)
+
+#define S3C64XX_TIMER_IRQ(x)   S3C_IRQ(64 + (x))
+
+#define IRQ_TIMER0             S3C64XX_TIMER_IRQ(0)
+#define IRQ_TIMER1             S3C64XX_TIMER_IRQ(1)
+#define IRQ_TIMER2             S3C64XX_TIMER_IRQ(2)
+#define IRQ_TIMER3             S3C64XX_TIMER_IRQ(3)
+#define IRQ_TIMER4             S3C64XX_TIMER_IRQ(4)
+
+/* compatibility for device defines */
+
+#define IRQ_IIC1               IRQ_S3C6410_IIC1
+
+/* Since the IRQ_EINT(x) are a linear mapping on current s3c64xx series
+ * we just defined them as an IRQ_EINT(x) macro from S3C_IRQ_EINT_BASE
+ * which we place after the pair of VICs. */
+
+#define S3C_IRQ_EINT_BASE      S3C_IRQ(64+5)
+
+#define S3C_EINT(x)            ((x) + S3C_IRQ_EINT_BASE)
+#define IRQ_EINT(x)            S3C_EINT(x)
+
+/* Next the external interrupt groups. These are similar to the IRQ_EINT(x)
+ * that they are sourced from the GPIO pins but with a different scheme for
+ * priority and source indication.
+ *
+ * The IRQ_EINT(x) can be thought of as 'group 0' of the available GPIO
+ * interrupts, but for historical reasons they are kept apart from these
+ * next interrupts.
+ *
+ * Use IRQ_EINT_GROUP(group, offset) to get the number for use in the
+ * machine specific support files.
+ */
+
+#define IRQ_EINT_GROUP1_NR     (15)
+#define IRQ_EINT_GROUP2_NR     (8)
+#define IRQ_EINT_GROUP3_NR     (5)
+#define IRQ_EINT_GROUP4_NR     (14)
+#define IRQ_EINT_GROUP5_NR     (7)
+#define IRQ_EINT_GROUP6_NR     (10)
+#define IRQ_EINT_GROUP7_NR     (16)
+#define IRQ_EINT_GROUP8_NR     (15)
+#define IRQ_EINT_GROUP9_NR     (9)
+
+#define IRQ_EINT_GROUP_BASE    S3C_EINT(28)
+#define IRQ_EINT_GROUP1_BASE   (IRQ_EINT_GROUP_BASE + 0x00)
+#define IRQ_EINT_GROUP2_BASE   (IRQ_EINT_GROUP1_BASE + IRQ_EINT_GROUP1_NR)
+#define IRQ_EINT_GROUP3_BASE   (IRQ_EINT_GROUP2_BASE + IRQ_EINT_GROUP2_NR)
+#define IRQ_EINT_GROUP4_BASE   (IRQ_EINT_GROUP3_BASE + IRQ_EINT_GROUP3_NR)
+#define IRQ_EINT_GROUP5_BASE   (IRQ_EINT_GROUP4_BASE + IRQ_EINT_GROUP4_NR)
+#define IRQ_EINT_GROUP6_BASE   (IRQ_EINT_GROUP5_BASE + IRQ_EINT_GROUP5_NR)
+#define IRQ_EINT_GROUP7_BASE   (IRQ_EINT_GROUP6_BASE + IRQ_EINT_GROUP6_NR)
+#define IRQ_EINT_GROUP8_BASE   (IRQ_EINT_GROUP7_BASE + IRQ_EINT_GROUP7_NR)
+#define IRQ_EINT_GROUP9_BASE   (IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR)
+
+#define IRQ_EINT_GROUP(group, no)      (IRQ_EINT_GROUP##group##__BASE + (x))
+
+/* Set the default NR_IRQS */
+
+#define NR_IRQS        (IRQ_EINT_GROUP9_BASE + IRQ_EINT_GROUP9_NR + 1)
+
+#endif /* __ASM_PLAT_S3C64XX_IRQS_H */
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/pll.h b/arch/arm/plat-s3c64xx/include/plat/pll.h
new file mode 100644 (file)
index 0000000..90bbd72
--- /dev/null
@@ -0,0 +1,74 @@
+/* arch/arm/plat-s3c64xx/include/plat/pll.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX PLL code
+ *
+ * This program is free software; you can 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 S3C6400_PLL_MDIV_MASK  ((1 << (25-16+1)) - 1)
+#define S3C6400_PLL_PDIV_MASK  ((1 << (13-8+1)) - 1)
+#define S3C6400_PLL_SDIV_MASK  ((1 << (2-0+1)) - 1)
+#define S3C6400_PLL_MDIV_SHIFT (16)
+#define S3C6400_PLL_PDIV_SHIFT (8)
+#define S3C6400_PLL_SDIV_SHIFT (0)
+
+#include <asm/div64.h>
+
+static inline unsigned long s3c6400_get_pll(unsigned long baseclk,
+                                           u32 pllcon)
+{
+       u32 mdiv, pdiv, sdiv;
+       u64 fvco = baseclk;
+
+       mdiv = (pllcon >> S3C6400_PLL_MDIV_SHIFT) & S3C6400_PLL_MDIV_MASK;
+       pdiv = (pllcon >> S3C6400_PLL_PDIV_SHIFT) & S3C6400_PLL_PDIV_MASK;
+       sdiv = (pllcon >> S3C6400_PLL_SDIV_SHIFT) & S3C6400_PLL_SDIV_MASK;
+
+       fvco *= mdiv;
+       do_div(fvco, (pdiv << sdiv));
+
+       return (unsigned long)fvco;
+}
+
+#define S3C6400_EPLL_MDIV_MASK ((1 << (23-16)) - 1)
+#define S3C6400_EPLL_PDIV_MASK ((1 << (13-8)) - 1)
+#define S3C6400_EPLL_SDIV_MASK ((1 << (2-0)) - 1)
+#define S3C6400_EPLL_MDIV_SHIFT        (16)
+#define S3C6400_EPLL_PDIV_SHIFT        (8)
+#define S3C6400_EPLL_SDIV_SHIFT        (0)
+#define S3C6400_EPLL_KDIV_MASK  (0xffff)
+
+static inline unsigned long s3c6400_get_epll(unsigned long baseclk)
+{
+       unsigned long result;
+       u32 epll0 = __raw_readl(S3C_EPLL_CON0);
+       u32 epll1 = __raw_readl(S3C_EPLL_CON1);
+       u32 mdiv, pdiv, sdiv, kdiv;
+       u64 tmp;
+
+       mdiv = (epll0 >> S3C6400_EPLL_MDIV_SHIFT) & S3C6400_EPLL_MDIV_MASK;
+       pdiv = (epll0 >> S3C6400_EPLL_PDIV_SHIFT) & S3C6400_EPLL_PDIV_MASK;
+       sdiv = (epll0 >> S3C6400_EPLL_SDIV_SHIFT) & S3C6400_EPLL_SDIV_MASK;
+       kdiv = epll1 & S3C6400_EPLL_KDIV_MASK;
+
+       /* We need to multiple baseclk by mdiv (the integer part) and kdiv
+        * which is in 2^16ths, so shift mdiv up (does not overflow) and
+        * add kdiv before multiplying. The use of tmp is to avoid any
+        * overflows before shifting bac down into result when multipling
+        * by the mdiv and kdiv pair.
+        */
+
+       tmp = baseclk;
+       tmp *= (mdiv << 16) + kdiv;
+       do_div(tmp, (pdiv << sdiv));
+       result = tmp >> 16;
+
+       return result;
+}
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h
new file mode 100644 (file)
index 0000000..b1082c1
--- /dev/null
@@ -0,0 +1,224 @@
+/* arch/arm/plat-s3c64xx/include/plat/regs-clock.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX clock register definitions
+ *
+ * This program is free software; you can 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 __PLAT_REGS_CLOCK_H
+#define __PLAT_REGS_CLOCK_H __FILE__
+
+#define S3C_CLKREG(x)          (S3C_VA_SYS + (x))
+
+#define S3C_APLL_LOCK          S3C_CLKREG(0x00)
+#define S3C_MPLL_LOCK          S3C_CLKREG(0x04)
+#define S3C_EPLL_LOCK          S3C_CLKREG(0x08)
+#define S3C_APLL_CON           S3C_CLKREG(0x0C)
+#define S3C_MPLL_CON           S3C_CLKREG(0x10)
+#define S3C_EPLL_CON0          S3C_CLKREG(0x14)
+#define S3C_EPLL_CON1          S3C_CLKREG(0x18)
+#define S3C_CLK_SRC            S3C_CLKREG(0x1C)
+#define S3C_CLK_DIV0           S3C_CLKREG(0x20)
+#define S3C_CLK_DIV1           S3C_CLKREG(0x24)
+#define S3C_CLK_DIV2           S3C_CLKREG(0x28)
+#define S3C_CLK_OUT            S3C_CLKREG(0x2C)
+#define S3C_HCLK_GATE          S3C_CLKREG(0x30)
+#define S3C_PCLK_GATE          S3C_CLKREG(0x34)
+#define S3C_SCLK_GATE          S3C_CLKREG(0x38)
+
+/* CLKDIV0 */
+#define S3C6400_CLKDIV0_MFC_MASK       (0xf << 28)
+#define S3C6400_CLKDIV0_MFC_SHIFT      (28)
+#define S3C6400_CLKDIV0_JPEG_MASK      (0xf << 24)
+#define S3C6400_CLKDIV0_JPEG_SHIFT     (24)
+#define S3C6400_CLKDIV0_CAM_MASK       (0xf << 20)
+#define S3C6400_CLKDIV0_CAM_SHIFT      (20)
+#define S3C6400_CLKDIV0_SECURITY_MASK  (0x3 << 18)
+#define S3C6400_CLKDIV0_SECURITY_SHIFT (18)
+#define S3C6400_CLKDIV0_PCLK_MASK      (0xf << 12)
+#define S3C6400_CLKDIV0_PCLK_SHIFT     (12)
+#define S3C6400_CLKDIV0_HCLK2_MASK     (0x7 << 9)
+#define S3C6400_CLKDIV0_HCLK2_SHIFT    (9)
+#define S3C6400_CLKDIV0_HCLK_MASK      (0x1 << 8)
+#define S3C6400_CLKDIV0_HCLK_SHIFT     (8)
+#define S3C6400_CLKDIV0_MPLL_MASK      (0x1 << 4)
+#define S3C6400_CLKDIV0_MPLL_SHIFT     (4)
+#define S3C6400_CLKDIV0_ARM_MASK       (0x3 << 0)
+#define S3C6410_CLKDIV0_ARM_MASK       (0x7 << 0)
+#define S3C6400_CLKDIV0_ARM_SHIFT      (0)
+
+/* CLKDIV1 */
+#define S3C6410_CLKDIV1_FIMC_MASK      (0xf << 24)
+#define S3C6410_CLKDIV1_FIMC_SHIFT     (24)
+#define S3C6400_CLKDIV1_UHOST_MASK     (0xf << 20)
+#define S3C6400_CLKDIV1_UHOST_SHIFT    (20)
+#define S3C6400_CLKDIV1_SCALER_MASK    (0xf << 16)
+#define S3C6400_CLKDIV1_SCALER_SHIFT   (16)
+#define S3C6400_CLKDIV1_LCD_MASK       (0xf << 12)
+#define S3C6400_CLKDIV1_LCD_SHIFT      (12)
+#define S3C6400_CLKDIV1_MMC2_MASK      (0xf << 8)
+#define S3C6400_CLKDIV1_MMC2_SHIFT     (8)
+#define S3C6400_CLKDIV1_MMC1_MASK      (0xf << 4)
+#define S3C6400_CLKDIV1_MMC1_SHIFT     (4)
+#define S3C6400_CLKDIV1_MMC0_MASK      (0xf << 0)
+#define S3C6400_CLKDIV1_MMC0_SHIFT     (0)
+
+/* CLKDIV2 */
+#define S3C6410_CLKDIV2_AUDIO2_MASK    (0xf << 24)
+#define S3C6410_CLKDIV2_AUDIO2_SHIFT   (24)
+#define S3C6400_CLKDIV2_IRDA_MASK      (0xf << 20)
+#define S3C6400_CLKDIV2_IRDA_SHIFT     (20)
+#define S3C6400_CLKDIV2_UART_MASK      (0xf << 16)
+#define S3C6400_CLKDIV2_UART_SHIFT     (16)
+#define S3C6400_CLKDIV2_AUDIO1_MASK    (0xf << 12)
+#define S3C6400_CLKDIV2_AUDIO1_SHIFT   (12)
+#define S3C6400_CLKDIV2_AUDIO0_MASK    (0xf << 8)
+#define S3C6400_CLKDIV2_AUDIO0_SHIFT   (8)
+#define S3C6400_CLKDIV2_SPI1_MASK      (0xf << 4)
+#define S3C6400_CLKDIV2_SPI1_SHIFT     (4)
+#define S3C6400_CLKDIV2_SPI0_MASK      (0xf << 0)
+#define S3C6400_CLKDIV2_SPI0_SHIFT     (0)
+
+/* HCLK GATE Registers */
+#define S3C_CLKCON_HCLK_BUS    (1<<30)
+#define S3C_CLKCON_HCLK_SECUR  (1<<29)
+#define S3C_CLKCON_HCLK_SDMA1  (1<<28)
+#define S3C_CLKCON_HCLK_SDMA2  (1<<27)
+#define S3C_CLKCON_HCLK_UHOST  (1<<26)
+#define S3C_CLKCON_HCLK_IROM   (1<<25)
+#define S3C_CLKCON_HCLK_DDR1   (1<<24)
+#define S3C_CLKCON_HCLK_DDR0   (1<<23)
+#define S3C_CLKCON_HCLK_MEM1   (1<<22)
+#define S3C_CLKCON_HCLK_MEM0   (1<<21)
+#define S3C_CLKCON_HCLK_USB    (1<<20)
+#define S3C_CLKCON_HCLK_HSMMC2 (1<<19)
+#define S3C_CLKCON_HCLK_HSMMC1 (1<<18)
+#define S3C_CLKCON_HCLK_HSMMC0 (1<<17)
+#define S3C_CLKCON_HCLK_MDP    (1<<16)
+#define S3C_CLKCON_HCLK_DHOST  (1<<15)
+#define S3C_CLKCON_HCLK_IHOST  (1<<14)
+#define S3C_CLKCON_HCLK_DMA1   (1<<13)
+#define S3C_CLKCON_HCLK_DMA0   (1<<12)
+#define S3C_CLKCON_HCLK_JPEG   (1<<11)
+#define S3C_CLKCON_HCLK_CAMIF  (1<<10)
+#define S3C_CLKCON_HCLK_SCALER (1<<9)
+#define S3C_CLKCON_HCLK_2D     (1<<8)
+#define S3C_CLKCON_HCLK_TV     (1<<7)
+#define S3C_CLKCON_HCLK_POST0  (1<<5)
+#define S3C_CLKCON_HCLK_ROT    (1<<4)
+#define S3C_CLKCON_HCLK_LCD    (1<<3)
+#define S3C_CLKCON_HCLK_TZIC   (1<<2)
+#define S3C_CLKCON_HCLK_INTC   (1<<1)
+#define S3C_CLKCON_HCLK_MFC    (1<<0)
+
+/* PCLK GATE Registers */
+#define S3C6410_CLKCON_PCLK_I2C1       (1<<27)
+#define S3C6410_CLKCON_PCLK_IIS2       (1<<26)
+#define S3C_CLKCON_PCLK_SKEY           (1<<24)
+#define S3C_CLKCON_PCLK_CHIPID         (1<<23)
+#define S3C_CLKCON_PCLK_SPI1           (1<<22)
+#define S3C_CLKCON_PCLK_SPI0           (1<<21)
+#define S3C_CLKCON_PCLK_HSIRX          (1<<20)
+#define S3C_CLKCON_PCLK_HSITX          (1<<19)
+#define S3C_CLKCON_PCLK_GPIO           (1<<18)
+#define S3C_CLKCON_PCLK_IIC            (1<<17)
+#define S3C_CLKCON_PCLK_IIS1           (1<<16)
+#define S3C_CLKCON_PCLK_IIS0           (1<<15)
+#define S3C_CLKCON_PCLK_AC97           (1<<14)
+#define S3C_CLKCON_PCLK_TZPC           (1<<13)
+#define S3C_CLKCON_PCLK_TSADC          (1<<12)
+#define S3C_CLKCON_PCLK_KEYPAD         (1<<11)
+#define S3C_CLKCON_PCLK_IRDA           (1<<10)
+#define S3C_CLKCON_PCLK_PCM1           (1<<9)
+#define S3C_CLKCON_PCLK_PCM0           (1<<8)
+#define S3C_CLKCON_PCLK_PWM            (1<<7)
+#define S3C_CLKCON_PCLK_RTC            (1<<6)
+#define S3C_CLKCON_PCLK_WDT            (1<<5)
+#define S3C_CLKCON_PCLK_UART3          (1<<4)
+#define S3C_CLKCON_PCLK_UART2          (1<<3)
+#define S3C_CLKCON_PCLK_UART1          (1<<2)
+#define S3C_CLKCON_PCLK_UART0          (1<<1)
+#define S3C_CLKCON_PCLK_MFC            (1<<0)
+
+/* SCLK GATE Registers */
+#define S3C_CLKCON_SCLK_UHOST          (1<<30)
+#define S3C_CLKCON_SCLK_MMC2_48                (1<<29)
+#define S3C_CLKCON_SCLK_MMC1_48                (1<<28)
+#define S3C_CLKCON_SCLK_MMC0_48                (1<<27)
+#define S3C_CLKCON_SCLK_MMC2           (1<<26)
+#define S3C_CLKCON_SCLK_MMC1           (1<<25)
+#define S3C_CLKCON_SCLK_MMC0           (1<<24)
+#define S3C_CLKCON_SCLK_SPI1_48        (1<<23)
+#define S3C_CLKCON_SCLK_SPI0_48        (1<<22)
+#define S3C_CLKCON_SCLK_SPI1           (1<<21)
+#define S3C_CLKCON_SCLK_SPI0           (1<<20)
+#define S3C_CLKCON_SCLK_DAC27          (1<<19)
+#define S3C_CLKCON_SCLK_TV27           (1<<18)
+#define S3C_CLKCON_SCLK_SCALER27       (1<<17)
+#define S3C_CLKCON_SCLK_SCALER         (1<<16)
+#define S3C_CLKCON_SCLK_LCD27          (1<<15)
+#define S3C_CLKCON_SCLK_LCD            (1<<14)
+#define S3C6400_CLKCON_SCLK_POST1_27   (1<<13)
+#define S3C6410_CLKCON_FIMC            (1<<13)
+#define S3C_CLKCON_SCLK_POST0_27       (1<<12)
+#define S3C6400_CLKCON_SCLK_POST1      (1<<11)
+#define S3C6410_CLKCON_SCLK_AUDIO2     (1<<11)
+#define S3C_CLKCON_SCLK_POST0          (1<<10)
+#define S3C_CLKCON_SCLK_AUDIO1         (1<<9)
+#define S3C_CLKCON_SCLK_AUDIO0         (1<<8)
+#define S3C_CLKCON_SCLK_SECUR          (1<<7)
+#define S3C_CLKCON_SCLK_IRDA           (1<<6)
+#define S3C_CLKCON_SCLK_UART           (1<<5)
+#define S3C_CLKCON_SCLK_ONENAND        (1<<4)
+#define S3C_CLKCON_SCLK_MFC            (1<<3)
+#define S3C_CLKCON_SCLK_CAM            (1<<2)
+#define S3C_CLKCON_SCLK_JPEG           (1<<1)
+
+/* CLKSRC */
+
+#define S3C6400_CLKSRC_APLL_MOUT       (1 << 0)
+#define S3C6400_CLKSRC_MPLL_MOUT       (1 << 1)
+#define S3C6400_CLKSRC_EPLL_MOUT       (1 << 2)
+#define S3C6400_CLKSRC_APLL_MOUT_SHIFT (0)
+#define S3C6400_CLKSRC_MPLL_MOUT_SHIFT (1)
+#define S3C6400_CLKSRC_EPLL_MOUT_SHIFT (2)
+#define S3C6400_CLKSRC_MFC             (1 << 4)
+
+#define S3C6410_CLKSRC_TV27_MASK       (0x1 << 31)
+#define S3C6410_CLKSRC_TV27_SHIFT      (31)
+#define S3C6410_CLKSRC_DAC27_MASK      (0x1 << 30)
+#define S3C6410_CLKSRC_DAC27_SHIFT     (30)
+#define S3C6400_CLKSRC_SCALER_MASK     (0x3 << 28)
+#define S3C6400_CLKSRC_SCALER_SHIFT    (28)
+#define S3C6400_CLKSRC_LCD_MASK                (0x3 << 26)
+#define S3C6400_CLKSRC_LCD_SHIFT       (26)
+#define S3C6400_CLKSRC_IRDA_MASK       (0x3 << 24)
+#define S3C6400_CLKSRC_IRDA_SHIFT      (24)
+#define S3C6400_CLKSRC_MMC2_MASK       (0x3 << 22)
+#define S3C6400_CLKSRC_MMC2_SHIFT      (22)
+#define S3C6400_CLKSRC_MMC1_MASK       (0x3 << 20)
+#define S3C6400_CLKSRC_MMC1_SHIFT      (20)
+#define S3C6400_CLKSRC_MMC0_MASK       (0x3 << 18)
+#define S3C6400_CLKSRC_MMC0_SHIFT      (18)
+#define S3C6400_CLKSRC_SPI1_MASK       (0x3 << 16)
+#define S3C6400_CLKSRC_SPI1_SHIFT      (16)
+#define S3C6400_CLKSRC_SPI0_MASK       (0x3 << 14)
+#define S3C6400_CLKSRC_SPI0_SHIFT      (14)
+#define S3C6400_CLKSRC_UART_MASK       (0x1 << 13)
+#define S3C6400_CLKSRC_UART_SHIFT      (13)
+#define S3C6400_CLKSRC_AUDIO1_MASK     (0x7 << 10)
+#define S3C6400_CLKSRC_AUDIO1_SHIFT    (10)
+#define S3C6400_CLKSRC_AUDIO0_MASK     (0x7 << 7)
+#define S3C6400_CLKSRC_AUDIO0_SHIFT    (7)
+#define S3C6400_CLKSRC_UHOST_MASK      (0x3 << 5)
+#define S3C6400_CLKSRC_UHOST_SHIFT     (5)
+
+
+#endif /* _PLAT_REGS_CLOCK_H */
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-gpio.h b/arch/arm/plat-s3c64xx/include/plat/regs-gpio.h
new file mode 100644 (file)
index 0000000..75b873d
--- /dev/null
@@ -0,0 +1,35 @@
+/* linux/arch/arm/plat-s3c64xx/include/mach/regs-gpio.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - GPIO register definitions
+ */
+
+#ifndef __ASM_PLAT_S3C64XX_REGS_GPIO_H
+#define __ASM_PLAT_S3C64XX_REGS_GPIO_H __FILE__
+
+/* Base addresses for each of the banks */
+
+#define S3C64XX_GPA_BASE       (S3C64XX_VA_GPIO + 0x0000)
+#define S3C64XX_GPB_BASE       (S3C64XX_VA_GPIO + 0x0020)
+#define S3C64XX_GPC_BASE       (S3C64XX_VA_GPIO + 0x0040)
+#define S3C64XX_GPD_BASE       (S3C64XX_VA_GPIO + 0x0060)
+#define S3C64XX_GPE_BASE       (S3C64XX_VA_GPIO + 0x0080)
+#define S3C64XX_GPF_BASE       (S3C64XX_VA_GPIO + 0x00A0)
+#define S3C64XX_GPG_BASE       (S3C64XX_VA_GPIO + 0x00C0)
+#define S3C64XX_GPH_BASE       (S3C64XX_VA_GPIO + 0x00E0)
+#define S3C64XX_GPI_BASE       (S3C64XX_VA_GPIO + 0x0100)
+#define S3C64XX_GPJ_BASE       (S3C64XX_VA_GPIO + 0x0120)
+#define S3C64XX_GPK_BASE       (S3C64XX_VA_GPIO + 0x0800)
+#define S3C64XX_GPL_BASE       (S3C64XX_VA_GPIO + 0x0810)
+#define S3C64XX_GPM_BASE       (S3C64XX_VA_GPIO + 0x0820)
+#define S3C64XX_GPN_BASE       (S3C64XX_VA_GPIO + 0x0830)
+#define S3C64XX_GPO_BASE       (S3C64XX_VA_GPIO + 0x0140)
+#define S3C64XX_GPP_BASE       (S3C64XX_VA_GPIO + 0x0160)
+#define S3C64XX_GPQ_BASE       (S3C64XX_VA_GPIO + 0x0180)
+
+#endif /* __ASM_PLAT_S3C64XX_REGS_GPIO_H */
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-sys.h b/arch/arm/plat-s3c64xx/include/plat/regs-sys.h
new file mode 100644 (file)
index 0000000..d8ed829
--- /dev/null
@@ -0,0 +1,24 @@
+/* arch/arm/plat-s3c64xx/include/plat/regs-sys.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX system register definitions
+ *
+ * This program is free software; you can 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 __PLAT_REGS_SYS_H
+#define __PLAT_REGS_SYS_H __FILE__
+
+#define S3C_SYSREG(x)          (S3C_VA_SYS + (x))
+
+#define S3C64XX_OTHERS         S3C_SYSREG(0x900)
+
+#define S3C64XX_OTHERS_USBMASK (1 << 16)
+
+#endif /* _PLAT_REGS_SYS_H */
diff --git a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h
new file mode 100644 (file)
index 0000000..571eaa2
--- /dev/null
@@ -0,0 +1,35 @@
+/* arch/arm/plat-s3c64xx/include/plat/s3c6400.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Header file for s3c6400 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* Common init code for S3C6400 related SoCs */
+
+extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+extern void s3c6400_register_clocks(void);
+extern void s3c6400_setup_clocks(void);
+
+#ifdef CONFIG_CPU_S3C6400
+
+extern  int s3c6400_init(void);
+extern void s3c6400_map_io(void);
+extern void s3c6400_init_clocks(int xtal);
+
+#define s3c6400_init_uarts s3c6400_common_init_uarts
+
+#else
+#define s3c6400_init_clocks NULL
+#define s3c6400_init_uarts NULL
+#define s3c6400_map_io NULL
+#define s3c6400_init NULL
+#endif
+
diff --git a/arch/arm/plat-s3c64xx/include/plat/s3c6410.h b/arch/arm/plat-s3c64xx/include/plat/s3c6410.h
new file mode 100644 (file)
index 0000000..50dcdd6
--- /dev/null
@@ -0,0 +1,29 @@
+/* arch/arm/plat-s3c64xx/include/plat/s3c6410.h
+ *
+ * Copyright 2008 Openmoko,  Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Header file for s3c6410 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifdef CONFIG_CPU_S3C6410
+
+extern  int s3c6410_init(void);
+extern void s3c6410_init_irq(void);
+extern void s3c6410_map_io(void);
+extern void s3c6410_init_clocks(int xtal);
+
+#define s3c6410_init_uarts s3c6400_common_init_uarts
+
+#else
+#define s3c6410_init_clocks NULL
+#define s3c6410_init_uarts NULL
+#define s3c6410_map_io NULL
+#define s3c6410_init NULL
+#endif
diff --git a/arch/arm/plat-s3c64xx/irq-eint.c b/arch/arm/plat-s3c64xx/irq-eint.c
new file mode 100644 (file)
index 0000000..1f7cc00
--- /dev/null
@@ -0,0 +1,202 @@
+/* arch/arm/plat-s3c64xx/irq-eint.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Interrupt handling for IRQ_EINT(x)
+ *
+ * This program is free software; you can 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/hardware/vic.h>
+
+#include <plat/regs-irqtype.h>
+
+#include <mach/map.h>
+#include <plat/cpu.h>
+
+/* GPIO is 0x7F008xxx, */
+#define S3C64XX_GPIOREG(x)     (S3C64XX_VA_GPIO + (x))
+
+#define S3C64XX_EINT0CON0      S3C64XX_GPIOREG(0x900)
+#define S3C64XX_EINT0CON1      S3C64XX_GPIOREG(0x904)
+#define S3C64XX_EINT0FLTCON0   S3C64XX_GPIOREG(0x910)
+#define S3C64XX_EINT0FLTCON1   S3C64XX_GPIOREG(0x914)
+#define S3C64XX_EINT0FLTCON2   S3C64XX_GPIOREG(0x918)
+#define S3C64XX_EINT0FLTCON3   S3C64XX_GPIOREG(0x91C)
+
+#define S3C64XX_EINT0MASK      S3C64XX_GPIOREG(0x920)
+#define S3C64XX_EINT0PEND      S3C64XX_GPIOREG(0x924)
+
+
+#define eint_offset(irq)       ((irq) - IRQ_EINT(0))
+#define eint_irq_to_bit(irq)   (1 << eint_offset(irq))
+
+static inline void s3c_irq_eint_mask(unsigned int irq)
+{
+       u32 mask;
+
+       mask = __raw_readl(S3C64XX_EINT0MASK);
+       mask |= eint_irq_to_bit(irq);
+       __raw_writel(mask, S3C64XX_EINT0MASK);
+}
+
+static void s3c_irq_eint_unmask(unsigned int irq)
+{
+       u32 mask;
+
+       mask = __raw_readl(S3C64XX_EINT0MASK);
+       mask |= eint_irq_to_bit(irq);
+       __raw_writel(mask, S3C64XX_EINT0MASK);
+}
+
+static inline void s3c_irq_eint_ack(unsigned int irq)
+{
+       __raw_writel(eint_irq_to_bit(irq), S3C64XX_EINT0PEND);
+}
+
+static void s3c_irq_eint_maskack(unsigned int irq)
+{
+       /* compiler should in-line these */
+       s3c_irq_eint_mask(irq);
+       s3c_irq_eint_ack(irq);
+}
+
+static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type)
+{
+       int offs = eint_offset(irq);
+       int shift;
+       u32 ctrl, mask;
+       u32 newvalue = 0;
+       void __iomem *reg;
+
+       if (offs > 27)
+               return -EINVAL;
+
+       if (offs <= 15)
+               reg = S3C64XX_EINT0CON0;
+       else
+               reg = S3C64XX_EINT0CON1;
+
+       switch (type) {
+       case IRQ_TYPE_NONE:
+               printk(KERN_WARNING "No edge setting!\n");
+               break;
+
+       case IRQ_TYPE_EDGE_RISING:
+               newvalue = S3C2410_EXTINT_RISEEDGE;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               newvalue = S3C2410_EXTINT_FALLEDGE;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               newvalue = S3C2410_EXTINT_BOTHEDGE;
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               newvalue = S3C2410_EXTINT_LOWLEV;
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               newvalue = S3C2410_EXTINT_HILEV;
+               break;
+
+       default:
+               printk(KERN_ERR "No such irq type %d", type);
+               return -1;
+       }
+
+       shift = (offs / 2) * 4;
+       mask = 0x7 << shift;
+
+       ctrl = __raw_readl(reg);
+       ctrl &= ~mask;
+       ctrl |= newvalue << shift;
+       __raw_writel(ctrl, reg);
+
+       return 0;
+}
+
+static struct irq_chip s3c_irq_eint = {
+       .name           = "s3c-eint",
+       .mask           = s3c_irq_eint_mask,
+       .unmask         = s3c_irq_eint_unmask,
+       .mask_ack       = s3c_irq_eint_maskack,
+       .ack            = s3c_irq_eint_ack,
+       .set_type       = s3c_irq_eint_set_type,
+};
+
+/* s3c_irq_demux_eint
+ *
+ * This function demuxes the IRQ from the group0 external interrupts,
+ * from IRQ_EINT(0) to IRQ_EINT(27). It is designed to be inlined into
+ * the specific handlers s3c_irq_demux_eintX_Y.
+ */
+static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end)
+{
+       u32 status = __raw_readl(S3C64XX_EINT0PEND);
+       u32 mask = __raw_readl(S3C64XX_EINT0MASK);
+       unsigned int irq;
+
+       status &= ~mask;
+       status >>= start;
+       status &= (1 << (end - start + 1)) - 1;
+
+       for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) {
+               if (status & 1)
+                       generic_handle_irq(irq);
+
+               status >>= 1;
+       }
+}
+
+static void s3c_irq_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_eint(0, 3);
+}
+
+static void s3c_irq_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_eint(4, 11);
+}
+
+static void s3c_irq_demux_eint12_19(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_eint(12, 19);
+}
+
+static void s3c_irq_demux_eint20_27(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_eint(20, 27);
+}
+
+int __init s3c64xx_init_irq_eint(void)
+{
+       int irq;
+
+       for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) {
+               set_irq_chip(irq, &s3c_irq_eint);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3);
+       set_irq_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11);
+       set_irq_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19);
+       set_irq_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27);
+
+       return 0;
+}
+
+arch_initcall(s3c64xx_init_irq_eint);
diff --git a/arch/arm/plat-s3c64xx/irq.c b/arch/arm/plat-s3c64xx/irq.c
new file mode 100644 (file)
index 0000000..a94f1d5
--- /dev/null
@@ -0,0 +1,257 @@
+/* arch/arm/plat-s3c64xx/irq.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Interrupt handling
+ *
+ * This program is free software; you can 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/hardware/vic.h>
+
+#include <mach/map.h>
+#include <plat/regs-timer.h>
+#include <plat/cpu.h>
+
+/* Timer interrupt handling */
+
+static void s3c_irq_demux_timer(unsigned int base_irq, unsigned int sub_irq)
+{
+       generic_handle_irq(sub_irq);
+}
+
+static void s3c_irq_demux_timer0(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_timer(irq, IRQ_TIMER0);
+}
+
+static void s3c_irq_demux_timer1(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_timer(irq, IRQ_TIMER1);
+}
+
+static void s3c_irq_demux_timer2(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_timer(irq, IRQ_TIMER2);
+}
+
+static void s3c_irq_demux_timer3(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_timer(irq, IRQ_TIMER3);
+}
+
+static void s3c_irq_demux_timer4(unsigned int irq, struct irq_desc *desc)
+{
+       s3c_irq_demux_timer(irq, IRQ_TIMER4);
+}
+
+/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
+
+static void s3c_irq_timer_mask(unsigned int irq)
+{
+       u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+
+       reg &= 0x1f;  /* mask out pending interrupts */
+       reg &= ~(1 << (irq - IRQ_TIMER0));
+       __raw_writel(reg, S3C64XX_TINT_CSTAT);
+}
+
+static void s3c_irq_timer_unmask(unsigned int irq)
+{
+       u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+
+       reg &= 0x1f;  /* mask out pending interrupts */
+       reg |= 1 << (irq - IRQ_TIMER0);
+       __raw_writel(reg, S3C64XX_TINT_CSTAT);
+}
+
+static void s3c_irq_timer_ack(unsigned int irq)
+{
+       u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
+
+       reg &= 0x1f;
+       reg |= (1 << 5) << (irq - IRQ_TIMER0);
+       __raw_writel(reg, S3C64XX_TINT_CSTAT);
+}
+
+static struct irq_chip s3c_irq_timer = {
+       .name           = "s3c-timer",
+       .mask           = s3c_irq_timer_mask,
+       .unmask         = s3c_irq_timer_unmask,
+       .ack            = s3c_irq_timer_ack,
+};
+
+struct uart_irq {
+       void __iomem    *regs;
+       unsigned int     base_irq;
+       unsigned int     parent_irq;
+};
+
+/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
+ * are consecutive when looking up the interrupt in the demux routines.
+ */
+static struct uart_irq uart_irqs[] = {
+       [0] = {
+               .regs           = S3C_VA_UART0,
+               .base_irq       = IRQ_S3CUART_BASE0,
+               .parent_irq     = IRQ_UART0,
+       },
+       [1] = {
+               .regs           = S3C_VA_UART1,
+               .base_irq       = IRQ_S3CUART_BASE1,
+               .parent_irq     = IRQ_UART1,
+       },
+       [2] = {
+               .regs           = S3C_VA_UART2,
+               .base_irq       = IRQ_S3CUART_BASE2,
+               .parent_irq     = IRQ_UART2,
+       },
+       [3] = {
+               .regs           = S3C_VA_UART3,
+               .base_irq       = IRQ_S3CUART_BASE3,
+               .parent_irq     = IRQ_UART3,
+       },
+};
+
+static inline void __iomem *s3c_irq_uart_base(unsigned int irq)
+{
+       struct uart_irq *uirq = get_irq_chip_data(irq);
+       return uirq->regs;
+}
+
+static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
+{
+       return irq & 3;
+}
+
+/* UART interrupt registers, not worth adding to seperate include header */
+#define S3C64XX_UINTP  0x30
+#define S3C64XX_UINTSP 0x34
+#define S3C64XX_UINTM  0x38
+
+static void s3c_irq_uart_mask(unsigned int irq)
+{
+       void __iomem *regs = s3c_irq_uart_base(irq);
+       unsigned int bit = s3c_irq_uart_bit(irq);
+       u32 reg;
+
+       reg = __raw_readl(regs + S3C64XX_UINTM);
+       reg |= (1 << bit);
+       __raw_writel(reg, regs + S3C64XX_UINTM);
+}
+
+static void s3c_irq_uart_maskack(unsigned int irq)
+{
+       void __iomem *regs = s3c_irq_uart_base(irq);
+       unsigned int bit = s3c_irq_uart_bit(irq);
+       u32 reg;
+
+       reg = __raw_readl(regs + S3C64XX_UINTM);
+       reg |= (1 << bit);
+       __raw_writel(reg, regs + S3C64XX_UINTM);
+       __raw_writel(1 << bit, regs + S3C64XX_UINTP);
+}
+
+static void s3c_irq_uart_unmask(unsigned int irq)
+{
+       void __iomem *regs = s3c_irq_uart_base(irq);
+       unsigned int bit = s3c_irq_uart_bit(irq);
+       u32 reg;
+
+       reg = __raw_readl(regs + S3C64XX_UINTM);
+       reg &= ~(1 << bit);
+       __raw_writel(reg, regs + S3C64XX_UINTM);
+}
+
+static void s3c_irq_uart_ack(unsigned int irq)
+{
+       void __iomem *regs = s3c_irq_uart_base(irq);
+       unsigned int bit = s3c_irq_uart_bit(irq);
+
+       __raw_writel(1 << bit, regs + S3C64XX_UINTP);
+}
+
+static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
+{
+       struct uart_irq *uirq = &uart_irqs[irq - IRQ_UART0];
+       u32 pend = __raw_readl(uirq->regs + S3C64XX_UINTP);
+       int base = uirq->base_irq;
+
+       if (pend & (1 << 0))
+               generic_handle_irq(base);
+       if (pend & (1 << 1))
+               generic_handle_irq(base + 1);
+       if (pend & (1 << 2))
+               generic_handle_irq(base + 2);
+       if (pend & (1 << 3))
+               generic_handle_irq(base + 3);
+}
+
+static struct irq_chip s3c_irq_uart = {
+       .name           = "s3c-uart",
+       .mask           = s3c_irq_uart_mask,
+       .unmask         = s3c_irq_uart_unmask,
+       .mask_ack       = s3c_irq_uart_maskack,
+       .ack            = s3c_irq_uart_ack,
+};
+
+static void __init s3c64xx_uart_irq(struct uart_irq *uirq)
+{
+       void *reg_base = uirq->regs;
+       unsigned int irq;
+       int offs;
+
+       /* mask all interrupts at the start. */
+       __raw_writel(0xf, reg_base + S3C64XX_UINTM);
+
+       for (offs = 0; offs < 3; offs++) {
+               irq = uirq->base_irq + offs;
+
+               set_irq_chip(irq, &s3c_irq_uart);
+               set_irq_chip_data(irq, uirq);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
+}
+
+void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
+{
+       int uart, irq;
+
+       printk(KERN_DEBUG "%s: initialising interrupts\n", __func__);
+
+       /* initialise the pair of VICs */
+       vic_init(S3C_VA_VIC0, S3C_VIC0_BASE, vic0_valid);
+       vic_init(S3C_VA_VIC1, S3C_VIC1_BASE, vic1_valid);
+
+       /* add the timer sub-irqs */
+
+       set_irq_chained_handler(IRQ_TIMER0_VIC, s3c_irq_demux_timer0);
+       set_irq_chained_handler(IRQ_TIMER1_VIC, s3c_irq_demux_timer1);
+       set_irq_chained_handler(IRQ_TIMER2_VIC, s3c_irq_demux_timer2);
+       set_irq_chained_handler(IRQ_TIMER3_VIC, s3c_irq_demux_timer3);
+       set_irq_chained_handler(IRQ_TIMER4_VIC, s3c_irq_demux_timer4);
+
+       for (irq = IRQ_TIMER0; irq <= IRQ_TIMER4; irq++) {
+               set_irq_chip(irq, &s3c_irq_timer);
+               set_irq_handler(irq, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+
+       for (uart = 0; uart < ARRAY_SIZE(uart_irqs); uart++)
+               s3c64xx_uart_irq(&uart_irqs[uart]);
+}
+
+
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
new file mode 100644 (file)
index 0000000..8d9a0ca
--- /dev/null
@@ -0,0 +1,655 @@
+/* linux/arch/arm/plat-s3c64xx/s3c6400-clock.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * S3C6400 based common clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+
+#include <plat/cpu-freq.h>
+
+#include <plat/regs-clock.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+
+/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
+ * ext_xtal_mux for want of an actual name from the manual.
+*/
+
+struct clk clk_ext_xtal_mux = {
+       .name           = "ext_xtal",
+       .id             = -1,
+};
+
+#define clk_fin_apll clk_ext_xtal_mux
+#define clk_fin_mpll clk_ext_xtal_mux
+#define clk_fin_epll clk_ext_xtal_mux
+
+#define clk_fout_mpll  clk_mpll
+
+struct clk_sources {
+       unsigned int    nr_sources;
+       struct clk      **sources;
+};
+
+struct clksrc_clk {
+       struct clk              clk;
+       unsigned int            mask;
+       unsigned int            shift;
+
+       struct clk_sources      *sources;
+
+       unsigned int            divider_shift;
+       void __iomem            *reg_divider;
+};
+
+struct clk clk_fout_apll = {
+       .name           = "fout_apll",
+       .id             = -1,
+};
+
+static struct clk *clk_src_apll_list[] = {
+       [0] = &clk_fin_apll,
+       [1] = &clk_fout_apll,
+};
+
+static struct clk_sources clk_src_apll = {
+       .sources        = clk_src_apll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_apll_list),
+};
+
+struct clksrc_clk clk_mout_apll = {
+       .clk    = {
+               .name           = "mout_apll",
+               .id             = -1,
+       },
+       .shift          = S3C6400_CLKSRC_APLL_MOUT_SHIFT,
+       .mask           = S3C6400_CLKSRC_APLL_MOUT,
+       .sources        = &clk_src_apll,
+};
+
+struct clk clk_fout_epll = {
+       .name           = "fout_epll",
+       .id             = -1,
+};
+
+static struct clk *clk_src_epll_list[] = {
+       [0] = &clk_fin_epll,
+       [1] = &clk_fout_epll,
+};
+
+static struct clk_sources clk_src_epll = {
+       .sources        = clk_src_epll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_epll_list),
+};
+
+struct clksrc_clk clk_mout_epll = {
+       .clk    = {
+               .name           = "mout_epll",
+               .id             = -1,
+       },
+       .shift          = S3C6400_CLKSRC_EPLL_MOUT_SHIFT,
+       .mask           = S3C6400_CLKSRC_EPLL_MOUT,
+       .sources        = &clk_src_epll,
+};
+
+static struct clk *clk_src_mpll_list[] = {
+       [0] = &clk_fin_mpll,
+       [1] = &clk_fout_mpll,
+};
+
+static struct clk_sources clk_src_mpll = {
+       .sources        = clk_src_mpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_mpll_list),
+};
+
+struct clksrc_clk clk_mout_mpll = {
+       .clk = {
+               .name           = "mout_mpll",
+               .id             = -1,
+       },
+       .shift          = S3C6400_CLKSRC_MPLL_MOUT_SHIFT,
+       .mask           = S3C6400_CLKSRC_MPLL_MOUT,
+       .sources        = &clk_src_mpll,
+};
+
+static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
+{
+       unsigned long rate = clk_get_rate(clk->parent);
+
+       printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
+
+       if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK)
+               rate /= 2;
+
+       return rate;
+}
+
+struct clk clk_dout_mpll = {
+       .name           = "dout_mpll",
+       .id             = -1,
+       .parent         = &clk_mout_mpll.clk,
+       .get_rate       = s3c64xx_clk_doutmpll_get_rate,
+};
+
+static struct clk *clkset_spi_mmc_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_fin_epll,
+       &clk_27m,
+};
+
+static struct clk_sources clkset_spi_mmc = {
+       .sources        = clkset_spi_mmc_list,
+       .nr_sources     = ARRAY_SIZE(clkset_spi_mmc_list),
+};
+
+static struct clk *clkset_irda_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       NULL,
+       &clk_27m,
+};
+
+static struct clk_sources clkset_irda = {
+       .sources        = clkset_irda_list,
+       .nr_sources     = ARRAY_SIZE(clkset_irda_list),
+};
+
+static struct clk *clkset_uart_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       NULL,
+       NULL
+};
+
+static struct clk_sources clkset_uart = {
+       .sources        = clkset_uart_list,
+       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
+};
+
+static struct clk *clkset_uhost_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll,
+       &clk_fin_epll,
+       &clk_48m,
+};
+
+static struct clk_sources clkset_uhost = {
+       .sources        = clkset_uhost_list,
+       .nr_sources     = ARRAY_SIZE(clkset_uhost_list),
+};
+
+
+/* The peripheral clocks are all controlled via clocksource followed
+ * by an optional divider and gate stage. We currently roll this into
+ * one clock which hides the intermediate clock from the mux.
+ *
+ * Note, the JPEG clock can only be an even divider...
+ *
+ * The scaler and LCD clocks depend on the S3C64XX version, and also
+ * have a common parent divisor so are not included here.
+ */
+
+static inline struct clksrc_clk *to_clksrc(struct clk *clk)
+{
+       return container_of(clk, struct clksrc_clk, clk);
+}
+
+static unsigned long s3c64xx_getrate_clksrc(struct clk *clk)
+{
+       struct clksrc_clk *sclk = to_clksrc(clk);
+       unsigned long rate = clk_get_rate(clk->parent);
+       u32 clkdiv = __raw_readl(sclk->reg_divider);
+
+       clkdiv >>= sclk->divider_shift;
+       clkdiv &= 0xf;
+       clkdiv++;
+
+       rate /= clkdiv;
+       return rate;
+}
+
+static int s3c64xx_setrate_clksrc(struct clk *clk, unsigned long rate)
+{
+       struct clksrc_clk *sclk = to_clksrc(clk);
+       void __iomem *reg = sclk->reg_divider;
+       unsigned int div;
+       u32 val;
+
+       rate = clk_round_rate(clk, rate);
+       div = clk_get_rate(clk->parent) / rate;
+
+       val = __raw_readl(reg);
+       val &= ~sclk->mask;
+       val |= (rate - 1) << sclk->shift;
+       __raw_writel(val, reg);
+
+       return 0;
+}
+
+static int s3c64xx_setparent_clksrc(struct clk *clk, struct clk *parent)
+{
+       struct clksrc_clk *sclk = to_clksrc(clk);
+       struct clk_sources *srcs = sclk->sources;
+       u32 clksrc = __raw_readl(S3C_CLK_SRC);
+       int src_nr = -1;
+       int ptr;
+
+       for (ptr = 0; ptr < srcs->nr_sources; ptr++)
+               if (srcs->sources[ptr] == parent) {
+                       src_nr = ptr;
+                       break;
+               }
+
+       if (src_nr >= 0) {
+               clksrc &= ~sclk->mask;
+               clksrc |= src_nr << sclk->shift;
+
+               __raw_writel(clksrc, S3C_CLK_SRC);
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static unsigned long s3c64xx_roundrate_clksrc(struct clk *clk,
+                                             unsigned long rate)
+{
+       unsigned long parent_rate = clk_get_rate(clk->parent);
+       int div;
+
+       if (rate > parent_rate)
+               rate = parent_rate;
+       else {
+               div = rate / parent_rate;
+
+               if (div == 0)
+                       div = 1;
+               if (div > 16)
+                       div = 16;
+
+               rate = parent_rate / div;
+       }
+
+       return rate;
+}
+
+static struct clksrc_clk clk_mmc0 = {
+       .clk    = {
+               .name           = "mmc_bus",
+               .id             = 0,
+               .ctrlbit        = S3C_CLKCON_SCLK_MMC0,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_MMC0_SHIFT,
+       .mask           = S3C6400_CLKSRC_MMC0_MASK,
+       .sources        = &clkset_spi_mmc,
+       .divider_shift  = S3C6400_CLKDIV1_MMC0_SHIFT,
+       .reg_divider    = S3C_CLK_DIV1,
+};
+
+static struct clksrc_clk clk_mmc1 = {
+       .clk    = {
+               .name           = "mmc_bus",
+               .id             = 1,
+               .ctrlbit        = S3C_CLKCON_SCLK_MMC1,
+               .enable         = s3c64xx_sclk_ctrl,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_MMC1_SHIFT,
+       .mask           = S3C6400_CLKSRC_MMC1_MASK,
+       .sources        = &clkset_spi_mmc,
+       .divider_shift  = S3C6400_CLKDIV1_MMC1_SHIFT,
+       .reg_divider    = S3C_CLK_DIV1,
+};
+
+static struct clksrc_clk clk_mmc2 = {
+       .clk    = {
+               .name           = "mmc_bus",
+               .id             = 2,
+               .ctrlbit        = S3C_CLKCON_SCLK_MMC2,
+               .enable         = s3c64xx_sclk_ctrl,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_MMC2_SHIFT,
+       .mask           = S3C6400_CLKSRC_MMC2_MASK,
+       .sources        = &clkset_spi_mmc,
+       .divider_shift  = S3C6400_CLKDIV1_MMC2_SHIFT,
+       .reg_divider    = S3C_CLK_DIV1,
+};
+
+static struct clksrc_clk clk_usbhost = {
+       .clk    = {
+               .name           = "usb-host-bus",
+               .id             = -1,
+               .ctrlbit        = S3C_CLKCON_SCLK_UHOST,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_UHOST_SHIFT,
+       .mask           = S3C6400_CLKSRC_UHOST_MASK,
+       .sources        = &clkset_uhost,
+       .divider_shift  = S3C6400_CLKDIV1_UHOST_SHIFT,
+       .reg_divider    = S3C_CLK_DIV1,
+};
+
+static struct clksrc_clk clk_uart_uclk1 = {
+       .clk    = {
+               .name           = "uclk1",
+               .id             = -1,
+               .ctrlbit        = S3C_CLKCON_SCLK_UART,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_UART_SHIFT,
+       .mask           = S3C6400_CLKSRC_UART_MASK,
+       .sources        = &clkset_uart,
+       .divider_shift  = S3C6400_CLKDIV2_UART_SHIFT,
+       .reg_divider    = S3C_CLK_DIV2,
+};
+
+/* Where does UCLK0 come from? */
+
+static struct clksrc_clk clk_spi0 = {
+       .clk    = {
+               .name           = "spi-bus",
+               .id             = 0,
+               .ctrlbit        = S3C_CLKCON_SCLK_SPI0,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_SPI0_SHIFT,
+       .mask           = S3C6400_CLKSRC_SPI0_MASK,
+       .sources        = &clkset_spi_mmc,
+       .divider_shift  = S3C6400_CLKDIV2_SPI0_SHIFT,
+       .reg_divider    = S3C_CLK_DIV2,
+};
+
+static struct clksrc_clk clk_spi1 = {
+       .clk    = {
+               .name           = "spi-bus",
+               .id             = 1,
+               .ctrlbit        = S3C_CLKCON_SCLK_SPI1,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_SPI1_SHIFT,
+       .mask           = S3C6400_CLKSRC_SPI1_MASK,
+       .sources        = &clkset_spi_mmc,
+       .divider_shift  = S3C6400_CLKDIV2_SPI1_SHIFT,
+       .reg_divider    = S3C_CLK_DIV2,
+};
+
+static struct clk clk_iis_cd0 = {
+       .name           = "iis_cdclk0",
+       .id             = -1,
+};
+
+static struct clk clk_iis_cd1 = {
+       .name           = "iis_cdclk1",
+       .id             = -1,
+};
+
+static struct clk clk_pcm_cd = {
+       .name           = "pcm_cdclk",
+       .id             = -1,
+};
+
+static struct clk *clkset_audio0_list[] = {
+       [0] = &clk_mout_epll.clk,
+       [1] = &clk_dout_mpll,
+       [2] = &clk_fin_epll,
+       [3] = &clk_iis_cd0,
+       [4] = &clk_pcm_cd,
+};
+
+static struct clk_sources clkset_audio0 = {
+       .sources        = clkset_audio0_list,
+       .nr_sources     = ARRAY_SIZE(clkset_audio0_list),
+};
+
+static struct clksrc_clk clk_audio0 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .id             = 0,
+               .ctrlbit        = S3C_CLKCON_SCLK_AUDIO0,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_AUDIO0_SHIFT,
+       .mask           = S3C6400_CLKSRC_AUDIO0_MASK,
+       .sources        = &clkset_audio0,
+       .divider_shift  = S3C6400_CLKDIV2_AUDIO0_SHIFT,
+       .reg_divider    = S3C_CLK_DIV2,
+};
+
+static struct clk *clkset_audio1_list[] = {
+       [0] = &clk_mout_epll.clk,
+       [1] = &clk_dout_mpll,
+       [2] = &clk_fin_epll,
+       [3] = &clk_iis_cd1,
+       [4] = &clk_pcm_cd,
+};
+
+static struct clk_sources clkset_audio1 = {
+       .sources        = clkset_audio1_list,
+       .nr_sources     = ARRAY_SIZE(clkset_audio1_list),
+};
+
+static struct clksrc_clk clk_audio1 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .id             = 1,
+               .ctrlbit        = S3C_CLKCON_SCLK_AUDIO1,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_AUDIO1_SHIFT,
+       .mask           = S3C6400_CLKSRC_AUDIO1_MASK,
+       .sources        = &clkset_audio1,
+       .divider_shift  = S3C6400_CLKDIV2_AUDIO1_SHIFT,
+       .reg_divider    = S3C_CLK_DIV2,
+};
+
+static struct clksrc_clk clk_irda = {
+       .clk    = {
+               .name           = "irda-bus",
+               .id             = 0,
+               .ctrlbit        = S3C_CLKCON_SCLK_IRDA,
+               .enable         = s3c64xx_sclk_ctrl,
+               .set_parent     = s3c64xx_setparent_clksrc,
+               .get_rate       = s3c64xx_getrate_clksrc,
+               .set_rate       = s3c64xx_setrate_clksrc,
+               .round_rate     = s3c64xx_roundrate_clksrc,
+       },
+       .shift          = S3C6400_CLKSRC_IRDA_SHIFT,
+       .mask           = S3C6400_CLKSRC_IRDA_MASK,
+       .sources        = &clkset_irda,
+       .divider_shift  = S3C6400_CLKDIV2_IRDA_SHIFT,
+       .reg_divider    = S3C_CLK_DIV2,
+};
+
+/* Clock initialisation code */
+
+static struct clksrc_clk *init_parents[] = {
+       &clk_mout_apll,
+       &clk_mout_epll,
+       &clk_mout_mpll,
+       &clk_mmc0,
+       &clk_mmc1,
+       &clk_mmc2,
+       &clk_usbhost,
+       &clk_uart_uclk1,
+       &clk_spi0,
+       &clk_spi1,
+       &clk_audio0,
+       &clk_audio1,
+       &clk_irda,
+};
+
+static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
+{
+       struct clk_sources *srcs = clk->sources;
+       u32 clksrc = __raw_readl(S3C_CLK_SRC);
+
+       clksrc &= clk->mask;
+       clksrc >>= clk->shift;
+
+       if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
+               printk(KERN_ERR "%s: bad source %d\n",
+                      clk->clk.name, clksrc);
+               return;
+       }
+
+       clk->clk.parent = srcs->sources[clksrc];
+
+       printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
+              clk->clk.name, clk->clk.parent->name, clksrc,
+              clk_get_rate(&clk->clk));
+}
+
+#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
+
+void __init_or_cpufreq s3c6400_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+       unsigned long xtal;
+       unsigned long fclk;
+       unsigned long hclk;
+       unsigned long hclk2;
+       unsigned long pclk;
+       unsigned long epll;
+       unsigned long apll;
+       unsigned long mpll;
+       unsigned int ptr;
+       u32 clkdiv0;
+
+       printk(KERN_DEBUG "%s: registering clocks\n", __func__);
+
+       clkdiv0 = __raw_readl(S3C_CLK_DIV0);
+       printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
+
+       xtal_clk = clk_get(NULL, "xtal");
+       BUG_ON(IS_ERR(xtal_clk));
+
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
+
+       epll = s3c6400_get_epll(xtal);
+       mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
+       apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
+
+       fclk = mpll;
+
+       printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
+              apll, mpll, epll);
+
+       hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
+       hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
+       pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
+
+       printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
+              hclk2, hclk, pclk);
+
+       clk_fout_mpll.rate = mpll;
+       clk_fout_epll.rate = epll;
+       clk_fout_apll.rate = apll;
+
+       clk_h.rate = hclk;
+       clk_p.rate = pclk;
+       clk_f.rate = fclk;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
+               s3c6400_set_clksrc(init_parents[ptr]);
+}
+
+static struct clk *clks[] __initdata = {
+       &clk_ext_xtal_mux,
+       &clk_iis_cd0,
+       &clk_iis_cd1,
+       &clk_pcm_cd,
+       &clk_mout_epll.clk,
+       &clk_fout_epll,
+       &clk_mout_mpll.clk,
+       &clk_dout_mpll,
+       &clk_mmc0.clk,
+       &clk_mmc1.clk,
+       &clk_mmc2.clk,
+       &clk_usbhost.clk,
+       &clk_uart_uclk1.clk,
+       &clk_spi0.clk,
+       &clk_spi1.clk,
+       &clk_audio0.clk,
+       &clk_audio1.clk,
+       &clk_irda.clk,
+};
+
+void __init s3c6400_register_clocks(void)
+{
+       struct clk *clkp;
+       int ret;
+       int ptr;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
+               clkp = clks[ptr];
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+       }
+
+       clk_mpll.parent = &clk_mout_mpll.clk;
+       clk_epll.parent = &clk_mout_epll.clk;
+}
diff --git a/arch/arm/plat-s3c64xx/s3c6400-init.c b/arch/arm/plat-s3c64xx/s3c6400-init.c
new file mode 100644 (file)
index 0000000..6c28f39
--- /dev/null
@@ -0,0 +1,29 @@
+/* linux/arch/arm/plat-s3c64xx/s3c6400-init.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C6400 - CPU initialisation (common with other S3C64XX chips)
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/init.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/s3c6400.h>
+#include <plat/s3c6410.h>
+
+/* uart registration process */
+
+void __init s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s3c24xx_init_uartdevs("s3c6400-uart", s3c64xx_uart_resources, cfg, no);
+}
diff --git a/arch/arm/plat-s3c64xx/setup-fb-24bpp.c b/arch/arm/plat-s3c64xx/setup-fb-24bpp.c
new file mode 100644 (file)
index 0000000..8e28e44
--- /dev/null
@@ -0,0 +1,37 @@
+/* linux/arch/arm/plat-s3c64xx/setup-fb-24bpp.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Base S3C64XX setup information for 24bpp LCD framebuffer
+ *
+ * This program is free software; you can 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/types.h>
+#include <linux/fb.h>
+
+#include <mach/regs-fb.h>
+#include <mach/gpio.h>
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+
+extern void s3c64xx_fb_gpio_setup_24bpp(void)
+{
+       unsigned int gpio;
+
+       for (gpio = S3C64XX_GPI(0); gpio <= S3C64XX_GPI(15); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+
+       for (gpio = S3C64XX_GPJ(0); gpio <= S3C64XX_GPJ(11); gpio++) {
+               s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+       }
+}
diff --git a/arch/arm/plat-s3c64xx/setup-i2c0.c b/arch/arm/plat-s3c64xx/setup-i2c0.c
new file mode 100644 (file)
index 0000000..3644807
--- /dev/null
@@ -0,0 +1,31 @@
+/* linux/arch/arm/plat-s3c64xx/setup-i2c0.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Base S3C64XX I2C bus 0 gpio configuration
+ *
+ * This program is free software; you can 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/types.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <mach/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-bank-b.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c0_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S3C64XX_GPB(5), S3C64XX_GPB5_I2C_SCL0);
+       s3c_gpio_cfgpin(S3C64XX_GPB(6), S3C64XX_GPB6_I2C_SDA0);
+       s3c_gpio_setpull(S3C64XX_GPB(5), S3C_GPIO_PULL_UP);
+       s3c_gpio_setpull(S3C64XX_GPB(6), S3C_GPIO_PULL_UP);
+}
diff --git a/arch/arm/plat-s3c64xx/setup-i2c1.c b/arch/arm/plat-s3c64xx/setup-i2c1.c
new file mode 100644 (file)
index 0000000..bbe229b
--- /dev/null
@@ -0,0 +1,31 @@
+/* linux/arch/arm/plat-s3c64xx/setup-i2c1.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * Base S3C64XX I2C bus 1 gpio configuration
+ *
+ * This program is free software; you can 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/types.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <mach/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-bank-b.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c1_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S3C64XX_GPB(2), S3C64XX_GPB2_I2C_SCL1);
+       s3c_gpio_cfgpin(S3C64XX_GPB(3), S3C64XX_GPB3_I2C_SDA1);
+       s3c_gpio_setpull(S3C64XX_GPB(2), S3C_GPIO_PULL_UP);
+       s3c_gpio_setpull(S3C64XX_GPB(3), S3C_GPIO_PULL_UP);
+}
index 43aa2020f85c9ac200c0db73a8c987e92051b56c..fd23c0e9e69863d5bfdec7ad61ee1a2568e1f820 100644 (file)
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Thu Sep 25 10:10:50 2008
+# Last update: Sun Nov 30 16:39:36 2008
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -1380,7 +1380,7 @@ holon                     MACH_HOLON              HOLON                   1377
 olip8                  MACH_OLIP8              OLIP8                   1378
 ghi270hg               MACH_GHI270HG           GHI270HG                1379
 davinci_dm6467_evm     MACH_DAVINCI_DM6467_EVM DAVINCI_DM6467_EVM      1380
-davinci_dm355_evm      MACH_DAVINCI_DM350_EVM  DAVINCI_DM350_EVM       1381
+davinci_dm355_evm      MACH_DAVINCI_DM355_EVM  DAVINCI_DM355_EVM       1381
 blackriver             MACH_BLACKRIVER         BLACKRIVER              1383
 sandgate_wp            MACH_SANDGATEWP         SANDGATEWP              1384
 cdotbwsg               MACH_CDOTBWSG           CDOTBWSG                1385
@@ -1771,7 +1771,7 @@ axs_ultrax                MACH_AXS_ULTRAX         AXS_ULTRAX              1779
 at572d940deb           MACH_AT572D940DEB       AT572D940DEB            1780
 davinci_da8xx_evm      MACH_DAVINCI_DA8XX_EVM  DAVINCI_DA8XX_EVM       1781
 ep9302                 MACH_EP9302             EP9302                  1782
-at572d940hfeb          MACH_AT572D940HFEB      AT572D940HFEB           1783
+at572d940hfek          MACH_AT572D940HFEB      AT572D940HFEB           1783
 cybook3                        MACH_CYBOOK3            CYBOOK3                 1784
 wdg002                 MACH_WDG002             WDG002                  1785
 sg560adsl              MACH_SG560ADSL          SG560ADSL               1786
@@ -1899,3 +1899,98 @@ rut100                   MACH_RUT100             RUT100                  1908
 asusp535               MACH_ASUSP535           ASUSP535                1909
 htcraphael             MACH_HTCRAPHAEL         HTCRAPHAEL              1910
 sygdg1                 MACH_SYGDG1             SYGDG1                  1911
+sygdg2                 MACH_SYGDG2             SYGDG2                  1912
+seoul                  MACH_SEOUL              SEOUL                   1913
+salerno                        MACH_SALERNO            SALERNO                 1914
+ucn_s3c64xx            MACH_UCN_S3C64XX        UCN_S3C64XX             1915
+msm7201a               MACH_MSM7201A           MSM7201A                1916
+lpr1                   MACH_LPR1               LPR1                    1917
+armadillo500fx         MACH_ARMADILLO500FX     ARMADILLO500FX          1918
+g3evm                  MACH_G3EVM              G3EVM                   1919
+z3_dm355               MACH_Z3_DM355           Z3_DM355                1920
+w90p910evb             MACH_W90P910EVB         W90P910EVB              1921
+w90p920evb             MACH_W90P920EVB         W90P920EVB              1922
+w90p950evb             MACH_W90P950EVB         W90P950EVB              1923
+w90n960evb             MACH_W90N960EVB         W90N960EVB              1924
+camhd                  MACH_CAMHD              CAMHD                   1925
+mvc100                 MACH_MVC100             MVC100                  1926
+electrum_200           MACH_ELECTRUM_200       ELECTRUM_200            1927
+htcjade                        MACH_HTCJADE            HTCJADE                 1928
+memphis                        MACH_MEMPHIS            MEMPHIS                 1929
+imx27sbc               MACH_IMX27SBC           IMX27SBC                1930
+lextar                 MACH_LEXTAR             LEXTAR                  1931
+mv88f6281gtw_ge                MACH_MV88F6281GTW_GE    MV88F6281GTW_GE         1932
+ncp                    MACH_NCP                NCP                     1933
+z32an_series           MACH_Z32AN              Z32AN                   1934
+tmq_capd               MACH_TMQ_CAPD           TMQ_CAPD                1935
+omap3_wl               MACH_OMAP3_WL           OMAP3_WL                1936
+chumby                 MACH_CHUMBY             CHUMBY                  1937
+atsarm9                        MACH_ATSARM9            ATSARM9                 1938
+davinci_dm365_evm      MACH_DAVINCI_DM365_EVM  DAVINCI_DM365_EVM       1939
+bahamas                        MACH_BAHAMAS            BAHAMAS                 1940
+das                    MACH_DAS                DAS                     1941
+minidas                        MACH_MINIDAS            MINIDAS                 1942
+vk1000                 MACH_VK1000             VK1000                  1943
+centro                 MACH_CENTRO             CENTRO                  1944
+ctera_2bay             MACH_CTERA_2BAY         CTERA_2BAY              1945
+edgeconnect            MACH_EDGECONNECT        EDGECONNECT             1946
+nd27000                        MACH_ND27000            ND27000                 1947
+cobra                  MACH_GEMALTO_COBRA      GEMALTO_COBRA           1948
+ingelabs_comet         MACH_INGELABS_COMET     INGELABS_COMET          1949
+pollux_wiz             MACH_POLLUX_WIZ         POLLUX_WIZ              1950
+blackstone             MACH_BLACKSTONE         BLACKSTONE              1951
+topaz                  MACH_TOPAZ              TOPAZ                   1952
+aixle                  MACH_AIXLE              AIXLE                   1953
+mw998                  MACH_MW998              MW998                   1954
+nokia_rx51             MACH_NOKIA_RX51         NOKIA_RX51              1955
+vsc5605ev              MACH_VSC5605EV          VSC5605EV               1956
+nt98700dk              MACH_NT98700DK          NT98700DK               1957
+icontact               MACH_ICONTACT           ICONTACT                1958
+swarco_frcpu           MACH_SWARCO_FRCPU       SWARCO_FRCPU            1959
+swarco_scpu            MACH_SWARCO_SCPU        SWARCO_SCPU             1960
+bbox_p16               MACH_BBOX_P16           BBOX_P16                1961
+bstd                   MACH_BSTD               BSTD                    1962
+sbc2440ii              MACH_SBC2440II          SBC2440II               1963
+pcm034                 MACH_PCM034             PCM034                  1964
+neso                   MACH_NESO               NESO                    1965
+wlnx_9g20              MACH_WLNX_9G20          WLNX_9G20               1966
+omap_zoom2             MACH_OMAP_ZOOM2         OMAP_ZOOM2              1967
+totemnova              MACH_TOTEMNOVA          TOTEMNOVA               1968
+c5000                  MACH_C5000              C5000                   1969
+unipo_at91sam9263      MACH_UNIPO_AT91SAM9263  UNIPO_AT91SAM9263       1970
+ethernut5              MACH_ETHERNUT5          ETHERNUT5               1971
+arm11                  MACH_ARM11              ARM11                   1972
+cpuat9260              MACH_CPUAT9260          CPUAT9260               1973
+cpupxa255              MACH_CPUPXA255          CPUPXA255               1974
+cpuimx27               MACH_CPUIMX27           CPUIMX27                1975
+cheflux                        MACH_CHEFLUX            CHEFLUX                 1976
+eb_cpux9k2             MACH_EB_CPUX9K2         EB_CPUX9K2              1977
+opcotec                        MACH_OPCOTEC            OPCOTEC                 1978
+yt                     MACH_YT                 YT                      1979
+motoq                  MACH_MOTOQ              MOTOQ                   1980
+bsb1                   MACH_BSB1               BSB1                    1981
+acs5k                  MACH_ACS5K              ACS5K                   1982
+milan                  MACH_MILAN              MILAN                   1983
+quartzv2               MACH_QUARTZV2           QUARTZV2                1984
+rsvp                   MACH_RSVP               RSVP                    1985
+rmp200                 MACH_RMP200             RMP200                  1986
+snapper_9260           MACH_SNAPPER_9260       SNAPPER_9260            1987
+dsm320                 MACH_DSM320             DSM320                  1988
+adsgcm                 MACH_ADSGCM             ADSGCM                  1989
+ase2_400               MACH_ASE2_400           ASE2_400                1990
+pizza                  MACH_PIZZA              PIZZA                   1991
+spot_ngpl              MACH_SPOT_NGPL          SPOT_NGPL               1992
+armata                 MACH_ARMATA             ARMATA                  1993
+exeda                  MACH_EXEDA              EXEDA                   1994
+mx31sf005              MACH_MX31SF005          MX31SF005               1995
+f5d8231_4_v2           MACH_F5D8231_4_V2       F5D8231_4_V2            1996
+q2440                  MACH_Q2440              Q2440                   1997
+qq2440                 MACH_QQ2440             QQ2440                  1998
+mini2440               MACH_MINI2440           MINI2440                1999
+colibri300             MACH_COLIBRI300         COLIBRI300              2000
+jades                  MACH_JADES              JADES                   2001
+spark                  MACH_SPARK              SPARK                   2002
+benzina                        MACH_BENZINA            BENZINA                 2003
+blaze                  MACH_BLAZE              BLAZE                   2004
+linkstation_ls_hgl     MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL      2005
+htcvenus               MACH_HTCVENUS           HTCVENUS                2006
index c85860bad585ecfd10d4a316408f8080f7748667..8de86e4feada7f56686abbbfe7b1a1067f50f466 100644 (file)
@@ -377,6 +377,6 @@ struct op {
        u32 flags;
 };
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PM)
 extern void vfp_save_state(void *location, u32 fpexc);
 #endif
index a62dcf7098bad660ee65c22cbcf76a0a24677c05..c92a08bd6a8674d53ecbc6c96b22f77e21584cf8 100644 (file)
@@ -101,9 +101,12 @@ ENTRY(vfp_support_entry)
        VFPFSTMIA r4, r5                @ save the working registers
        VFPFMRX r5, FPSCR               @ current status
        tst     r1, #FPEXC_EX           @ is there additional state to save?
-       VFPFMRX r6, FPINST, NE          @ FPINST (only if FPEXC.EX is set)
-       tstne   r1, #FPEXC_FP2V         @ is there an FPINST2 to read?
-       VFPFMRX r8, FPINST2, NE         @ FPINST2 if needed (and present)
+       beq     1f
+       VFPFMRX r6, FPINST              @ FPINST (only if FPEXC.EX is set)
+       tst     r1, #FPEXC_FP2V         @ is there an FPINST2 to read?
+       beq     1f
+       VFPFMRX r8, FPINST2             @ FPINST2 if needed (and present)
+1:
        stmia   r4, {r1, r5, r6, r8}    @ save FPEXC, FPSCR, FPINST, FPINST2
                                        @ and point r4 at the word at the
                                        @ start of the register dump
@@ -117,9 +120,12 @@ no_old_VFP_process:
                                        @ FPEXC is in a safe state
        ldmia   r10, {r1, r5, r6, r8}   @ load FPEXC, FPSCR, FPINST, FPINST2
        tst     r1, #FPEXC_EX           @ is there additional state to restore?
-       VFPFMXR FPINST, r6, NE          @ restore FPINST (only if FPEXC.EX is set)
-       tstne   r1, #FPEXC_FP2V         @ is there an FPINST2 to write?
-       VFPFMXR FPINST2, r8, NE         @ FPINST2 if needed (and present)
+       beq     1f
+       VFPFMXR FPINST, r6              @ restore FPINST (only if FPEXC.EX is set)
+       tst     r1, #FPEXC_FP2V         @ is there an FPINST2 to write?
+       beq     1f
+       VFPFMXR FPINST2, r8             @ FPINST2 if needed (and present)
+1:
        VFPFMXR FPSCR, r5               @ restore status
 
 check_for_exception:
@@ -166,7 +172,7 @@ process_exception:
                                        @ retry the faulted instruction
 ENDPROC(vfp_support_entry)
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PM)
 ENTRY(vfp_save_state)
        @ Save the current VFP state
        @ r0 - save location
@@ -175,9 +181,12 @@ ENTRY(vfp_save_state)
        VFPFSTMIA r0, r2                @ save the working registers
        VFPFMRX r2, FPSCR               @ current status
        tst     r1, #FPEXC_EX           @ is there additional state to save?
-       VFPFMRX r3, FPINST, NE          @ FPINST (only if FPEXC.EX is set)
-       tstne   r1, #FPEXC_FP2V         @ is there an FPINST2 to read?
-       VFPFMRX r12, FPINST2, NE        @ FPINST2 if needed (and present)
+       beq     1f
+       VFPFMRX r3, FPINST              @ FPINST (only if FPEXC.EX is set)
+       tst     r1, #FPEXC_FP2V         @ is there an FPINST2 to read?
+       beq     1f
+       VFPFMRX r12, FPINST2            @ FPINST2 if needed (and present)
+1:
        stmia   r0, {r1, r2, r3, r12}   @ save FPEXC, FPSCR, FPINST, FPINST2
        mov     pc, lr
 ENDPROC(vfp_save_state)
index c0d2c9bb952b67133b66a0f81a6a734f737a29f0..9f476a1be2cace8280a4f7dfad0d3fcf8f92cfc0 100644 (file)
@@ -322,6 +322,61 @@ static void vfp_enable(void *unused)
        set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
 }
 
+#ifdef CONFIG_PM
+#include <linux/sysdev.h>
+
+static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+       struct thread_info *ti = current_thread_info();
+       u32 fpexc = fmrx(FPEXC);
+
+       /* if vfp is on, then save state for resumption */
+       if (fpexc & FPEXC_EN) {
+               printk(KERN_DEBUG "%s: saving vfp state\n", __func__);
+               vfp_save_state(&ti->vfpstate, fpexc);
+
+               /* disable, just in case */
+               fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+       }
+
+       /* clear any information we had about last context state */
+       memset(last_VFP_context, 0, sizeof(last_VFP_context));
+
+       return 0;
+}
+
+static int vfp_pm_resume(struct sys_device *dev)
+{
+       /* ensure we have access to the vfp */
+       vfp_enable(NULL);
+
+       /* and disable it to ensure the next usage restores the state */
+       fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+
+       return 0;
+}
+
+static struct sysdev_class vfp_pm_sysclass = {
+       .name           = "vfp",
+       .suspend        = vfp_pm_suspend,
+       .resume         = vfp_pm_resume,
+};
+
+static struct sys_device vfp_pm_sysdev = {
+       .cls    = &vfp_pm_sysclass,
+};
+
+static void vfp_pm_init(void)
+{
+       sysdev_class_register(&vfp_pm_sysclass);
+       sysdev_register(&vfp_pm_sysdev);
+}
+
+
+#else
+static inline void vfp_pm_init(void) { }
+#endif /* CONFIG_PM */
+
 #include <linux/smp.h>
 
 /*
@@ -365,12 +420,22 @@ static int __init vfp_init(void)
                vfp_vector = vfp_support_entry;
 
                thread_register_notifier(&vfp_notifier_block);
+               vfp_pm_init();
 
                /*
                 * We detected VFP, and the support code is
                 * in place; report VFP support to userspace.
                 */
                elf_hwcap |= HWCAP_VFP;
+#ifdef CONFIG_NEON
+               /*
+                * Check for the presence of the Advanced SIMD
+                * load/store instructions, integer and single
+                * precision floating point operations.
+                */
+               if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
+                       elf_hwcap |= HWCAP_NEON;
+#endif
        }
        return 0;
 }
index f4e55be2eea948548837177f432e893175960391..afad9f5ac0ac2190d1cb4e6685ca479b42b542a0 100644 (file)
@@ -208,6 +208,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)
                break;
        case ERR_TYPE_KERNEL_PANIC:
        default:
+               WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */
                spin_unlock_irqrestore(&rtasd_log_lock, s);
                return;
        }
@@ -227,6 +228,7 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)
        /* Check to see if we need to or have stopped logging */
        if (fatal || !logging_enabled) {
                logging_enabled = 0;
+               WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */
                spin_unlock_irqrestore(&rtasd_log_lock, s);
                return;
        }
@@ -249,11 +251,13 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal)
                else
                        rtas_log_start += 1;
 
+               WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */
                spin_unlock_irqrestore(&rtasd_log_lock, s);
                wake_up_interruptible(&rtas_log_wait);
                break;
        case ERR_TYPE_KERNEL_PANIC:
        default:
+               WARN_ON_ONCE(!irqs_disabled()); /* @@@ DEBUG @@@ */
                spin_unlock_irqrestore(&rtasd_log_lock, s);
                return;
        }
index c13568b9351c06ed1dd2114fb6b68e3c04bad09f..0503936f101f0a11b1271005e4662192545e2906 100644 (file)
@@ -50,6 +50,10 @@ struct kvm_vqconfig {
 #define KVM_S390_VIRTIO_RESET          1
 #define KVM_S390_VIRTIO_SET_STATUS     2
 
+/* The alignment to use between consumer and producer parts of vring.
+ * This is pagesize for historical reasons. */
+#define KVM_S390_VIRTIO_RING_ALIGN     4096
+
 #ifdef __KERNEL__
 /* early virtio console setup */
 #ifdef CONFIG_S390_GUEST
index ef3635b52fc0ce1420945fdbd42cf32845ecf671..0767827540b1778b0d88fa555d957ca457dc1d41 100644 (file)
@@ -263,7 +263,7 @@ int s390_enable_sie(void)
        /* lets check if we are allowed to replace the mm */
        task_lock(tsk);
        if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
-           tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) {
+           tsk->mm != tsk->active_mm || !hlist_empty(&tsk->mm->ioctx_list)) {
                task_unlock(tsk);
                return -EINVAL;
        }
@@ -279,7 +279,7 @@ int s390_enable_sie(void)
        /* Now lets check again if something happened */
        task_lock(tsk);
        if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
-           tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) {
+           tsk->mm != tsk->active_mm || !hlist_empty(&tsk->mm->ioctx_list)) {
                mmput(mm);
                task_unlock(tsk);
                return -EINVAL;
index e594559c8dbaa7658f56f079354e8ed25468fdcf..0a94d9c9cde1bf5d8c17a39880d5392954ae8afa 100644 (file)
 
 mainmenu "Linux/SPARC Kernel Configuration"
 
+config SPARC
+       bool
+       default y
+       select HAVE_IDE
+       select HAVE_OPROFILE
+       select HAVE_ARCH_KGDB if !SMP || SPARC64
+       select HAVE_ARCH_TRACEHOOK
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select RTC_CLASS
+       select RTC_DRV_M48T59
+
+# Identify this as a Sparc32 build
+config SPARC32
+       bool
+       default y if ARCH = "sparc"
+       help
+         SPARC is a family of RISC microprocessors designed and marketed by
+         Sun Microsystems, incorporated.  They are very widely found in Sun
+         workstations and clones. This port covers the original 32-bit SPARC;
+         it is old and stable and usually considered one of the "big three"
+         along with the Intel and Alpha ports.  The UltraLinux project
+         maintains both the SPARC32 and SPARC64 ports; its web page is
+         available at <http://www.ultralinux.org/>.
+
+config SPARC64
+       bool
+       default y if ARCH = "sparc64"
+       select ARCH_SUPPORTS_MSI
+       select HAVE_FUNCTION_TRACER
+       select HAVE_KRETPROBES
+       select HAVE_KPROBES
+       select HAVE_LMB
+       select USE_GENERIC_SMP_HELPERS if SMP
+       select RTC_DRV_CMOS
+       select RTC_DRV_BQ4802
+       select RTC_DRV_SUN4V
+       select RTC_DRV_STARFIRE
+
+config ARCH_DEFCONFIG
+       string
+       default "arch/sparc/configs/sparc32_defconfig" if SPARC32
+       default "arch/sparc/configs/sparc64_defconfig" if SPARC64
+
+# CONFIG_BITS can be used at source level to get 32/64 bits
+config BITS
+       int
+       default 32 if SPARC32
+       default 64 if SPARC64
+
+config 64BIT
+       def_bool y if SPARC64
+
+config GENERIC_TIME
+       bool
+       default y if SPARC64
+
+config GENERIC_CMOS_UPDATE
+       bool
+       default y if SPARC64
+
+config GENERIC_CLOCKEVENTS
+       bool
+       default y if SPARC64
+
+config IOMMU_HELPER
+       bool
+       default y if SPARC64
+
+config QUICKLIST
+       bool
+       default y if SPARC64
+
+config STACKTRACE_SUPPORT
+       bool
+       default y if SPARC64
+
+config LOCKDEP_SUPPORT
+       bool
+       default y if SPARC64
+
+config HAVE_LATENCYTOP_SUPPORT
+       bool
+       default y if SPARC64
+
+config AUDIT_ARCH
+       bool
+       default y
+
+config HAVE_SETUP_PER_CPU_AREA
+       def_bool y if SPARC64
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       bool
+       def_bool y if SPARC64
+
 config MMU
        bool
        default y
 
 config HIGHMEM
        bool
-       default y
+       default y if SPARC32
 
 config ZONE_DMA
        bool
-       default y
+       default y if SPARC32
 
 config GENERIC_ISA_DMA
        bool
-       default y
+       default y if SPARC32
 
 config GENERIC_GPIO
        bool
@@ -31,15 +126,11 @@ config ARCH_NO_VIRT_TO_BUS
 config OF
        def_bool y
 
-config HZ
-       int
-       default 100
-
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
 
-menu "General machine setup"
+menu "Processor type and features"
 
 config SMP
        bool "Symmetric multi-processing support (does not work on sun4/sun4c)"
@@ -64,82 +155,269 @@ config SMP
          If you don't know what to do here, say N.
 
 config NR_CPUS
-       int "Maximum number of CPUs (2-32)"
-       range 2 32
+       int "Maximum number of CPUs"
        depends on SMP
-       default "32"
+       range 2 32 if SPARC32
+       range 2 1024 if SPARC64
+       default 32 if SPARC32
+       default 64 if SPARC64
 
-config SPARC
+source kernel/Kconfig.hz
+
+config RWSEM_GENERIC_SPINLOCK
+       bool
+       default y if SPARC32
+
+config RWSEM_XCHGADD_ALGORITHM
+       bool
+       default y if SPARC64
+
+config GENERIC_FIND_NEXT_BIT
        bool
        default y
-       select HAVE_IDE
-       select HAVE_OPROFILE
-       select HAVE_ARCH_KGDB if !SMP
-       select HAVE_ARCH_TRACEHOOK
-       select ARCH_WANT_OPTIONAL_GPIOLIB
-       select RTC_CLASS
-       select RTC_DRV_M48T59
 
-# Identify this as a Sparc32 build
-config SPARC32
+config GENERIC_HWEIGHT
+       bool
+       default y if !ULTRA_HAS_POPULATION_COUNT
+
+config GENERIC_CALIBRATE_DELAY
        bool
        default y
-       help
-         SPARC is a family of RISC microprocessors designed and marketed by
-         Sun Microsystems, incorporated.  They are very widely found in Sun
-         workstations and clones. This port covers the original 32-bit SPARC;
-         it is old and stable and usually considered one of the "big three"
-         along with the Intel and Alpha ports.  The UltraLinux project
-         maintains both the SPARC32 and SPARC64 ports; its web page is
-         available at <http://www.ultralinux.org/>.
 
-# Global things across all Sun machines.
-config ISA
+config ARCH_MAY_HAVE_PC_FDC
        bool
-       help
-         ISA is found on Espresso only and is not supported currently.
-         Say N
+       default y
 
-config EISA
+config ARCH_HAS_ILOG2_U32
        bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
+config EMULATED_CMPXCHG
+       bool
+       default y if SPARC32
        help
-         EISA is not supported.
-         Say N
+         Sparc32 does not have a CAS instruction like sparc64. cmpxchg()
+         is emulated, and therefore it is not completely atomic.
 
-config MCA
+# Makefile helpers
+config SPARC32_SMP
+       bool
+       default y
+       depends on SPARC32 && SMP
+
+config SPARC64_SMP
        bool
+       default y
+       depends on SPARC64 && SMP
+
+choice
+       prompt "Kernel page size" if SPARC64
+       default SPARC64_PAGE_SIZE_8KB
+
+config SPARC64_PAGE_SIZE_8KB
+       bool "8KB"
        help
-         MCA is not supported.
-         Say N
+         This lets you select the page size of the kernel.
 
-config PCMCIA
-       tristate
-       ---help---
-         Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
-         computer.  These are credit-card size devices such as network cards,
-         modems or hard drives often used with laptops computers.  There are
-         actually two varieties of these cards: the older 16 bit PCMCIA cards
-         and the newer 32 bit CardBus cards.  If you want to use CardBus
-         cards, you need to say Y here and also to "CardBus support" below.
+         8KB and 64KB work quite well, since SPARC ELF sections
+         provide for up to 64KB alignment.
 
-         To use your PC-cards, you will need supporting software from David
-         Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-         for location).  Please also read the PCMCIA-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
+         If you don't know what to do, choose 8KB.
 
-         To compile this driver as modules, choose M here: the
-         modules will be called pcmcia_core and ds.
+config SPARC64_PAGE_SIZE_64KB
+       bool "64KB"
 
-config SBUS
+endchoice
+
+config SECCOMP
+       bool "Enable seccomp to safely compute untrusted bytecode"
+       depends on SPARC64 && PROC_FS
+       default y
+       help
+         This kernel feature is useful for number crunching applications
+         that may need to compute untrusted bytecode during their
+         execution. By using pipes or other transports made available to
+         the process as file descriptors supporting the read/write
+         syscalls, it's possible to isolate those applications in
+         their own address space using seccomp. Once seccomp is
+         enabled via /proc/<pid>/seccomp, it cannot be disabled
+         and the task is only allowed to execute a few safe syscalls
+         defined by each seccomp mode.
+
+         If unsure, say Y. Only embedded should say N here.
+
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs"
+       depends on SPARC64 && SMP
+       select HOTPLUG
+       help
+         Say Y here to experiment with turning CPUs off and on.  CPUs
+         can be controlled through /sys/devices/system/cpu/cpu#.
+         Say N if you want to disable CPU hotplug.
+
+config GENERIC_HARDIRQS
        bool
+       default y if SPARC64
+
+source "kernel/time/Kconfig"
+
+if SPARC64
+source "drivers/cpufreq/Kconfig"
+
+config US3_FREQ
+       tristate "UltraSPARC-III CPU Frequency driver"
+       depends on CPU_FREQ
+       select CPU_FREQ_TABLE
+       help
+         This adds the CPUFreq driver for UltraSPARC-III processors.
+
+         For details, take a look at <file:Documentation/cpu-freq>.
+
+         If in doubt, say N.
+
+config US2E_FREQ
+       tristate "UltraSPARC-IIe CPU Frequency driver"
+       depends on CPU_FREQ
+       select CPU_FREQ_TABLE
+       help
+         This adds the CPUFreq driver for UltraSPARC-IIe processors.
+
+         For details, take a look at <file:Documentation/cpu-freq>.
+
+         If in doubt, say N.
+
+endif
+
+config US3_MC
+       tristate "UltraSPARC-III Memory Controller driver"
+       depends on SPARC64
        default y
+       help
+         This adds a driver for the UltraSPARC-III memory controller.
+         Loading this driver allows exact mnemonic strings to be
+         printed in the event of a memory error, so that the faulty DIMM
+         on the motherboard can be matched to the error.
 
-config SBUSCHAR
+         If in doubt, say Y, as this information can be very useful.
+
+# Global things across all Sun machines.
+config GENERIC_LOCKBREAK
        bool
        default y
+       depends on SPARC64 && SMP && PREEMPT
+
+choice
+       prompt "SPARC64 Huge TLB Page Size"
+       depends on SPARC64 && HUGETLB_PAGE
+       default HUGETLB_PAGE_SIZE_4MB
+
+config HUGETLB_PAGE_SIZE_4MB
+       bool "4MB"
+
+config HUGETLB_PAGE_SIZE_512K
+       bool "512K"
+
+config HUGETLB_PAGE_SIZE_64K
+       depends on !SPARC64_PAGE_SIZE_64KB
+       bool "64K"
+
+endchoice
+
+config NUMA
+       bool "NUMA support"
+       depends on SPARC64 && SMP
+
+config NODES_SHIFT
+       int
+       default "4"
+       depends on NEED_MULTIPLE_NODES
+
+# Some NUMA nodes have memory ranges that span
+# other nodes.  Even though a pfn is valid and
+# between a node's start and end pfns, it may not
+# reside on that node.  See memmap_init_zone()
+# for details.
+config NODES_SPAN_OTHER_NODES
+       def_bool y
+       depends on NEED_MULTIPLE_NODES
+
+config ARCH_POPULATES_NODE_MAP
+       def_bool y if SPARC64
+
+config ARCH_SELECT_MEMORY_MODEL
+       def_bool y if SPARC64
+
+config ARCH_SPARSEMEM_ENABLE
+       def_bool y if SPARC64
+       select SPARSEMEM_VMEMMAP_ENABLE
+
+config ARCH_SPARSEMEM_DEFAULT
+       def_bool y if SPARC64
+
+source "mm/Kconfig"
+
+config SCHED_SMT
+       bool "SMT (Hyperthreading) scheduler support"
+       depends on SPARC64 && SMP
+       default y
+       help
+         SMT scheduler support improves the CPU scheduler's decision making
+         when dealing with SPARC cpus at a cost of slightly increased overhead
+         in some places. If unsure say N here.
+
+config SCHED_MC
+       bool "Multi-core scheduler support"
+       depends on SPARC64 && SMP
+       default y
+       help
+         Multi-core scheduler support improves the CPU scheduler's decision
+         making when dealing with multi-core CPU chips at a cost of slightly
+         increased overhead in some places. If unsure say N here.
+
+if SPARC64
+source "kernel/Kconfig.preempt"
+endif
+
+config CMDLINE_BOOL
+       bool "Default bootloader kernel arguments"
+       depends on SPARC64
+
+config CMDLINE
+       string "Initial kernel command string"
+       depends on CMDLINE_BOOL
+       default "console=ttyS0,9600 root=/dev/sda1"
+       help
+         Say Y here if you want to be able to pass default arguments to
+         the kernel. This will be overridden by the bootloader, if you
+         use one (such as SILO). This is most useful if you want to boot
+         a kernel from TFTP, and want default options to be available
+         with having them passed on the command line.
+
+         NOTE: This option WILL override the PROM bootargs setting!
+
+config SUN_PM
+       bool
+       default y if SPARC32
+       help
+         Enable power management and CPU standby features on supported
+         SPARC platforms.
+
+config SPARC_LED
+       tristate "Sun4m LED driver"
+       depends on SPARC32
+       help
+         This driver toggles the front-panel LED on sun4m systems
+         in a user-specifiable manner.  Its state can be probed
+         by reading /proc/led and its blinking mode can be changed
+         via writes to /proc/led
 
 config SERIAL_CONSOLE
        bool
+       depends on SPARC32
        default y
        ---help---
          If you say Y here, it will be possible to use a serial port as the
@@ -161,71 +439,66 @@ config SERIAL_CONSOLE
 
          If unsure, say N.
 
-config SUN_AUXIO
-       bool
-       default y
-
-config SUN_IO
-       bool
-       default y
-
-config RWSEM_GENERIC_SPINLOCK
-       bool
-       default y
+endmenu
 
-config RWSEM_XCHGADD_ALGORITHM
+menu "Bus options (PCI etc.)"
+config ISA
        bool
+       help
+         ISA is found on Espresso only and is not supported currently.
 
-config GENERIC_FIND_NEXT_BIT
+config ISAPNP
        bool
-       default y
+       help
+         ISAPNP is not supported
 
-config GENERIC_HWEIGHT
+config EISA
        bool
-       default y
+       help
+         EISA is not supported.
 
-config GENERIC_CALIBRATE_DELAY
+config MCA
        bool
-       default y
+       help
+         MCA is not supported.
 
-config ARCH_MAY_HAVE_PC_FDC
+config SBUS
        bool
        default y
 
-config ARCH_HAS_ILOG2_U32
-       bool
-       default n
-
-config ARCH_HAS_ILOG2_U64
-       bool
-       default n
-
-config EMULATED_CMPXCHG
+config SBUSCHAR
        bool
        default y
-       help
-         Sparc32 does not have a CAS instruction like sparc64. cmpxchg()
-         is emulated, and therefore it is not completely atomic.
 
-config SUN_PM
-       bool
-       default y
+config SUN_LDOMS
+       bool "Sun Logical Domains support"
+       depends on SPARC64
        help
-         Enable power management and CPU standby features on supported
-         SPARC platforms.
+         Say Y here is you want to support virtual devices via
+         Logical Domains.
 
 config PCI
        bool "Support for PCI and PS/2 keyboard/mouse"
        help
+         Find out whether your system includes a PCI bus. PCI is the name of
+         a bus system, i.e. the way the CPU talks to the other stuff inside
+         your box.  If you say Y here, the kernel will include drivers and
+         infrastructure code to support PCI bus devices.
+
          CONFIG_PCI is needed for all JavaStation's (including MrCoffee),
          CP-1200, JavaEngine-1, Corona, Red October, and Serengeti SGSC.
          All of these platforms are extremely obscure, so say N if unsure.
 
+config PCI_DOMAINS
+       def_bool PCI if SPARC64
+
 config PCI_SYSCALL
        def_bool PCI
 
 source "drivers/pci/Kconfig"
 
+source "drivers/pcmcia/Kconfig"
+
 config SUN_OPENPROMFS
        tristate "Openprom tree appears in /proc/openprom"
        help
@@ -239,17 +512,33 @@ config SUN_OPENPROMFS
          Only choose N if you know in advance that you will not need to modify
          OpenPROM settings on the running system.
 
-config SPARC_LED
-       tristate "Sun4m LED driver"
-       help
-         This driver toggles the front-panel LED on sun4m systems
-         in a user-specifiable manner.  Its state can be probed
-         by reading /proc/led and its blinking mode can be changed
-         via writes to /proc/led
+# Makefile helpers
+config SPARC32_PCI
+       bool
+       default y
+       depends on SPARC32 && PCI
+
+config SPARC64_PCI
+       bool
+       default y
+       depends on SPARC64 && PCI
+
+endmenu
+
+menu "Executable file formats"
 
 source "fs/Kconfig.binfmt"
 
-source "mm/Kconfig"
+config COMPAT
+       bool
+       depends on SPARC64
+       default y
+       select COMPAT_BINFMT_ELF
+
+config SYSVIPC_COMPAT
+       bool
+       depends on COMPAT && SYSVIPC
+       default y
 
 endmenu
 
@@ -259,40 +548,6 @@ source "drivers/Kconfig"
 
 source "drivers/sbus/char/Kconfig"
 
-# This one must be before the filesystem configs. -DaveM
-
-menu "Unix98 PTY support"
-
-config UNIX98_PTYS
-       bool "Unix98 PTY support"
-       ---help---
-         A pseudo terminal (PTY) is a software device consisting of two
-         halves: a master and a slave. The slave device behaves identical to
-         a physical terminal; the master device is used by a process to
-         read data from and write data to the slave, thereby emulating a
-         terminal. Typical programs for the master side are telnet servers
-         and xterms.
-
-         Linux has traditionally used the BSD-like names /dev/ptyxx for
-         masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
-         has a number of problems. The GNU C library glibc 2.1 and later,
-         however, supports the Unix98 naming standard: in order to acquire a
-         pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
-         terminal is then made available to the process and the pseudo
-         terminal slave can be accessed as /dev/pts/<number>. What was
-         traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-         The entries in /dev/pts/ are created on the fly by a virtual
-         file system; therefore, if you say Y here you should say Y to
-         "/dev/pts file system for Unix98 PTYs" as well.
-
-         If you want to say Y here, you need to have the C library glibc 2.1
-         or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-         Read the instructions in <file:Documentation/Changes> pertaining to
-         pseudo terminals. It's safe to say N.
-
-endmenu
-
 source "fs/Kconfig"
 
 source "arch/sparc/Kconfig.debug"
index 87dd496f15eb1bc2eb60318b99e0c75903261dd6..b8a15e271bfaacc2e6ce0e789fcb501b792f27b9 100644 (file)
@@ -15,4 +15,30 @@ config DEBUG_STACK_USAGE
 
          This option will slow down process creation somewhat.
 
+config DEBUG_DCFLUSH
+       bool "D-cache flush debugging"
+       depends on SPARC64 && DEBUG_KERNEL
+
+config STACK_DEBUG
+       bool "Stack Overflow Detection Support"
+
+config DEBUG_PAGEALLOC
+       bool "Debug page memory allocations"
+       depends on SPARC64 && DEBUG_KERNEL && !HIBERNATION
+       help
+         Unmap pages from the kernel linear mapping after free_pages().
+         This results in a large slowdown, but helps to find certain types
+         of memory corruptions.
+
+config MCOUNT
+       bool
+       depends on SPARC64
+       depends on STACK_DEBUG || FUNCTION_TRACER
+       default y
+
+config FRAME_POINTER
+       bool
+       depends on MCOUNT
+       default y
+
 endmenu
index 9592889a6fd0e11ef797e138b4be58f94b27bd30..2003ded054c25c779e2f19422acf130b61b7213c 100644 (file)
@@ -2,18 +2,31 @@
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
-# Sparc.
+# Sparc and sparc64.
 #
-# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1994,1996,1998 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+
+# We are not yet configured - so test on arch
+ifeq ($(ARCH),sparc)
+        KBUILD_DEFCONFIG := sparc32_defconfig
+else
+        KBUILD_DEFCONFIG := sparc64_defconfig
+endif
+
+ifeq ($(CONFIG_SPARC32),y)
+#####
+# sparc32
 #
 
 #
 # Uncomment the first KBUILD_CFLAGS if you are doing kgdb source level
 # debugging of the kernel to get the proper debugging information.
 
-AS              := $(AS) -32
-LDFLAGS                := -m elf32_sparc
-CHECKFLAGS     += -D__sparc__
+AS             := $(AS) -32
+LDFLAGS        := -m elf32_sparc
+CHECKFLAGS     += -D__sparc__
+export BITS    := 32
 
 #KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
 KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
@@ -25,38 +38,60 @@ CPPFLAGS_vmlinux.lds += -m32
 #  Actual linking is done with "make image".
 LDFLAGS_vmlinux = -r
 
-head-y := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
-HEAD_Y := $(head-y)
+# Default target
+all: zImage
+
+
+else
+#####
+# sparc64
+#
 
-core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/
-libs-y += arch/sparc/prom/ arch/sparc/lib/
+CHECKFLAGS      += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
+
+# Undefine sparc when processing vmlinux.lds - it is used
+# And teach CPP we are doing 64 bit builds (for this case)
+CPPFLAGS_vmlinux.lds += -m64 -Usparc
+LDFLAGS              := -m elf64_sparc
+export BITS          := 64
+
+KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow   \
+                 -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
+                 -Wa,--undeclared-regs
+KBUILD_CFLAGS += $(call cc-option,-mtune=ultrasparc3)
+KBUILD_AFLAGS += -m64 -mcpu=ultrasparc -Wa,--undeclared-regs
+
+ifeq ($(CONFIG_MCOUNT),y)
+  KBUILD_CFLAGS += -pg
+endif
+
+endif
+
+head-y                 := arch/sparc/kernel/head_$(BITS).o
+head-y                 += arch/sparc/kernel/init_task.o
+
+core-y                 += arch/sparc/kernel/
+core-y                 += arch/sparc/mm/ arch/sparc/math-emu/
+
+libs-y                 += arch/sparc/prom/
+libs-y                 += arch/sparc/lib/
 
 drivers-$(CONFIG_OPROFILE)     += arch/sparc/oprofile/
 
 # Export what is needed by arch/sparc/boot/Makefile
-# Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-)
-INIT_Y         := $(patsubst %/, %/built-in.o, $(init-y))
-CORE_Y         := $(core-y)
-CORE_Y         += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
-CORE_Y         := $(patsubst %/, %/built-in.o, $(CORE_Y))
-DRIVERS_Y      := $(patsubst %/, %/built-in.o, $(drivers-y))
-NET_Y          := $(patsubst %/, %/built-in.o, $(net-y))
-LIBS_Y1                := $(patsubst %/, %/lib.a, $(libs-y))
-LIBS_Y2                := $(patsubst %/, %/built-in.o, $(libs-y))
-LIBS_Y         := $(LIBS_Y1) $(LIBS_Y2)
+export VMLINUX_INIT VMLINUX_MAIN
+VMLINUX_INIT := $(head-y) $(init-y)
+VMLINUX_MAIN := $(core-y) kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+VMLINUX_MAIN += $(patsubst %/, %/lib.a, $(libs-y)) $(libs-y)
+VMLINUX_MAIN += $(drivers-y) $(net-y)
 
 ifdef CONFIG_KALLSYMS
-kallsyms.o := .tmp_kallsyms2.o
+export kallsyms.o := .tmp_kallsyms2.o
 endif
 
-export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD_Y kallsyms.o
-
-# Default target
-all: zImage
-
 boot := arch/sparc/boot
 
-image zImage tftpboot.img: vmlinux
+image zImage tftpboot.img vmlinux.aout: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 archclean:
@@ -65,11 +100,17 @@ archclean:
 # This is the image used for packaging
 KBUILD_IMAGE := $(boot)/zImage
 
-CLEAN_FILES += arch/$(ARCH)/boot/System.map
-
 # Don't use tabs in echo arguments.
+ifeq ($(ARCH),sparc)
 define archhelp
   echo  '* image        - kernel image ($(boot)/image)'
   echo  '* zImage       - stripped kernel image ($(boot)/zImage)'
   echo  '  tftpboot.img - image prepared for tftp'
 endef
+else
+define archhelp
+  echo  '* vmlinux       - Standard sparc64 kernel'
+  echo  '  vmlinux.aout  - a.out kernel for sparc64'
+  echo  '  tftpboot.img - image prepared for tftp'
+endef
+endif
similarity index 60%
rename from arch/sparc64/boot/.gitignore
rename to arch/sparc/boot/.gitignore
index 36356f9d498e5299320875ed1561a70cc62a0241..fc6f3986c76c43358ad66737e61d7169a7c5c65c 100644 (file)
@@ -1,4 +1,8 @@
+btfix.S
+btfixupprep
 image
+zImage
 tftpboot.img
 vmlinux.aout
 piggyback
+
index 3e77a9f522489c6a7c1a4d85c17dc060da20a771..96041a8d39e8cf2e01695c0536502440e43e0f0d 100644 (file)
@@ -6,13 +6,16 @@
 ROOT_IMG       := /usr/src/root.img
 ELFTOAOUT      := elftoaout
 
-hostprogs-y    := piggyback btfixupprep
-targets                := tftpboot.img btfix.o btfix.S image
+hostprogs-y    := piggyback_32 piggyback_64 btfixupprep
+targets                := tftpboot.img btfix.o btfix.S image zImage vmlinux.aout
+clean-files    := System.map
 
 quiet_cmd_elftoaout    = ELFTOAOUT $@
       cmd_elftoaout    = $(ELFTOAOUT) $(obj)/image -o $@
+
+ifeq ($(CONFIG_SPARC32),y)
 quiet_cmd_piggy                = PIGGY   $@
-      cmd_piggy                = $(obj)/piggyback $@ $(obj)/System.map $(ROOT_IMG)
+      cmd_piggy                = $(obj)/piggyback_32 $@ $(obj)/System.map $(ROOT_IMG)
 quiet_cmd_btfix                = BTFIX   $@
       cmd_btfix                = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@
 quiet_cmd_sysmap        = SYSMAP  $(obj)/System.map
@@ -37,8 +40,8 @@ define rule_image
        echo 'cmd_$@ := $(cmd_image)' > $(@D)/.$(@F).cmd
 endef
 
-BTOBJS := $(HEAD_Y) $(INIT_Y)
-BTLIBS := $(CORE_Y) $(LIBS_Y) $(DRIVERS_Y) $(NET_Y)
+BTOBJS := $(patsubst %/, %/built-in.o, $(VMLINUX_INIT))
+BTLIBS := $(patsubst %/, %/built-in.o, $(VMLINUX_MAIN))
 LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds $(BTOBJS) \
                   --start-group $(BTLIBS) --end-group \
                   $(kallsyms.o) $(obj)/btfix.o
@@ -61,3 +64,28 @@ $(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE
 
 $(obj)/btfix.S: $(obj)/btfixupprep vmlinux FORCE
        $(call if_changed,btfix)
+
+endif
+
+ifeq ($(CONFIG_SPARC64),y)
+quiet_cmd_piggy     = PIGGY   $@
+      cmd_piggy     = $(obj)/piggyback_64 $@ System.map $(ROOT_IMG)
+quiet_cmd_strip     = STRIP   $@
+      cmd_strip     = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@
+
+
+# Actual linking
+$(obj)/image: vmlinux FORCE
+       $(call if_changed,strip)
+       @echo '  kernel: $@ is ready'
+
+$(obj)/tftpboot.img: vmlinux $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE
+       $(call if_changed,elftoaout)
+       $(call if_changed,piggy)
+       @echo '  kernel: $@ is ready'
+
+$(obj)/vmlinux.aout: vmlinux FORCE
+       $(call if_changed,elftoaout)
+       @echo '  kernel: $@ is ready'
+endif
+
index 2d2769d766ec7cacc827737bdbea9d73e139cfce..89c260aab45c83fd503119114095f93f2589ddc0 100644 (file)
@@ -15,8 +15,6 @@ header-y += signal_32.h
 header-y += signal_64.h
 header-y += stat_32.h
 header-y += stat_64.h
-header-y += unistd_32.h
-header-y += unistd_64.h
 
 header-y += apc.h
 header-y += asi.h
diff --git a/arch/sparc/include/asm/asm.h b/arch/sparc/include/asm/asm.h
new file mode 100644 (file)
index 0000000..e8e1d94
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _SPARC_ASM_H
+#define _SPARC_ASM_H
+
+/* Macros to assist the sharing of assembler code between 32-bit and
+ * 64-bit sparc.
+ */
+
+#ifdef CONFIG_SPARC64
+#define BRANCH32(TYPE, PREDICT, DEST) \
+       TYPE,PREDICT    %icc, DEST
+#define BRANCH32_ANNUL(TYPE, PREDICT, DEST) \
+       TYPE,a,PREDICT  %icc, DEST
+#define BRANCH_REG_ZERO(PREDICT, REG, DEST) \
+       brz,PREDICT     REG, DEST
+#define BRANCH_REG_ZERO_ANNUL(PREDICT, REG, DEST) \
+       brz,a,PREDICT   REG, DEST
+#define BRANCH_REG_NOT_ZERO(PREDICT, REG, DEST) \
+       brnz,PREDICT    REG, DEST
+#define BRANCH_REG_NOT_ZERO_ANNUL(PREDICT, REG, DEST) \
+       brnz,a,PREDICT  REG, DEST
+#else
+#define BRANCH32(TYPE, PREDICT, DEST) \
+       TYPE            DEST
+#define BRANCH32_ANNUL(TYPE, PREDICT, DEST) \
+       TYPE,a          DEST
+#define BRANCH_REG_ZERO(PREDICT, REG, DEST) \
+       cmp             REG, 0; \
+       be              DEST
+#define BRANCH_REG_ZERO_ANNUL(PREDICT, REG, DEST) \
+       cmp             REG, 0; \
+       be,a            DEST
+#define BRANCH_REG_NOT_ZERO(PREDICT, REG, DEST) \
+       cmp             REG, 0; \
+       bne             DEST
+#define BRANCH_REG_NOT_ZERO_ANNUL(PREDICT, REG, DEST) \
+       cmp             REG, 0; \
+       bne,a           DEST
+#endif
+
+#endif /* _SPARC_ASM_H */
index 2c71ec4a3b180930f53bcbec979527d3f28d3f97..5982c5ae7f0799e9159cd89096e80e99d600c8fe 100644 (file)
@@ -112,17 +112,10 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
 /* Atomic operations are already serializing */
-#ifdef CONFIG_SMP
-#define smp_mb__before_atomic_dec()    membar_storeload_loadload();
-#define smp_mb__after_atomic_dec()     membar_storeload_storestore();
-#define smp_mb__before_atomic_inc()    membar_storeload_loadload();
-#define smp_mb__after_atomic_inc()     membar_storeload_storestore();
-#else
 #define smp_mb__before_atomic_dec()    barrier()
 #define smp_mb__after_atomic_dec()     barrier()
 #define smp_mb__before_atomic_inc()    barrier()
 #define smp_mb__after_atomic_inc()     barrier()
-#endif
 
 #include <asm-generic/atomic.h>
 #endif /* !(__ARCH_SPARC64_ATOMIC__) */
index bb87b80802200090d8f1e7476bd735d6a23d1b3f..e72ac9cdfb982eb307367a7cd1d8f8f9914efaa4 100644 (file)
@@ -23,13 +23,8 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
 
 #include <asm-generic/bitops/non-atomic.h>
 
-#ifdef CONFIG_SMP
-#define smp_mb__before_clear_bit()     membar_storeload_loadload()
-#define smp_mb__after_clear_bit()      membar_storeload_storestore()
-#else
 #define smp_mb__before_clear_bit()     barrier()
 #define smp_mb__after_clear_bit()      barrier()
-#endif
 
 #include <asm-generic/bitops/ffz.h>
 #include <asm-generic/bitops/__ffs.h>
index 109ae24ba242c3f24a7861d15580c0c62045709b..bafe5a631b6d1a4e46653c7f6fa01f4b80603a1f 100644 (file)
@@ -2713,6 +2713,30 @@ extern unsigned long sun4v_ldc_revoke(unsigned long channel,
  */
 #define HV_FAST_SET_PERFREG            0x101
 
+#define HV_N2_PERF_SPARC_CTL           0x0
+#define HV_N2_PERF_DRAM_CTL0           0x1
+#define HV_N2_PERF_DRAM_CNT0           0x2
+#define HV_N2_PERF_DRAM_CTL1           0x3
+#define HV_N2_PERF_DRAM_CNT1           0x4
+#define HV_N2_PERF_DRAM_CTL2           0x5
+#define HV_N2_PERF_DRAM_CNT2           0x6
+#define HV_N2_PERF_DRAM_CTL3           0x7
+#define HV_N2_PERF_DRAM_CNT3           0x8
+
+#define HV_FAST_N2_GET_PERFREG         0x104
+#define HV_FAST_N2_SET_PERFREG         0x105
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_niagara_getperf(unsigned long reg,
+                                          unsigned long *val);
+extern unsigned long sun4v_niagara_setperf(unsigned long reg,
+                                          unsigned long val);
+extern unsigned long sun4v_niagara2_getperf(unsigned long reg,
+                                           unsigned long *val);
+extern unsigned long sun4v_niagara2_setperf(unsigned long reg,
+                                           unsigned long val);
+#endif
+
 /* MMU statistics services.
  *
  * The hypervisor maintains MMU statistics and privileged code provides
index fe205cc444b889619e82612ac3ba7ed00302035a..ea43057d47633164b0100367a01f4c9f3ff67e12 100644 (file)
@@ -12,4 +12,5 @@
 
 #define irq_canonicalize(irq)  (irq)
 
+extern void __init init_IRQ(void);
 #endif
index 71673eca3660be0dcce7359c88aa9edcae0e7ee1..d47d4a1955a974169b8a9bf432915c5d4263807c 100644 (file)
@@ -66,6 +66,9 @@ extern void virt_irq_free(unsigned int virt_irq);
 extern void __init init_IRQ(void);
 extern void fixup_irqs(void);
 
+extern int register_perfctr_intr(void (*handler)(struct pt_regs *));
+extern void release_perfctr_intr(void (*handler)(struct pt_regs *));
+
 static inline void set_softint(unsigned long bits)
 {
        __asm__ __volatile__("wr        %0, 0x0, %%set_softint"
index bb42e59162aab85829566a369255a55ce67180aa..8b49bf920df3b11a1d7d9b661891c5d0918a11de 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
 
+#include <asm/pil.h>
+
 #ifndef __ASSEMBLY__
 
 static inline unsigned long __raw_local_save_flags(void)
@@ -40,9 +42,9 @@ static inline void raw_local_irq_restore(unsigned long flags)
 static inline void raw_local_irq_disable(void)
 {
        __asm__ __volatile__(
-               "wrpr   15, %%pil"
+               "wrpr   %0, %%pil"
                : /* no outputs */
-               : /* no inputs */
+               : "i" (PIL_NORMAL_MAX)
                : "memory"
        );
 }
index e82cf9a3e60ee53e22ba05abdb0ef2a024e8b487..ff8e02d803344f4548b05854df2f3c6fd3a086cf 100644 (file)
@@ -1,8 +1,24 @@
-#ifndef ___ASM_SPARC_MODULE_H
-#define ___ASM_SPARC_MODULE_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/module_64.h>
-#else
-#include <asm/module_32.h>
-#endif
-#endif
+#ifndef __SPARC_MODULE_H
+#define __SPARC_MODULE_H
+struct mod_arch_specific { };
+
+/*
+ * Use some preprocessor magic to define the correct symbol
+ * for sparc32 and sparc64.
+ * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64
+ */
+#define ___ELF(a, b, c) a##b##c
+#define __ELF(a, b, c)  ___ELF(a, b, c)
+#define  _Elf(t)        __ELF(Elf, CONFIG_BITS, t)
+#define  _ELF(t)        __ELF(ELF, CONFIG_BITS, t)
+
+#define Elf_Shdr     _Elf(_Shdr)
+#define Elf_Sym      _Elf(_Sym)
+#define Elf_Ehdr     _Elf(_Ehdr)
+#define Elf_Rela     _Elf(_Rela)
+#define Elf_Addr     _Elf(_Addr)
+
+#define ELF_R_SYM    _ELF(_R_SYM)
+#define ELF_R_TYPE   _ELF(_R_TYPE)
+
+#endif /* __SPARC_MODULE_H */
diff --git a/arch/sparc/include/asm/module_32.h b/arch/sparc/include/asm/module_32.h
deleted file mode 100644 (file)
index cbd9e67..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _ASM_SPARC_MODULE_H
-#define _ASM_SPARC_MODULE_H
-struct mod_arch_specific { };
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-#endif /* _ASM_SPARC_MODULE_H */
diff --git a/arch/sparc/include/asm/module_64.h b/arch/sparc/include/asm/module_64.h
deleted file mode 100644 (file)
index 3d77ba4..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _ASM_SPARC64_MODULE_H
-#define _ASM_SPARC64_MODULE_H
-struct mod_arch_specific { };
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#endif /* _ASM_SPARC64_MODULE_H */
index 8b1649f29ed954439d996a8bbd337a9d2aa1c482..875da3552d80e7d415182957f95ef8b77c111c28 100644 (file)
@@ -170,9 +170,9 @@ struct linux_romvec {
 struct linux_nodeops {
        int (*no_nextnode)(int node);
        int (*no_child)(int node);
-       int (*no_proplen)(int node, char *name);
-       int (*no_getprop)(int node, char *name, char *val);
-       int (*no_setprop)(int node, char *name, char *val, int len);
+       int (*no_proplen)(int node, const char *name);
+       int (*no_getprop)(int node, const char *name, char *val);
+       int (*no_setprop)(int node, const char *name, char *val, int len);
        char * (*no_nextprop)(int node, char *name);
 };
 
index 699da05235c83f5f8c6afa4415775f17df7340e0..73d45521db04f8fb60584ef2a35c0a351ac1023a 100644 (file)
@@ -136,7 +136,7 @@ extern char prom_getchar(void);
 extern void prom_putchar(char character);
 
 /* Prom's internal routines, don't use in kernel/boot code. */
-extern void prom_printf(char *fmt, ...);
+extern void prom_printf(const char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
 /* Multiprocessor operations... */
@@ -199,12 +199,12 @@ extern int prom_getsibling(int node);
 /* Get the length, at the passed node, of the given property type.
  * Returns -1 on error (ie. no such property at this node).
  */
-extern int prom_getproplen(int thisnode, char *property);
+extern int prom_getproplen(int thisnode, const char *property);
 
 /* Fetch the requested property using the given buffer.  Returns
  * the number of bytes the prom put into your buffer or -1 on error.
  */
-extern int __must_check prom_getproperty(int thisnode, char *property,
+extern int __must_check prom_getproperty(int thisnode, const char *property,
                                         char *prop_buffer, int propbuf_size);
 
 /* Acquire an integer property. */
@@ -246,7 +246,7 @@ extern int prom_node_has_property(int node, char *property);
 /* Set the indicated property at the given node with the passed value.
  * Returns the number of bytes of your value that the prom took.
  */
-extern int prom_setprop(int node, char *prop_name, char *prop_value,
+extern int prom_setprop(int node, const char *prop_name, char *prop_value,
                        int value_size);
 
 extern int prom_pathtoinode(char *path);
index 71819bb943fc7e863f0a82cd8e4ff11f2b324c74..d573820c0ff4fc9bc766687174acdde78d664700 100644 (file)
  *
  * In fact any XCALL which has to etrap/rtrap has a problem because
  * it is difficult to prevent rtrap from running BH's, and that would
- * need to be done if the XCALL arrived while %pil==15.
+ * need to be done if the XCALL arrived while %pil==PIL_NORMAL_MAX.
+ *
+ * Finally, in order to handle profiling events even when a
+ * local_irq_disable() is in progress, we only disable up to level 14
+ * interrupts.  Profile counter overflow interrupts arrive at level
+ * 15.
  */
 #define PIL_SMP_CALL_FUNC      1
 #define PIL_SMP_RECEIVE_SIGNAL 2
@@ -18,5 +23,7 @@
 #define PIL_SMP_CTX_NEW_VERSION        4
 #define PIL_DEVICE_IRQ         5
 #define PIL_SMP_CALL_FUNC_SNGL 6
+#define PIL_NORMAL_MAX         14
+#define PIL_NMI                        15
 
 #endif /* !(_SPARC64_PIL_H) */
index ec21a4517641b16b8414baab15f18a55a4363e27..e580f5581c8863ce60ad9d6638f15c039f31ce30 100644 (file)
@@ -1,8 +1,27 @@
-#ifndef ___ASM_SPARC_SCATTERLIST_H
-#define ___ASM_SPARC_SCATTERLIST_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/scatterlist_64.h>
-#else
-#include <asm/scatterlist_32.h>
-#endif
+#ifndef _SPARC_SCATTERLIST_H
+#define _SPARC_SCATTERLIST_H
+
+#include <asm/page.h>
+#include <asm/types.h>
+
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
 #endif
+       unsigned long   page_link;
+       unsigned int    offset;
+
+       unsigned int    length;
+
+       dma_addr_t      dma_address;
+       __u32           dma_length;
+};
+
+#define sg_dma_address(sg)     ((sg)->dma_address)
+#define sg_dma_len(sg)         ((sg)->dma_length)
+
+#define ISA_DMA_THRESHOLD      (~0UL)
+
+#define ARCH_HAS_SG_CHAIN
+
+#endif /* !(_SPARC_SCATTERLIST_H) */
diff --git a/arch/sparc/include/asm/scatterlist_32.h b/arch/sparc/include/asm/scatterlist_32.h
deleted file mode 100644 (file)
index c82609c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _SPARC_SCATTERLIST_H
-#define _SPARC_SCATTERLIST_H
-
-#include <linux/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-
-       unsigned int length;
-
-       __u32 dvma_address; /* A place to hang host-specific addresses at. */
-       __u32 dvma_length;
-};
-
-#define sg_dma_address(sg) ((sg)->dvma_address)
-#define sg_dma_len(sg)     ((sg)->dvma_length)
-
-#define ISA_DMA_THRESHOLD (~0UL)
-
-#define ARCH_HAS_SG_CHAIN
-
-#endif /* !(_SPARC_SCATTERLIST_H) */
diff --git a/arch/sparc/include/asm/scatterlist_64.h b/arch/sparc/include/asm/scatterlist_64.h
deleted file mode 100644 (file)
index 81bd058..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _SPARC64_SCATTERLIST_H
-#define _SPARC64_SCATTERLIST_H
-
-#include <asm/page.h>
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-
-       unsigned int    length;
-
-       dma_addr_t      dma_address;
-       __u32           dma_length;
-};
-
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->dma_length)
-
-#define ISA_DMA_THRESHOLD      (~0UL)
-
-#define ARCH_HAS_SG_CHAIN
-
-#endif /* !(_SPARC64_SCATTERLIST_H) */
index c7c69b00967ffe4fa826dcdbece00d901c1fe270..0b0553bbd8a0dd26feb97be864a29997b754643e 100644 (file)
@@ -1,8 +1,10 @@
-#ifndef ___ASM_SPARC_SECTIONS_H
-#define ___ASM_SPARC_SECTIONS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sections_64.h>
-#else
-#include <asm/sections_32.h>
-#endif
+#ifndef __SPARC_SECTIONS_H
+#define __SPARC_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+/* sparc entry point */
+extern char _start[];
+
 #endif
diff --git a/arch/sparc/include/asm/sections_32.h b/arch/sparc/include/asm/sections_32.h
deleted file mode 100644 (file)
index 6832841..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_SECTIONS_H
-#define _SPARC_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-#endif
diff --git a/arch/sparc/include/asm/sections_64.h b/arch/sparc/include/asm/sections_64.h
deleted file mode 100644 (file)
index 3f4b9fd..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _SPARC64_SECTIONS_H
-#define _SPARC64_SECTIONS_H
-
-/* nothing to see, move along */
-#include <asm-generic/sections.h>
-
-extern char _start[];
-
-#endif
index 120cfe4577c752bc44a417cdf2e4c1cef986f1c9..c4d274d330e98b848489c3aeb64cf8516f6f7b4f 100644 (file)
  * and rebuild your kernel.
  */
 
-/* All of these locking primitives are expected to work properly
- * even in an RMO memory model, which currently is what the kernel
- * runs in.
- *
- * There is another issue.  Because we play games to save cycles
- * in the non-contention case, we need to be extra careful about
- * branch targets into the "spinning" code.  They live in their
- * own section, but the newer V9 branches have a shorter range
- * than the traditional 32-bit sparc branch variants.  The rule
- * is that the branches that go into and out of the spinner sections
- * must be pre-V9 branches.
+/* Because we play games to save cycles in the non-contention case, we
+ * need to be extra careful about branch targets into the "spinning"
+ * code.  They live in their own section, but the newer V9 branches
+ * have a shorter range than the traditional 32-bit sparc branch
+ * variants.  The rule is that the branches that go into and out of
+ * the spinner sections must be pre-V9 branches.
  */
 
 #define __raw_spin_is_locked(lp)       ((lp)->lock != 0)
@@ -38,12 +33,10 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
 
        __asm__ __volatile__(
 "1:    ldstub          [%1], %0\n"
-"      membar          #StoreLoad | #StoreStore\n"
 "      brnz,pn         %0, 2f\n"
 "       nop\n"
 "      .subsection     2\n"
 "2:    ldub            [%1], %0\n"
-"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 2b\n"
 "       nop\n"
 "      ba,a,pt         %%xcc, 1b\n"
@@ -59,7 +52,6 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
 
        __asm__ __volatile__(
 "      ldstub          [%1], %0\n"
-"      membar          #StoreLoad | #StoreStore"
        : "=r" (result)
        : "r" (lock)
        : "memory");
@@ -70,7 +62,6 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
 {
        __asm__ __volatile__(
-"      membar          #StoreStore | #LoadStore\n"
 "      stb             %%g0, [%0]"
        : /* No outputs */
        : "r" (lock)
@@ -83,14 +74,12 @@ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long fla
 
        __asm__ __volatile__(
 "1:    ldstub          [%2], %0\n"
-"      membar          #StoreLoad | #StoreStore\n"
 "      brnz,pn         %0, 2f\n"
 "       nop\n"
 "      .subsection     2\n"
 "2:    rdpr            %%pil, %1\n"
 "      wrpr            %3, %%pil\n"
 "3:    ldub            [%2], %0\n"
-"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 3b\n"
 "       nop\n"
 "      ba,pt           %%xcc, 1b\n"
@@ -113,12 +102,10 @@ static void inline __read_lock(raw_rwlock_t *lock)
 "4:     add            %0, 1, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
-"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
 "       nop\n"
 "      .subsection     2\n"
 "2:    ldsw            [%2], %0\n"
-"      membar          #LoadLoad\n"
 "      brlz,pt         %0, 2b\n"
 "       nop\n"
 "      ba,a,pt         %%xcc, 4b\n"
@@ -139,7 +126,6 @@ static int inline __read_trylock(raw_rwlock_t *lock)
 "      add             %0, 1, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
-"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
 "       mov            1, %0\n"
 "2:"
@@ -155,7 +141,6 @@ static void inline __read_unlock(raw_rwlock_t *lock)
        unsigned long tmp1, tmp2;
 
        __asm__ __volatile__(
-"      membar  #StoreLoad | #LoadLoad\n"
 "1:    lduw    [%2], %0\n"
 "      sub     %0, 1, %1\n"
 "      cas     [%2], %0, %1\n"
@@ -179,12 +164,10 @@ static void inline __write_lock(raw_rwlock_t *lock)
 "4:     or             %0, %3, %1\n"
 "      cas             [%2], %0, %1\n"
 "      cmp             %0, %1\n"
-"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
 "       nop\n"
 "      .subsection     2\n"
 "2:    lduw            [%2], %0\n"
-"      membar          #LoadLoad\n"
 "      brnz,pt         %0, 2b\n"
 "       nop\n"
 "      ba,a,pt         %%xcc, 4b\n"
@@ -197,7 +180,6 @@ static void inline __write_lock(raw_rwlock_t *lock)
 static void inline __write_unlock(raw_rwlock_t *lock)
 {
        __asm__ __volatile__(
-"      membar          #LoadStore | #StoreStore\n"
 "      stw             %%g0, [%0]"
        : /* no outputs */
        : "r" (lock)
@@ -217,7 +199,6 @@ static int inline __write_trylock(raw_rwlock_t *lock)
 "       or             %0, %4, %1\n"
 "      cas             [%3], %0, %1\n"
 "      cmp             %0, %1\n"
-"      membar          #StoreLoad | #StoreStore\n"
 "      bne,pn          %%icc, 1b\n"
 "       nop\n"
 "      mov             1, %2\n"
index 985ea7e319927d2e7906c13956cd95dc5354289e..f0d0c40c44da9c98bd83f573d6d8374d2c44172b 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef _SPARC64_SPITFIRE_H
 #define _SPARC64_SPITFIRE_H
 
+#ifdef CONFIG_SPARC64
+
 #include <asm/asi.h>
 
 /* The following register addresses are accessible via ASI_DMMU
@@ -338,5 +340,5 @@ static inline void cheetah_put_itlb_data(int entry, unsigned long data)
 }
 
 #endif /* !(__ASSEMBLY__) */
-
+#endif /* CONFIG_SPARC64 */
 #endif /* !(_SPARC64_SPITFIRE_H) */
index 8623fc48fe247bbe4005bb3400d34802cff70fa1..79c1ae2b42a346ec11aa284a9719a926212741f3 100644 (file)
 
 #include <linux/irqflags.h>
 
+static inline unsigned int probe_irq_mask(unsigned long val)
+{
+       return 0;
+}
+
 /*
  * Sparc (general) CPU types
  */
index 8759f2a1b837c3f4c655cf48d10b91475f54da12..6c077816ab28c923f75c47494fa8b37efb55ab0a 100644 (file)
@@ -59,20 +59,9 @@ do { __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
                             : : : "memory"); \
 } while (0)
 
-#define mb()   \
-       membar_safe("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad")
-#define rmb()  \
-       membar_safe("#LoadLoad")
-#define wmb()  \
-       membar_safe("#StoreStore")
-#define membar_storeload() \
-       membar_safe("#StoreLoad")
-#define membar_storeload_storestore() \
-       membar_safe("#StoreLoad | #StoreStore")
-#define membar_storeload_loadload() \
-       membar_safe("#StoreLoad | #LoadLoad")
-#define membar_storestore_loadstore() \
-       membar_safe("#StoreStore | #LoadStore")
+#define mb()   membar_safe("#StoreLoad")
+#define rmb()  __asm__ __volatile__("":::"memory")
+#define wmb()  __asm__ __volatile__("":::"memory")
 
 #endif
 
@@ -80,20 +69,20 @@ do {        __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
 
 #define read_barrier_depends()         do { } while(0)
 #define set_mb(__var, __value) \
-       do { __var = __value; membar_storeload_storestore(); } while(0)
+       do { __var = __value; membar_safe("#StoreLoad"); } while(0)
 
 #ifdef CONFIG_SMP
 #define smp_mb()       mb()
 #define smp_rmb()      rmb()
 #define smp_wmb()      wmb()
-#define smp_read_barrier_depends()     read_barrier_depends()
 #else
 #define smp_mb()       __asm__ __volatile__("":::"memory")
 #define smp_rmb()      __asm__ __volatile__("":::"memory")
 #define smp_wmb()      __asm__ __volatile__("":::"memory")
-#define smp_read_barrier_depends()     do { } while(0)
 #endif
 
+#define smp_read_barrier_depends()     do { } while(0)
+
 #define flushi(addr)   __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
 
 #define flushw_all()   __asm__ __volatile__("flushw")
@@ -107,11 +96,12 @@ do {       __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
  * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
  * for more information.
  */
-#define reset_pic()                                                    \
-       __asm__ __volatile__("ba,pt     %xcc, 99f\n\t"          \
+#define write_pic(__p)                                         \
+       __asm__ __volatile__("ba,pt     %%xcc, 99f\n\t"         \
                             ".align    64\n"                   \
-                         "99:wr        %g0, 0x0, %pic\n\t"     \
-                            "rd        %pic, %g0")
+                         "99:wr        %0, 0x0, %%pic\n\t"     \
+                            "rd        %%pic, %%g0" : : "r" (__p))
+#define reset_pic()    write_pic(0)
 
 #ifndef __ASSEMBLY__
 
@@ -170,6 +160,7 @@ do {        if (test_thread_flag(TIF_PERFCTR)) {                            \
        "stb    %%o5, [%%g6 + %5]\n\t"                                  \
        "rdpr   %%cwp, %%o5\n\t"                                        \
        "stb    %%o5, [%%g6 + %8]\n\t"                                  \
+       "wrpr   %%g0, 15, %%pil\n\t"                                    \
        "mov    %4, %%g6\n\t"                                           \
        "ldub   [%4 + %8], %%g1\n\t"                                    \
        "wrpr   %%g1, %%cwp\n\t"                                        \
@@ -180,6 +171,7 @@ do {        if (test_thread_flag(TIF_PERFCTR)) {                            \
        "ldx    [%%sp + 2047 + 0x70], %%i6\n\t"                         \
        "ldx    [%%sp + 2047 + 0x78], %%i7\n\t"                         \
        "ldx    [%%g6 + %9], %%g4\n\t"                                  \
+       "wrpr   %%g0, 14, %%pil\n\t"                                    \
        "brz,pt %%o7, switch_to_pc\n\t"                                 \
        " mov   %%g7, %0\n\t"                                           \
        "sethi  %%hi(ret_from_syscall), %%g1\n\t"                       \
@@ -209,14 +201,12 @@ static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int va
        unsigned long tmp1, tmp2;
 
        __asm__ __volatile__(
-"      membar          #StoreLoad | #LoadLoad\n"
 "      mov             %0, %1\n"
 "1:    lduw            [%4], %2\n"
 "      cas             [%4], %2, %0\n"
 "      cmp             %2, %0\n"
 "      bne,a,pn        %%icc, 1b\n"
 "       mov            %1, %0\n"
-"      membar          #StoreLoad | #StoreStore\n"
        : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
        : "0" (val), "r" (m)
        : "cc", "memory");
@@ -228,14 +218,12 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long
        unsigned long tmp1, tmp2;
 
        __asm__ __volatile__(
-"      membar          #StoreLoad | #LoadLoad\n"
 "      mov             %0, %1\n"
 "1:    ldx             [%4], %2\n"
 "      casx            [%4], %2, %0\n"
 "      cmp             %2, %0\n"
 "      bne,a,pn        %%xcc, 1b\n"
 "       mov            %1, %0\n"
-"      membar          #StoreLoad | #StoreStore\n"
        : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
        : "0" (val), "r" (m)
        : "cc", "memory");
@@ -272,9 +260,7 @@ extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noret
 static inline unsigned long
 __cmpxchg_u32(volatile int *m, int old, int new)
 {
-       __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
-                            "cas [%2], %3, %0\n\t"
-                            "membar #StoreLoad | #StoreStore"
+       __asm__ __volatile__("cas [%2], %3, %0"
                             : "=&r" (new)
                             : "0" (new), "r" (m), "r" (old)
                             : "memory");
@@ -285,9 +271,7 @@ __cmpxchg_u32(volatile int *m, int old, int new)
 static inline unsigned long
 __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
 {
-       __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
-                            "casx [%2], %3, %0\n\t"
-                            "membar #StoreLoad | #StoreStore"
+       __asm__ __volatile__("casx [%2], %3, %0"
                             : "=&r" (new)
                             : "0" (new), "r" (m), "r" (old)
                             : "memory");
index 76e4299dd9bc957667668bd39b38713d8cb9440e..83c571d8c8a7ebd2fb243c9b057105dd43c827e6 100644 (file)
@@ -50,8 +50,6 @@
 #define TSB_TAG_INVALID_BIT    46
 #define TSB_TAG_INVALID_HIGH   (1 << (TSB_TAG_INVALID_BIT - 32))
 
-#define TSB_MEMBAR     membar  #StoreStore
-
 /* Some cpus support physical address quad loads.  We want to use
  * those if possible so we don't need to hard-lock the TSB mapping
  * into the TLB.  We encode some instruction patching in order to
@@ -128,13 +126,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        cmp     REG1, REG2;             \
        bne,pn  %icc, 99b;              \
         nop;                           \
-       TSB_MEMBAR
 
 #define TSB_WRITE(TSB, TTE, TAG) \
        add     TSB, 0x8, TSB;   \
        TSB_STORE(TSB, TTE);     \
        sub     TSB, 0x8, TSB;   \
-       TSB_MEMBAR;              \
        TSB_STORE(TSB, TAG);
 
 #define KTSB_LOAD_QUAD(TSB, REG) \
@@ -153,13 +149,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
        cmp     REG1, REG2;             \
        bne,pn  %icc, 99b;              \
         nop;                           \
-       TSB_MEMBAR
 
 #define KTSB_WRITE(TSB, TTE, TAG) \
        add     TSB, 0x8, TSB;   \
        stxa    TTE, [TSB] ASI_N;     \
        sub     TSB, 0x8, TSB;   \
-       TSB_MEMBAR;              \
        stxa    TAG, [TSB] ASI_N;
 
        /* Do a kernel page table walk.  Leaves physical PTE pointer in
index 5708ba2719fb07e666cef4a0cc1e1cccf597d14d..48f2807d326563da2bc95be4f870517685331aaf 100644 (file)
@@ -2,6 +2,7 @@
 #define _SPARC64_TTABLE_H
 
 #include <asm/utrap.h>
+#include <asm/pil.h>
 
 #ifdef __ASSEMBLY__
 #include <asm/thread_info.h>
 
 #define TRAP_IRQ(routine, level)                       \
        rdpr    %pil, %g2;                              \
-       wrpr    %g0, 15, %pil;                          \
+       wrpr    %g0, PIL_NORMAL_MAX, %pil;              \
        sethi   %hi(1f-4), %g7;                         \
        ba,pt   %xcc, etrap_irq;                        \
         or     %g7, %lo(1f-4), %g7;                    \
 
 #define TRAP_IRQ(routine, level)                       \
        rdpr    %pil, %g2;                              \
-       wrpr    %g0, 15, %pil;                          \
+       wrpr    %g0, PIL_NORMAL_MAX, %pil;              \
        ba,pt   %xcc, etrap_irq;                        \
         rd     %pc, %g7;                               \
        mov     level, %o0;                             \
 
 #endif
 
+#define TRAP_NMI_IRQ(routine, level)                   \
+       rdpr    %pil, %g2;                              \
+       wrpr    %g0, PIL_NMI, %pil;                     \
+       ba,pt   %xcc, etrap_irq;                        \
+        rd     %pc, %g7;                               \
+       mov     level, %o0;                             \
+       call    routine;                                \
+        add    %sp, PTREGS_OFF, %o1;                   \
+       ba,a,pt %xcc, rtrap_nmi;
+
 #define TRAP_IVEC TRAP_NOSAVE(do_ivec)
 
 #define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
index 4207fb362da03e300ce2cff530ca68401560c7f7..031f038b19f719c6a34fdd346efd4c3ebacf7283 100644 (file)
@@ -1,8 +1,444 @@
-#ifndef ___ASM_SPARC_UNISTD_H
-#define ___ASM_SPARC_UNISTD_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/unistd_64.h>
+#ifndef _SPARC_UNISTD_H
+#define _SPARC_UNISTD_H
+
+/*
+ * System calls under the Sparc.
+ *
+ * Don't be scared by the ugly clobbers, it is the only way I can
+ * think of right now to force the arguments into fixed registers
+ * before the trap into the system call with gcc 'asm' statements.
+ *
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
+ *
+ * SunOS compatibility based upon preliminary work which is:
+ *
+ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
+ */
+#ifndef __32bit_syscall_numbers__
+#ifndef __arch64__
+#define __32bit_syscall_numbers__
+#endif
+#endif
+
+#define __NR_restart_syscall      0 /* Linux Specific                             */
+#define __NR_exit                 1 /* Common                                      */
+#define __NR_fork                 2 /* Common                                      */
+#define __NR_read                 3 /* Common                                      */
+#define __NR_write                4 /* Common                                      */
+#define __NR_open                 5 /* Common                                      */
+#define __NR_close                6 /* Common                                      */
+#define __NR_wait4                7 /* Common                                      */
+#define __NR_creat                8 /* Common                                      */
+#define __NR_link                 9 /* Common                                      */
+#define __NR_unlink              10 /* Common                                      */
+#define __NR_execv               11 /* SunOS Specific                              */
+#define __NR_chdir               12 /* Common                                      */
+#define __NR_chown              13 /* Common                                      */
+#define __NR_mknod               14 /* Common                                      */
+#define __NR_chmod               15 /* Common                                      */
+#define __NR_lchown              16 /* Common                                      */
+#define __NR_brk                 17 /* Common                                      */
+#define __NR_perfctr             18 /* Performance counter operations              */
+#define __NR_lseek               19 /* Common                                      */
+#define __NR_getpid              20 /* Common                                      */
+#define __NR_capget             21 /* Linux Specific                              */
+#define __NR_capset             22 /* Linux Specific                              */
+#define __NR_setuid              23 /* Implemented via setreuid in SunOS           */
+#define __NR_getuid              24 /* Common                                      */
+#define __NR_vmsplice           25 /* ENOSYS under SunOS                          */
+#define __NR_ptrace              26 /* Common                                      */
+#define __NR_alarm               27 /* Implemented via setitimer in SunOS          */
+#define __NR_sigaltstack        28 /* Common                                      */
+#define __NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
+#define __NR_utime               30 /* Implemented via utimes() under SunOS        */
+#ifdef __32bit_syscall_numbers__
+#define __NR_lchown32            31 /* Linux sparc32 specific                      */
+#define __NR_fchown32            32 /* Linux sparc32 specific                      */
+#endif
+#define __NR_access              33 /* Common                                      */
+#define __NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
+#ifdef __32bit_syscall_numbers__
+#define __NR_chown32             35 /* Linux sparc32 specific                      */
+#endif
+#define __NR_sync                36 /* Common                                      */
+#define __NR_kill                37 /* Common                                      */
+#define __NR_stat                38 /* Common                                      */
+#define __NR_sendfile           39 /* Linux Specific                              */
+#define __NR_lstat               40 /* Common                                      */
+#define __NR_dup                 41 /* Common                                      */
+#define __NR_pipe                42 /* Common                                      */
+#define __NR_times               43 /* Implemented via getrusage() in SunOS        */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getuid32            44 /* Linux sparc32 specific                      */
+#endif
+#define __NR_umount2             45 /* Linux Specific                              */
+#define __NR_setgid              46 /* Implemented via setregid() in SunOS         */
+#define __NR_getgid              47 /* Common                                      */
+#define __NR_signal              48 /* Implemented via sigvec() in SunOS           */
+#define __NR_geteuid             49 /* SunOS calls getuid()                        */
+#define __NR_getegid             50 /* SunOS calls getgid()                        */
+#define __NR_acct                51 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getgid32            53 /* Linux sparc32 specific                      */
+#else
+#define __NR_memory_ordering    52 /* Linux Specific                              */
+#endif
+#define __NR_ioctl               54 /* Common                                      */
+#define __NR_reboot              55 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_mmap2              56 /* Linux sparc32 Specific                      */
+#endif
+#define __NR_symlink             57 /* Common                                      */
+#define __NR_readlink            58 /* Common                                      */
+#define __NR_execve              59 /* Common                                      */
+#define __NR_umask               60 /* Common                                      */
+#define __NR_chroot              61 /* Common                                      */
+#define __NR_fstat               62 /* Common                                      */
+#define __NR_fstat64            63 /* Linux Specific                              */
+#define __NR_getpagesize         64 /* Common                                      */
+#define __NR_msync               65 /* Common in newer 1.3.x revs...               */
+#define __NR_vfork               66 /* Common                                      */
+#define __NR_pread64             67 /* Linux Specific                              */
+#define __NR_pwrite64            68 /* Linux Specific                              */
+#ifdef __32bit_syscall_numbers__
+#define __NR_geteuid32           69 /* Linux sparc32, sbrk under SunOS             */
+#define __NR_getegid32           70 /* Linux sparc32, sstk under SunOS             */
+#endif
+#define __NR_mmap                71 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setreuid32          72 /* Linux sparc32, vadvise under SunOS          */
+#endif
+#define __NR_munmap              73 /* Common                                      */
+#define __NR_mprotect            74 /* Common                                      */
+#define __NR_madvise             75 /* Common                                      */
+#define __NR_vhangup             76 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_truncate64                 77 /* Linux sparc32 Specific                      */
+#endif
+#define __NR_mincore             78 /* Common                                      */
+#define __NR_getgroups           79 /* Common                                      */
+#define __NR_setgroups           80 /* Common                                      */
+#define __NR_getpgrp             81 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setgroups32         82 /* Linux sparc32, setpgrp under SunOS          */
+#endif
+#define __NR_setitimer           83 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_ftruncate64        84 /* Linux sparc32 Specific                      */
+#endif
+#define __NR_swapon              85 /* Common                                      */
+#define __NR_getitimer           86 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setuid32            87 /* Linux sparc32, gethostname under SunOS      */
+#endif
+#define __NR_sethostname         88 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setgid32            89 /* Linux sparc32, getdtablesize under SunOS    */
+#endif
+#define __NR_dup2                90 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setfsuid32          91 /* Linux sparc32, getdopt under SunOS          */
+#endif
+#define __NR_fcntl               92 /* Common                                      */
+#define __NR_select              93 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setfsgid32          94 /* Linux sparc32, setdopt under SunOS          */
+#endif
+#define __NR_fsync               95 /* Common                                      */
+#define __NR_setpriority         96 /* Common                                      */
+#define __NR_socket              97 /* Common                                      */
+#define __NR_connect             98 /* Common                                      */
+#define __NR_accept              99 /* Common                                      */
+#define __NR_getpriority        100 /* Common                                      */
+#define __NR_rt_sigreturn       101 /* Linux Specific                              */
+#define __NR_rt_sigaction       102 /* Linux Specific                              */
+#define __NR_rt_sigprocmask     103 /* Linux Specific                              */
+#define __NR_rt_sigpending      104 /* Linux Specific                              */
+#define __NR_rt_sigtimedwait    105 /* Linux Specific                              */
+#define __NR_rt_sigqueueinfo    106 /* Linux Specific                              */
+#define __NR_rt_sigsuspend      107 /* Linux Specific                              */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setresuid32        108 /* Linux Specific, sigvec under SunOS         */
+#define __NR_getresuid32        109 /* Linux Specific, sigblock under SunOS       */
+#define __NR_setresgid32        110 /* Linux Specific, sigsetmask under SunOS     */
+#define __NR_getresgid32        111 /* Linux Specific, sigpause under SunOS       */
+#define __NR_setregid32         112 /* Linux sparc32, sigstack under SunOS         */
+#else
+#define __NR_setresuid          108 /* Linux Specific, sigvec under SunOS         */
+#define __NR_getresuid          109 /* Linux Specific, sigblock under SunOS       */
+#define __NR_setresgid          110 /* Linux Specific, sigsetmask under SunOS     */
+#define __NR_getresgid          111 /* Linux Specific, sigpause under SunOS       */
+#endif
+#define __NR_recvmsg            113 /* Common                                      */
+#define __NR_sendmsg            114 /* Common                                      */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getgroups32        115 /* Linux sparc32, vtrace under SunOS           */
+#endif
+#define __NR_gettimeofday       116 /* Common                                      */
+#define __NR_getrusage          117 /* Common                                      */
+#define __NR_getsockopt         118 /* Common                                      */
+#define __NR_getcwd            119 /* Linux Specific                              */
+#define __NR_readv              120 /* Common                                      */
+#define __NR_writev             121 /* Common                                      */
+#define __NR_settimeofday       122 /* Common                                      */
+#define __NR_fchown             123 /* Common                                      */
+#define __NR_fchmod             124 /* Common                                      */
+#define __NR_recvfrom           125 /* Common                                      */
+#define __NR_setreuid           126 /* Common                                      */
+#define __NR_setregid           127 /* Common                                      */
+#define __NR_rename             128 /* Common                                      */
+#define __NR_truncate           129 /* Common                                      */
+#define __NR_ftruncate          130 /* Common                                      */
+#define __NR_flock              131 /* Common                                      */
+#define __NR_lstat64           132 /* Linux Specific                              */
+#define __NR_sendto             133 /* Common                                      */
+#define __NR_shutdown           134 /* Common                                      */
+#define __NR_socketpair         135 /* Common                                      */
+#define __NR_mkdir              136 /* Common                                      */
+#define __NR_rmdir              137 /* Common                                      */
+#define __NR_utimes             138 /* SunOS Specific                              */
+#define __NR_stat64            139 /* Linux Specific                              */
+#define __NR_sendfile64         140 /* adjtime under SunOS                         */
+#define __NR_getpeername        141 /* Common                                      */
+#define __NR_futex              142 /* gethostid under SunOS                       */
+#define __NR_gettid             143 /* ENOSYS under SunOS                          */
+#define __NR_getrlimit         144 /* Common                                      */
+#define __NR_setrlimit          145 /* Common                                      */
+#define __NR_pivot_root                146 /* Linux Specific, killpg under SunOS          */
+#define __NR_prctl             147 /* ENOSYS under SunOS                          */
+#define __NR_pciconfig_read    148 /* ENOSYS under SunOS                          */
+#define __NR_pciconfig_write   149 /* ENOSYS under SunOS                          */
+#define __NR_getsockname        150 /* Common                                      */
+#define __NR_inotify_init       151 /* Linux specific                              */
+#define __NR_inotify_add_watch  152 /* Linux specific                              */
+#define __NR_poll               153 /* Common                                      */
+#define __NR_getdents64                154 /* Linux specific                              */
+#ifdef __32bit_syscall_numbers__
+#define __NR_fcntl64           155 /* Linux sparc32 Specific                      */
+#endif
+#define __NR_inotify_rm_watch   156 /* Linux specific                             */
+#define __NR_statfs             157 /* Common                                      */
+#define __NR_fstatfs            158 /* Common                                      */
+#define __NR_umount             159 /* Common                                      */
+#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS    */
+#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS           */
+#define __NR_getdomainname      162 /* SunOS Specific                              */
+#define __NR_setdomainname      163 /* Common                                      */
+#ifndef __32bit_syscall_numbers__
+#define __NR_utrap_install     164 /* SYSV ABI/v9 required                        */
+#endif
+#define __NR_quotactl           165 /* Common                                      */
+#define __NR_set_tid_address    166 /* Linux specific, exportfs under SunOS        */
+#define __NR_mount              167 /* Common                                      */
+#define __NR_ustat              168 /* Common                                      */
+#define __NR_setxattr           169 /* SunOS: semsys                               */
+#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
+#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
+#define __NR_getxattr           172 /* SunOS: auditsys                             */
+#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
+#define __NR_getdents           174 /* Common                                      */
+#define __NR_setsid             175 /* Common                                      */
+#define __NR_fchdir             176 /* Common                                      */
+#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
+#define __NR_listxattr          178 /* SunOS: vpixsys                              */
+#define __NR_llistxattr         179 /* SunOS: aioread                              */
+#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
+#define __NR_removexattr        181 /* SunOS: aiowait                              */
+#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
+#define __NR_sigpending         183 /* Common                                      */
+#define __NR_query_module      184 /* Linux Specific                              */
+#define __NR_setpgid            185 /* Common                                      */
+#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
+#define __NR_tkill              187 /* SunOS: fpathconf                            */
+#define __NR_exit_group                188 /* Linux specific, sysconf undef SunOS         */
+#define __NR_uname              189 /* Linux Specific                              */
+#define __NR_init_module        190 /* Linux Specific                              */
+#define __NR_personality        191 /* Linux Specific                              */
+#define __NR_remap_file_pages   192 /* Linux Specific                              */
+#define __NR_epoll_create       193 /* Linux Specific                              */
+#define __NR_epoll_ctl          194 /* Linux Specific                              */
+#define __NR_epoll_wait         195 /* Linux Specific                              */
+#define __NR_ioprio_set         196 /* Linux Specific                              */
+#define __NR_getppid            197 /* Linux Specific                              */
+#define __NR_sigaction          198 /* Linux Specific                              */
+#define __NR_sgetmask           199 /* Linux Specific                              */
+#define __NR_ssetmask           200 /* Linux Specific                              */
+#define __NR_sigsuspend         201 /* Linux Specific                              */
+#define __NR_oldlstat           202 /* Linux Specific                              */
+#define __NR_uselib             203 /* Linux Specific                              */
+#define __NR_readdir            204 /* Linux Specific                              */
+#define __NR_readahead          205 /* Linux Specific                              */
+#define __NR_socketcall         206 /* Linux Specific                              */
+#define __NR_syslog             207 /* Linux Specific                              */
+#define __NR_lookup_dcookie     208 /* Linux Specific                              */
+#define __NR_fadvise64          209 /* Linux Specific                              */
+#define __NR_fadvise64_64       210 /* Linux Specific                              */
+#define __NR_tgkill             211 /* Linux Specific                              */
+#define __NR_waitpid            212 /* Linux Specific                              */
+#define __NR_swapoff            213 /* Linux Specific                              */
+#define __NR_sysinfo            214 /* Linux Specific                              */
+#define __NR_ipc                215 /* Linux Specific                              */
+#define __NR_sigreturn          216 /* Linux Specific                              */
+#define __NR_clone              217 /* Linux Specific                              */
+#define __NR_ioprio_get         218 /* Linux Specific                              */
+#define __NR_adjtimex           219 /* Linux Specific                              */
+#define __NR_sigprocmask        220 /* Linux Specific                              */
+#define __NR_create_module      221 /* Linux Specific                              */
+#define __NR_delete_module      222 /* Linux Specific                              */
+#define __NR_get_kernel_syms    223 /* Linux Specific                              */
+#define __NR_getpgid            224 /* Linux Specific                              */
+#define __NR_bdflush            225 /* Linux Specific                              */
+#define __NR_sysfs              226 /* Linux Specific                              */
+#define __NR_afs_syscall        227 /* Linux Specific                              */
+#define __NR_setfsuid           228 /* Linux Specific                              */
+#define __NR_setfsgid           229 /* Linux Specific                              */
+#define __NR__newselect         230 /* Linux Specific                              */
+#ifdef __32bit_syscall_numbers__
+#define __NR_time               231 /* Linux Specific                              */
 #else
-#include <asm/unistd_32.h>
+#ifdef __KERNEL__
+#define __NR_time              231 /* Linux sparc32                               */
+#endif
+#endif
+#define __NR_splice             232 /* Linux Specific                              */
+#define __NR_stime              233 /* Linux Specific                              */
+#define __NR_statfs64           234 /* Linux Specific                              */
+#define __NR_fstatfs64          235 /* Linux Specific                              */
+#define __NR__llseek            236 /* Linux Specific                              */
+#define __NR_mlock              237
+#define __NR_munlock            238
+#define __NR_mlockall           239
+#define __NR_munlockall         240
+#define __NR_sched_setparam     241
+#define __NR_sched_getparam     242
+#define __NR_sched_setscheduler 243
+#define __NR_sched_getscheduler 244
+#define __NR_sched_yield        245
+#define __NR_sched_get_priority_max 246
+#define __NR_sched_get_priority_min 247
+#define __NR_sched_rr_get_interval  248
+#define __NR_nanosleep          249
+#define __NR_mremap             250
+#define __NR__sysctl            251
+#define __NR_getsid             252
+#define __NR_fdatasync          253
+#define __NR_nfsservctl         254
+#define __NR_sync_file_range   255
+#define __NR_clock_settime     256
+#define __NR_clock_gettime     257
+#define __NR_clock_getres      258
+#define __NR_clock_nanosleep   259
+#define __NR_sched_getaffinity 260
+#define __NR_sched_setaffinity 261
+#define __NR_timer_settime     262
+#define __NR_timer_gettime     263
+#define __NR_timer_getoverrun  264
+#define __NR_timer_delete      265
+#define __NR_timer_create      266
+/* #define __NR_vserver                267 Reserved for VSERVER */
+#define __NR_io_setup          268
+#define __NR_io_destroy                269
+#define __NR_io_submit         270
+#define __NR_io_cancel         271
+#define __NR_io_getevents      272
+#define __NR_mq_open           273
+#define __NR_mq_unlink         274
+#define __NR_mq_timedsend      275
+#define __NR_mq_timedreceive   276
+#define __NR_mq_notify         277
+#define __NR_mq_getsetattr     278
+#define __NR_waitid            279
+#define __NR_tee               280
+#define __NR_add_key           281
+#define __NR_request_key       282
+#define __NR_keyctl            283
+#define __NR_openat            284
+#define __NR_mkdirat           285
+#define __NR_mknodat           286
+#define __NR_fchownat          287
+#define __NR_futimesat         288
+#define __NR_fstatat64         289
+#define __NR_unlinkat          290
+#define __NR_renameat          291
+#define __NR_linkat            292
+#define __NR_symlinkat         293
+#define __NR_readlinkat                294
+#define __NR_fchmodat          295
+#define __NR_faccessat         296
+#define __NR_pselect6          297
+#define __NR_ppoll             298
+#define __NR_unshare           299
+#define __NR_set_robust_list   300
+#define __NR_get_robust_list   301
+#define __NR_migrate_pages     302
+#define __NR_mbind             303
+#define __NR_get_mempolicy     304
+#define __NR_set_mempolicy     305
+#define __NR_kexec_load                306
+#define __NR_move_pages                307
+#define __NR_getcpu            308
+#define __NR_epoll_pwait       309
+#define __NR_utimensat         310
+#define __NR_signalfd          311
+#define __NR_timerfd_create    312
+#define __NR_eventfd           313
+#define __NR_fallocate         314
+#define __NR_timerfd_settime   315
+#define __NR_timerfd_gettime   316
+#define __NR_signalfd4         317
+#define __NR_eventfd2          318
+#define __NR_epoll_create1     319
+#define __NR_dup3              320
+#define __NR_pipe2             321
+#define __NR_inotify_init1     322
+#define __NR_accept4           323
+
+#define NR_SYSCALLS            324
+
+#ifdef __32bit_syscall_numbers__
+/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
+ * it never had the plain ones and there is no value to adding those
+ * old versions into the syscall table.
+ */
+#define __IGNORE_setresuid
+#define __IGNORE_getresuid
+#define __IGNORE_setresgid
+#define __IGNORE_getresgid
 #endif
+
+#ifdef __KERNEL__
+#define __ARCH_WANT_IPC_PARSE_VERSION
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_SGETMASK
+#define __ARCH_WANT_SYS_SIGNAL
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_WAITPID
+#define __ARCH_WANT_SYS_SOCKETCALL
+#define __ARCH_WANT_SYS_FADVISE64
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __ARCH_WANT_SYS_SIGPENDING
+#define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#ifndef __32bit_syscall_numbers__
+#define __ARCH_WANT_COMPAT_SYS_TIME
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 #endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+
+#endif /* __KERNEL__ */
+#endif /* _SPARC_UNISTD_H */
diff --git a/arch/sparc/include/asm/unistd_32.h b/arch/sparc/include/asm/unistd_32.h
deleted file mode 100644 (file)
index 0d13d2a..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-#ifndef _SPARC_UNISTD_H
-#define _SPARC_UNISTD_H
-
-/*
- * System calls under the Sparc.
- *
- * Don't be scared by the ugly clobbers, it is the only way I can
- * think of right now to force the arguments into fixed registers
- * before the trap into the system call with gcc 'asm' statements.
- *
- * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
- *
- * SunOS compatibility based upon preliminary work which is:
- *
- * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
- */
-
-#define __NR_restart_syscall      0 /* Linux Specific                             */
-#define __NR_exit                 1 /* Common                                      */
-#define __NR_fork                 2 /* Common                                      */
-#define __NR_read                 3 /* Common                                      */
-#define __NR_write                4 /* Common                                      */
-#define __NR_open                 5 /* Common                                      */
-#define __NR_close                6 /* Common                                      */
-#define __NR_wait4                7 /* Common                                      */
-#define __NR_creat                8 /* Common                                      */
-#define __NR_link                 9 /* Common                                      */
-#define __NR_unlink              10 /* Common                                      */
-#define __NR_execv               11 /* SunOS Specific                              */
-#define __NR_chdir               12 /* Common                                      */
-#define __NR_chown              13 /* Common                                      */
-#define __NR_mknod               14 /* Common                                      */
-#define __NR_chmod               15 /* Common                                      */
-#define __NR_lchown              16 /* Common                                      */
-#define __NR_brk                 17 /* Common                                      */
-#define __NR_perfctr             18 /* Performance counter operations              */
-#define __NR_lseek               19 /* Common                                      */
-#define __NR_getpid              20 /* Common                                      */
-#define __NR_capget             21 /* Linux Specific                              */
-#define __NR_capset             22 /* Linux Specific                              */
-#define __NR_setuid              23 /* Implemented via setreuid in SunOS           */
-#define __NR_getuid              24 /* Common                                      */
-#define __NR_vmsplice           25 /* ENOSYS under SunOS                          */
-#define __NR_ptrace              26 /* Common                                      */
-#define __NR_alarm               27 /* Implemented via setitimer in SunOS          */
-#define __NR_sigaltstack        28 /* Common                                      */
-#define __NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
-#define __NR_utime               30 /* Implemented via utimes() under SunOS        */
-#define __NR_lchown32            31 /* Linux sparc32 specific                      */
-#define __NR_fchown32            32 /* Linux sparc32 specific                      */
-#define __NR_access              33 /* Common                                      */
-#define __NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
-#define __NR_chown32             35 /* Linux sparc32 specific                      */
-#define __NR_sync                36 /* Common                                      */
-#define __NR_kill                37 /* Common                                      */
-#define __NR_stat                38 /* Common                                      */
-#define __NR_sendfile           39 /* Linux Specific                              */
-#define __NR_lstat               40 /* Common                                      */
-#define __NR_dup                 41 /* Common                                      */
-#define __NR_pipe                42 /* Common                                      */
-#define __NR_times               43 /* Implemented via getrusage() in SunOS        */
-#define __NR_getuid32            44 /* Linux sparc32 specific                      */
-#define __NR_umount2             45 /* Linux Specific                              */
-#define __NR_setgid              46 /* Implemented via setregid() in SunOS         */
-#define __NR_getgid              47 /* Common                                      */
-#define __NR_signal              48 /* Implemented via sigvec() in SunOS           */
-#define __NR_geteuid             49 /* SunOS calls getuid()                        */
-#define __NR_getegid             50 /* SunOS calls getgid()                        */
-#define __NR_acct                51 /* Common                                      */
-/* #define __NR_memory_ordering  52    Linux sparc64 specific                     */
-#define __NR_getgid32            53 /* Linux sparc32 specific                      */
-#define __NR_ioctl               54 /* Common                                      */
-#define __NR_reboot              55 /* Common                                      */
-#define __NR_mmap2              56 /* Linux sparc32 Specific                      */
-#define __NR_symlink             57 /* Common                                      */
-#define __NR_readlink            58 /* Common                                      */
-#define __NR_execve              59 /* Common                                      */
-#define __NR_umask               60 /* Common                                      */
-#define __NR_chroot              61 /* Common                                      */
-#define __NR_fstat               62 /* Common                                      */
-#define __NR_fstat64            63 /* Linux Specific                              */
-#define __NR_getpagesize         64 /* Common                                      */
-#define __NR_msync               65 /* Common in newer 1.3.x revs...               */
-#define __NR_vfork               66 /* Common                                      */
-#define __NR_pread64             67 /* Linux Specific                              */
-#define __NR_pwrite64            68 /* Linux Specific                              */
-#define __NR_geteuid32           69 /* Linux sparc32, sbrk under SunOS             */
-#define __NR_getegid32           70 /* Linux sparc32, sstk under SunOS             */
-#define __NR_mmap                71 /* Common                                      */
-#define __NR_setreuid32          72 /* Linux sparc32, vadvise under SunOS          */
-#define __NR_munmap              73 /* Common                                      */
-#define __NR_mprotect            74 /* Common                                      */
-#define __NR_madvise             75 /* Common                                      */
-#define __NR_vhangup             76 /* Common                                      */
-#define __NR_truncate64                 77 /* Linux sparc32 Specific                      */
-#define __NR_mincore             78 /* Common                                      */
-#define __NR_getgroups           79 /* Common                                      */
-#define __NR_setgroups           80 /* Common                                      */
-#define __NR_getpgrp             81 /* Common                                      */
-#define __NR_setgroups32         82 /* Linux sparc32, setpgrp under SunOS          */
-#define __NR_setitimer           83 /* Common                                      */
-#define __NR_ftruncate64        84 /* Linux sparc32 Specific                      */
-#define __NR_swapon              85 /* Common                                      */
-#define __NR_getitimer           86 /* Common                                      */
-#define __NR_setuid32            87 /* Linux sparc32, gethostname under SunOS      */
-#define __NR_sethostname         88 /* Common                                      */
-#define __NR_setgid32            89 /* Linux sparc32, getdtablesize under SunOS    */
-#define __NR_dup2                90 /* Common                                      */
-#define __NR_setfsuid32          91 /* Linux sparc32, getdopt under SunOS          */
-#define __NR_fcntl               92 /* Common                                      */
-#define __NR_select              93 /* Common                                      */
-#define __NR_setfsgid32          94 /* Linux sparc32, setdopt under SunOS          */
-#define __NR_fsync               95 /* Common                                      */
-#define __NR_setpriority         96 /* Common                                      */
-#define __NR_socket              97 /* Common                                      */
-#define __NR_connect             98 /* Common                                      */
-#define __NR_accept              99 /* Common                                      */
-#define __NR_getpriority        100 /* Common                                      */
-#define __NR_rt_sigreturn       101 /* Linux Specific                              */
-#define __NR_rt_sigaction       102 /* Linux Specific                              */
-#define __NR_rt_sigprocmask     103 /* Linux Specific                              */
-#define __NR_rt_sigpending      104 /* Linux Specific                              */
-#define __NR_rt_sigtimedwait    105 /* Linux Specific                              */
-#define __NR_rt_sigqueueinfo    106 /* Linux Specific                              */
-#define __NR_rt_sigsuspend      107 /* Linux Specific                              */
-#define __NR_setresuid32        108 /* Linux Specific, sigvec under SunOS         */
-#define __NR_getresuid32        109 /* Linux Specific, sigblock under SunOS       */
-#define __NR_setresgid32        110 /* Linux Specific, sigsetmask under SunOS     */
-#define __NR_getresgid32        111 /* Linux Specific, sigpause under SunOS       */
-#define __NR_setregid32         112 /* Linux sparc32, sigstack under SunOS         */
-#define __NR_recvmsg            113 /* Common                                      */
-#define __NR_sendmsg            114 /* Common                                      */
-#define __NR_getgroups32        115 /* Linux sparc32, vtrace under SunOS           */
-#define __NR_gettimeofday       116 /* Common                                      */
-#define __NR_getrusage          117 /* Common                                      */
-#define __NR_getsockopt         118 /* Common                                      */
-#define __NR_getcwd            119 /* Linux Specific                              */
-#define __NR_readv              120 /* Common                                      */
-#define __NR_writev             121 /* Common                                      */
-#define __NR_settimeofday       122 /* Common                                      */
-#define __NR_fchown             123 /* Common                                      */
-#define __NR_fchmod             124 /* Common                                      */
-#define __NR_recvfrom           125 /* Common                                      */
-#define __NR_setreuid           126 /* Common                                      */
-#define __NR_setregid           127 /* Common                                      */
-#define __NR_rename             128 /* Common                                      */
-#define __NR_truncate           129 /* Common                                      */
-#define __NR_ftruncate          130 /* Common                                      */
-#define __NR_flock              131 /* Common                                      */
-#define __NR_lstat64           132 /* Linux Specific                              */
-#define __NR_sendto             133 /* Common                                      */
-#define __NR_shutdown           134 /* Common                                      */
-#define __NR_socketpair         135 /* Common                                      */
-#define __NR_mkdir              136 /* Common                                      */
-#define __NR_rmdir              137 /* Common                                      */
-#define __NR_utimes             138 /* SunOS Specific                              */
-#define __NR_stat64            139 /* Linux Specific                              */
-#define __NR_sendfile64         140 /* adjtime under SunOS                         */
-#define __NR_getpeername        141 /* Common                                      */
-#define __NR_futex              142 /* gethostid under SunOS                       */
-#define __NR_gettid             143 /* ENOSYS under SunOS                          */
-#define __NR_getrlimit          144 /* Common                                      */
-#define __NR_setrlimit          145 /* Common                                      */
-#define __NR_pivot_root                146 /* Linux Specific, killpg under SunOS          */
-#define __NR_prctl             147 /* ENOSYS under SunOS                          */
-#define __NR_pciconfig_read    148 /* ENOSYS under SunOS                          */
-#define __NR_pciconfig_write   149 /* ENOSYS under SunOS                          */
-#define __NR_getsockname        150 /* Common                                      */
-#define __NR_inotify_init       151 /* Linux specific                              */
-#define __NR_inotify_add_watch  152 /* Linux specific                              */
-#define __NR_poll               153 /* Common                                      */
-#define __NR_getdents64                154 /* Linux specific                              */
-#define __NR_fcntl64           155 /* Linux sparc32 Specific                      */
-#define __NR_inotify_rm_watch   156 /* Linux specific                             */
-#define __NR_statfs             157 /* Common                                      */
-#define __NR_fstatfs            158 /* Common                                      */
-#define __NR_umount             159 /* Common                                      */
-#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS    */
-#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS           */
-#define __NR_getdomainname      162 /* SunOS Specific                              */
-#define __NR_setdomainname      163 /* Common                                      */
-/* #define __NR_utrap_install   164    Linux sparc64 specific                     */
-#define __NR_quotactl           165 /* Common                                      */
-#define __NR_set_tid_address    166 /* Linux specific, exportfs under SunOS        */
-#define __NR_mount              167 /* Common                                      */
-#define __NR_ustat              168 /* Common                                      */
-#define __NR_setxattr           169 /* SunOS: semsys                               */
-#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
-#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
-#define __NR_getxattr           172 /* SunOS: auditsys                             */
-#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
-#define __NR_getdents           174 /* Common                                      */
-#define __NR_setsid             175 /* Common                                      */
-#define __NR_fchdir             176 /* Common                                      */
-#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
-#define __NR_listxattr          178 /* SunOS: vpixsys                              */
-#define __NR_llistxattr         179 /* SunOS: aioread                              */
-#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
-#define __NR_removexattr        181 /* SunOS: aiowait                              */
-#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
-#define __NR_sigpending         183 /* Common                                      */
-#define __NR_query_module      184 /* Linux Specific                              */
-#define __NR_setpgid            185 /* Common                                      */
-#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
-#define __NR_tkill              187 /* SunOS: fpathconf                            */
-#define __NR_exit_group                188 /* Linux specific, sysconf undef SunOS         */
-#define __NR_uname              189 /* Linux Specific                              */
-#define __NR_init_module        190 /* Linux Specific                              */
-#define __NR_personality        191 /* Linux Specific                              */
-#define __NR_remap_file_pages   192 /* Linux Specific                              */
-#define __NR_epoll_create       193 /* Linux Specific                              */
-#define __NR_epoll_ctl          194 /* Linux Specific                              */
-#define __NR_epoll_wait         195 /* Linux Specific                              */
-#define __NR_ioprio_set         196 /* Linux Specific                              */
-#define __NR_getppid            197 /* Linux Specific                              */
-#define __NR_sigaction          198 /* Linux Specific                              */
-#define __NR_sgetmask           199 /* Linux Specific                              */
-#define __NR_ssetmask           200 /* Linux Specific                              */
-#define __NR_sigsuspend         201 /* Linux Specific                              */
-#define __NR_oldlstat           202 /* Linux Specific                              */
-#define __NR_uselib             203 /* Linux Specific                              */
-#define __NR_readdir            204 /* Linux Specific                              */
-#define __NR_readahead          205 /* Linux Specific                              */
-#define __NR_socketcall         206 /* Linux Specific                              */
-#define __NR_syslog             207 /* Linux Specific                              */
-#define __NR_lookup_dcookie     208 /* Linux Specific                              */
-#define __NR_fadvise64          209 /* Linux Specific                              */
-#define __NR_fadvise64_64       210 /* Linux Specific                              */
-#define __NR_tgkill             211 /* Linux Specific                              */
-#define __NR_waitpid            212 /* Linux Specific                              */
-#define __NR_swapoff            213 /* Linux Specific                              */
-#define __NR_sysinfo            214 /* Linux Specific                              */
-#define __NR_ipc                215 /* Linux Specific                              */
-#define __NR_sigreturn          216 /* Linux Specific                              */
-#define __NR_clone              217 /* Linux Specific                              */
-#define __NR_ioprio_get         218 /* Linux Specific                              */
-#define __NR_adjtimex           219 /* Linux Specific                              */
-#define __NR_sigprocmask        220 /* Linux Specific                              */
-#define __NR_create_module      221 /* Linux Specific                              */
-#define __NR_delete_module      222 /* Linux Specific                              */
-#define __NR_get_kernel_syms    223 /* Linux Specific                              */
-#define __NR_getpgid            224 /* Linux Specific                              */
-#define __NR_bdflush            225 /* Linux Specific                              */
-#define __NR_sysfs              226 /* Linux Specific                              */
-#define __NR_afs_syscall        227 /* Linux Specific                              */
-#define __NR_setfsuid           228 /* Linux Specific                              */
-#define __NR_setfsgid           229 /* Linux Specific                              */
-#define __NR__newselect         230 /* Linux Specific                              */
-#define __NR_time               231 /* Linux Specific                              */
-#define __NR_splice             232 /* Linux Specific                              */
-#define __NR_stime              233 /* Linux Specific                              */
-#define __NR_statfs64           234 /* Linux Specific                              */
-#define __NR_fstatfs64          235 /* Linux Specific                              */
-#define __NR__llseek            236 /* Linux Specific                              */
-#define __NR_mlock              237
-#define __NR_munlock            238
-#define __NR_mlockall           239
-#define __NR_munlockall         240
-#define __NR_sched_setparam     241
-#define __NR_sched_getparam     242
-#define __NR_sched_setscheduler 243
-#define __NR_sched_getscheduler 244
-#define __NR_sched_yield        245
-#define __NR_sched_get_priority_max 246
-#define __NR_sched_get_priority_min 247
-#define __NR_sched_rr_get_interval  248
-#define __NR_nanosleep          249
-#define __NR_mremap             250
-#define __NR__sysctl            251
-#define __NR_getsid             252
-#define __NR_fdatasync          253
-#define __NR_nfsservctl         254
-#define __NR_sync_file_range   255
-#define __NR_clock_settime     256
-#define __NR_clock_gettime     257
-#define __NR_clock_getres      258
-#define __NR_clock_nanosleep   259
-#define __NR_sched_getaffinity 260
-#define __NR_sched_setaffinity 261
-#define __NR_timer_settime     262
-#define __NR_timer_gettime     263
-#define __NR_timer_getoverrun  264
-#define __NR_timer_delete      265
-#define __NR_timer_create      266
-/* #define __NR_vserver                267 Reserved for VSERVER */
-#define __NR_io_setup          268
-#define __NR_io_destroy                269
-#define __NR_io_submit         270
-#define __NR_io_cancel         271
-#define __NR_io_getevents      272
-#define __NR_mq_open           273
-#define __NR_mq_unlink         274
-#define __NR_mq_timedsend      275
-#define __NR_mq_timedreceive   276
-#define __NR_mq_notify         277
-#define __NR_mq_getsetattr     278
-#define __NR_waitid            279
-#define __NR_tee               280
-#define __NR_add_key           281
-#define __NR_request_key       282
-#define __NR_keyctl            283
-#define __NR_openat            284
-#define __NR_mkdirat           285
-#define __NR_mknodat           286
-#define __NR_fchownat          287
-#define __NR_futimesat         288
-#define __NR_fstatat64         289
-#define __NR_unlinkat          290
-#define __NR_renameat          291
-#define __NR_linkat            292
-#define __NR_symlinkat         293
-#define __NR_readlinkat                294
-#define __NR_fchmodat          295
-#define __NR_faccessat         296
-#define __NR_pselect6          297
-#define __NR_ppoll             298
-#define __NR_unshare           299
-#define __NR_set_robust_list   300
-#define __NR_get_robust_list   301
-#define __NR_migrate_pages     302
-#define __NR_mbind             303
-#define __NR_get_mempolicy     304
-#define __NR_set_mempolicy     305
-#define __NR_kexec_load                306
-#define __NR_move_pages                307
-#define __NR_getcpu            308
-#define __NR_epoll_pwait       309
-#define __NR_utimensat         310
-#define __NR_signalfd          311
-#define __NR_timerfd_create    312
-#define __NR_eventfd           313
-#define __NR_fallocate         314
-#define __NR_timerfd_settime   315
-#define __NR_timerfd_gettime   316
-#define __NR_signalfd4         317
-#define __NR_eventfd2          318
-#define __NR_epoll_create1     319
-#define __NR_dup3              320
-#define __NR_pipe2             321
-#define __NR_inotify_init1     322
-#define __NR_accept4           323
-
-#define NR_SYSCALLS            324
-
-/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
- * it never had the plain ones and there is no value to adding those
- * old versions into the syscall table.
- */
-#define __IGNORE_setresuid
-#define __IGNORE_getresuid
-#define __IGNORE_setresgid
-#define __IGNORE_getresgid
-
-#ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
-#endif /* __KERNEL__ */
-#endif /* _SPARC_UNISTD_H */
diff --git a/arch/sparc/include/asm/unistd_64.h b/arch/sparc/include/asm/unistd_64.h
deleted file mode 100644 (file)
index fa5d3c0..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-#ifndef _SPARC64_UNISTD_H
-#define _SPARC64_UNISTD_H
-
-/*
- * System calls under the Sparc.
- *
- * Don't be scared by the ugly clobbers, it is the only way I can
- * think of right now to force the arguments into fixed registers
- * before the trap into the system call with gcc 'asm' statements.
- *
- * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
- *
- * SunOS compatibility based upon preliminary work which is:
- *
- * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
- */
-
-#define __NR_restart_syscall      0 /* Linux Specific                             */
-#define __NR_exit                 1 /* Common                                      */
-#define __NR_fork                 2 /* Common                                      */
-#define __NR_read                 3 /* Common                                      */
-#define __NR_write                4 /* Common                                      */
-#define __NR_open                 5 /* Common                                      */
-#define __NR_close                6 /* Common                                      */
-#define __NR_wait4                7 /* Common                                      */
-#define __NR_creat                8 /* Common                                      */
-#define __NR_link                 9 /* Common                                      */
-#define __NR_unlink              10 /* Common                                      */
-#define __NR_execv               11 /* SunOS Specific                              */
-#define __NR_chdir               12 /* Common                                      */
-#define __NR_chown              13 /* Common                                      */
-#define __NR_mknod               14 /* Common                                      */
-#define __NR_chmod               15 /* Common                                      */
-#define __NR_lchown              16 /* Common                                      */
-#define __NR_brk                 17 /* Common                                      */
-#define __NR_perfctr             18 /* Performance counter operations              */
-#define __NR_lseek               19 /* Common                                      */
-#define __NR_getpid              20 /* Common                                      */
-#define __NR_capget             21 /* Linux Specific                              */
-#define __NR_capset             22 /* Linux Specific                              */
-#define __NR_setuid              23 /* Implemented via setreuid in SunOS           */
-#define __NR_getuid              24 /* Common                                      */
-#define __NR_vmsplice           25 /* ENOSYS under SunOS                          */
-#define __NR_ptrace              26 /* Common                                      */
-#define __NR_alarm               27 /* Implemented via setitimer in SunOS          */
-#define __NR_sigaltstack        28 /* Common                                      */
-#define __NR_pause               29 /* Is sigblock(0)->sigpause() in SunOS         */
-#define __NR_utime               30 /* Implemented via utimes() under SunOS        */
-/* #define __NR_lchown32         31    Linux sparc32 specific                      */
-/* #define __NR_fchown32         32    Linux sparc32 specific                      */
-#define __NR_access              33 /* Common                                      */
-#define __NR_nice                34 /* Implemented via get/setpriority() in SunOS  */
-/* #define __NR_chown32          35    Linux sparc32 specific                      */
-#define __NR_sync                36 /* Common                                      */
-#define __NR_kill                37 /* Common                                      */
-#define __NR_stat                38 /* Common                                      */
-#define __NR_sendfile           39 /* Linux Specific                              */
-#define __NR_lstat               40 /* Common                                      */
-#define __NR_dup                 41 /* Common                                      */
-#define __NR_pipe                42 /* Common                                      */
-#define __NR_times               43 /* Implemented via getrusage() in SunOS        */
-/* #define __NR_getuid32         44    Linux sparc32 specific                      */
-#define __NR_umount2             45 /* Linux Specific                              */
-#define __NR_setgid              46 /* Implemented via setregid() in SunOS         */
-#define __NR_getgid              47 /* Common                                      */
-#define __NR_signal              48 /* Implemented via sigvec() in SunOS           */
-#define __NR_geteuid             49 /* SunOS calls getuid()                        */
-#define __NR_getegid             50 /* SunOS calls getgid()                        */
-#define __NR_acct                51 /* Common                                      */
-#define __NR_memory_ordering    52 /* Linux Specific                              */
-/* #define __NR_getgid32         53    Linux sparc32 specific                      */
-#define __NR_ioctl               54 /* Common                                      */
-#define __NR_reboot              55 /* Common                                      */
-/* #define __NR_mmap2           56    Linux sparc32 Specific                      */
-#define __NR_symlink             57 /* Common                                      */
-#define __NR_readlink            58 /* Common                                      */
-#define __NR_execve              59 /* Common                                      */
-#define __NR_umask               60 /* Common                                      */
-#define __NR_chroot              61 /* Common                                      */
-#define __NR_fstat               62 /* Common                                      */
-#define __NR_fstat64             63 /* Linux Specific                              */
-#define __NR_getpagesize         64 /* Common                                      */
-#define __NR_msync               65 /* Common in newer 1.3.x revs...               */
-#define __NR_vfork               66 /* Common                                      */
-#define __NR_pread64             67 /* Linux Specific                              */
-#define __NR_pwrite64            68 /* Linux Specific                              */
-/* #define __NR_geteuid32        69    Linux sparc32, sbrk under SunOS             */
-/* #define __NR_getegid32        70    Linux sparc32, sstk under SunOS             */
-#define __NR_mmap                71 /* Common                                      */
-/* #define __NR_setreuid32       72    Linux sparc32, vadvise under SunOS          */
-#define __NR_munmap              73 /* Common                                      */
-#define __NR_mprotect            74 /* Common                                      */
-#define __NR_madvise             75 /* Common                                      */
-#define __NR_vhangup             76 /* Common                                      */
-/* #define __NR_truncate64       77    Linux sparc32 Specific                     */
-#define __NR_mincore             78 /* Common                                      */
-#define __NR_getgroups           79 /* Common                                      */
-#define __NR_setgroups           80 /* Common                                      */
-#define __NR_getpgrp             81 /* Common                                      */
-/* #define __NR_setgroups32      82    Linux sparc32, setpgrp under SunOS          */
-#define __NR_setitimer           83 /* Common                                      */
-/* #define __NR_ftruncate64      84    Linux sparc32 Specific                     */
-#define __NR_swapon              85 /* Common                                      */
-#define __NR_getitimer           86 /* Common                                      */
-/* #define __NR_setuid32         87    Linux sparc32, gethostname under SunOS      */
-#define __NR_sethostname         88 /* Common                                      */
-/* #define __NR_setgid32         89    Linux sparc32, getdtablesize under SunOS    */
-#define __NR_dup2                90 /* Common                                      */
-/* #define __NR_setfsuid32       91    Linux sparc32, getdopt under SunOS          */
-#define __NR_fcntl               92 /* Common                                      */
-#define __NR_select              93 /* Common                                      */
-/* #define __NR_setfsgid32       94    Linux sparc32, setdopt under SunOS          */
-#define __NR_fsync               95 /* Common                                      */
-#define __NR_setpriority         96 /* Common                                      */
-#define __NR_socket              97 /* Common                                      */
-#define __NR_connect             98 /* Common                                      */
-#define __NR_accept              99 /* Common                                      */
-#define __NR_getpriority        100 /* Common                                      */
-#define __NR_rt_sigreturn       101 /* Linux Specific                              */
-#define __NR_rt_sigaction       102 /* Linux Specific                              */
-#define __NR_rt_sigprocmask     103 /* Linux Specific                              */
-#define __NR_rt_sigpending      104 /* Linux Specific                              */
-#define __NR_rt_sigtimedwait    105 /* Linux Specific                              */
-#define __NR_rt_sigqueueinfo    106 /* Linux Specific                              */
-#define __NR_rt_sigsuspend      107 /* Linux Specific                              */
-#define __NR_setresuid          108 /* Linux Specific, sigvec under SunOS         */
-#define __NR_getresuid          109 /* Linux Specific, sigblock under SunOS       */
-#define __NR_setresgid          110 /* Linux Specific, sigsetmask under SunOS     */
-#define __NR_getresgid          111 /* Linux Specific, sigpause under SunOS       */
-/* #define __NR_setregid32       75    Linux sparc32, sigstack under SunOS         */
-#define __NR_recvmsg            113 /* Common                                      */
-#define __NR_sendmsg            114 /* Common                                      */
-/* #define __NR_getgroups32     115    Linux sparc32, vtrace under SunOS           */
-#define __NR_gettimeofday       116 /* Common                                      */
-#define __NR_getrusage          117 /* Common                                      */
-#define __NR_getsockopt         118 /* Common                                      */
-#define __NR_getcwd            119 /* Linux Specific                              */
-#define __NR_readv              120 /* Common                                      */
-#define __NR_writev             121 /* Common                                      */
-#define __NR_settimeofday       122 /* Common                                      */
-#define __NR_fchown             123 /* Common                                      */
-#define __NR_fchmod             124 /* Common                                      */
-#define __NR_recvfrom           125 /* Common                                      */
-#define __NR_setreuid           126 /* Common                                      */
-#define __NR_setregid           127 /* Common                                      */
-#define __NR_rename             128 /* Common                                      */
-#define __NR_truncate           129 /* Common                                      */
-#define __NR_ftruncate          130 /* Common                                      */
-#define __NR_flock              131 /* Common                                      */
-#define __NR_lstat64           132 /* Linux Specific                              */
-#define __NR_sendto             133 /* Common                                      */
-#define __NR_shutdown           134 /* Common                                      */
-#define __NR_socketpair         135 /* Common                                      */
-#define __NR_mkdir              136 /* Common                                      */
-#define __NR_rmdir              137 /* Common                                      */
-#define __NR_utimes             138 /* SunOS Specific                              */
-#define __NR_stat64            139 /* Linux Specific                              */
-#define __NR_sendfile64         140 /* adjtime under SunOS                         */
-#define __NR_getpeername        141 /* Common                                      */
-#define __NR_futex              142 /* gethostid under SunOS                       */
-#define __NR_gettid             143 /* ENOSYS under SunOS                          */
-#define __NR_getrlimit         144 /* Common                                      */
-#define __NR_setrlimit          145 /* Common                                      */
-#define __NR_pivot_root                146 /* Linux Specific, killpg under SunOS          */
-#define __NR_prctl             147 /* ENOSYS under SunOS                          */
-#define __NR_pciconfig_read    148 /* ENOSYS under SunOS                          */
-#define __NR_pciconfig_write   149 /* ENOSYS under SunOS                          */
-#define __NR_getsockname        150 /* Common                                      */
-#define __NR_inotify_init       151 /* Linux specific                              */
-#define __NR_inotify_add_watch  152 /* Linux specific                              */
-#define __NR_poll               153 /* Common                                      */
-#define __NR_getdents64                154 /* Linux specific                              */
-/* #define __NR_fcntl64         155    Linux sparc32 Specific                      */
-#define __NR_inotify_rm_watch   156 /* Linux specific                             */
-#define __NR_statfs             157 /* Common                                      */
-#define __NR_fstatfs            158 /* Common                                      */
-#define __NR_umount             159 /* Common                                      */
-#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS    */
-#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS           */
-#define __NR_getdomainname      162 /* SunOS Specific                              */
-#define __NR_setdomainname      163 /* Common                                      */
-#define __NR_utrap_install     164 /* SYSV ABI/v9 required                        */
-#define __NR_quotactl           165 /* Common                                      */
-#define __NR_set_tid_address    166 /* Linux specific, exportfs under SunOS        */
-#define __NR_mount              167 /* Common                                      */
-#define __NR_ustat              168 /* Common                                      */
-#define __NR_setxattr           169 /* SunOS: semsys                               */
-#define __NR_lsetxattr          170 /* SunOS: msgsys                               */
-#define __NR_fsetxattr          171 /* SunOS: shmsys                               */
-#define __NR_getxattr           172 /* SunOS: auditsys                             */
-#define __NR_lgetxattr          173 /* SunOS: rfssys                               */
-#define __NR_getdents           174 /* Common                                      */
-#define __NR_setsid             175 /* Common                                      */
-#define __NR_fchdir             176 /* Common                                      */
-#define __NR_fgetxattr          177 /* SunOS: fchroot                              */
-#define __NR_listxattr          178 /* SunOS: vpixsys                              */
-#define __NR_llistxattr         179 /* SunOS: aioread                              */
-#define __NR_flistxattr         180 /* SunOS: aiowrite                             */
-#define __NR_removexattr        181 /* SunOS: aiowait                              */
-#define __NR_lremovexattr       182 /* SunOS: aiocancel                            */
-#define __NR_sigpending         183 /* Common                                      */
-#define __NR_query_module      184 /* Linux Specific                              */
-#define __NR_setpgid            185 /* Common                                      */
-#define __NR_fremovexattr       186 /* SunOS: pathconf                             */
-#define __NR_tkill              187 /* SunOS: fpathconf                            */
-#define __NR_exit_group                188 /* Linux specific, sysconf undef SunOS         */
-#define __NR_uname              189 /* Linux Specific                              */
-#define __NR_init_module        190 /* Linux Specific                              */
-#define __NR_personality        191 /* Linux Specific                              */
-#define __NR_remap_file_pages   192 /* Linux Specific                              */
-#define __NR_epoll_create       193 /* Linux Specific                              */
-#define __NR_epoll_ctl          194 /* Linux Specific                              */
-#define __NR_epoll_wait         195 /* Linux Specific                              */
-#define __NR_ioprio_set         196 /* Linux Specific                              */
-#define __NR_getppid            197 /* Linux Specific                              */
-#define __NR_sigaction          198 /* Linux Specific                              */
-#define __NR_sgetmask           199 /* Linux Specific                              */
-#define __NR_ssetmask           200 /* Linux Specific                              */
-#define __NR_sigsuspend         201 /* Linux Specific                              */
-#define __NR_oldlstat           202 /* Linux Specific                              */
-#define __NR_uselib             203 /* Linux Specific                              */
-#define __NR_readdir            204 /* Linux Specific                              */
-#define __NR_readahead          205 /* Linux Specific                              */
-#define __NR_socketcall         206 /* Linux Specific                              */
-#define __NR_syslog             207 /* Linux Specific                              */
-#define __NR_lookup_dcookie     208 /* Linux Specific                              */
-#define __NR_fadvise64          209 /* Linux Specific                              */
-#define __NR_fadvise64_64       210 /* Linux Specific                              */
-#define __NR_tgkill             211 /* Linux Specific                              */
-#define __NR_waitpid            212 /* Linux Specific                              */
-#define __NR_swapoff            213 /* Linux Specific                              */
-#define __NR_sysinfo            214 /* Linux Specific                              */
-#define __NR_ipc                215 /* Linux Specific                              */
-#define __NR_sigreturn          216 /* Linux Specific                              */
-#define __NR_clone              217 /* Linux Specific                              */
-#define __NR_ioprio_get         218 /* Linux Specific                              */
-#define __NR_adjtimex           219 /* Linux Specific                              */
-#define __NR_sigprocmask        220 /* Linux Specific                              */
-#define __NR_create_module      221 /* Linux Specific                              */
-#define __NR_delete_module      222 /* Linux Specific                              */
-#define __NR_get_kernel_syms    223 /* Linux Specific                              */
-#define __NR_getpgid            224 /* Linux Specific                              */
-#define __NR_bdflush            225 /* Linux Specific                              */
-#define __NR_sysfs              226 /* Linux Specific                              */
-#define __NR_afs_syscall        227 /* Linux Specific                              */
-#define __NR_setfsuid           228 /* Linux Specific                              */
-#define __NR_setfsgid           229 /* Linux Specific                              */
-#define __NR__newselect         230 /* Linux Specific                              */
-#ifdef __KERNEL__
-#define __NR_time              231 /* Linux sparc32                               */
-#endif
-#define __NR_splice             232 /* Linux Specific                              */
-#define __NR_stime              233 /* Linux Specific                              */
-#define __NR_statfs64           234 /* Linux Specific                              */
-#define __NR_fstatfs64          235 /* Linux Specific                              */
-#define __NR__llseek            236 /* Linux Specific                              */
-#define __NR_mlock              237
-#define __NR_munlock            238
-#define __NR_mlockall           239
-#define __NR_munlockall         240
-#define __NR_sched_setparam     241
-#define __NR_sched_getparam     242
-#define __NR_sched_setscheduler 243
-#define __NR_sched_getscheduler 244
-#define __NR_sched_yield        245
-#define __NR_sched_get_priority_max 246
-#define __NR_sched_get_priority_min 247
-#define __NR_sched_rr_get_interval  248
-#define __NR_nanosleep          249
-#define __NR_mremap             250
-#define __NR__sysctl            251
-#define __NR_getsid             252
-#define __NR_fdatasync          253
-#define __NR_nfsservctl         254
-#define __NR_sync_file_range   255
-#define __NR_clock_settime     256
-#define __NR_clock_gettime     257
-#define __NR_clock_getres      258
-#define __NR_clock_nanosleep   259
-#define __NR_sched_getaffinity 260
-#define __NR_sched_setaffinity 261
-#define __NR_timer_settime     262
-#define __NR_timer_gettime     263
-#define __NR_timer_getoverrun  264
-#define __NR_timer_delete      265
-#define __NR_timer_create      266
-/* #define __NR_vserver                267 Reserved for VSERVER */
-#define __NR_io_setup          268
-#define __NR_io_destroy                269
-#define __NR_io_submit         270
-#define __NR_io_cancel         271
-#define __NR_io_getevents      272
-#define __NR_mq_open           273
-#define __NR_mq_unlink         274
-#define __NR_mq_timedsend      275
-#define __NR_mq_timedreceive   276
-#define __NR_mq_notify         277
-#define __NR_mq_getsetattr     278
-#define __NR_waitid            279
-#define __NR_tee               280
-#define __NR_add_key           281
-#define __NR_request_key       282
-#define __NR_keyctl            283
-#define __NR_openat            284
-#define __NR_mkdirat           285
-#define __NR_mknodat           286
-#define __NR_fchownat          287
-#define __NR_futimesat         288
-#define __NR_fstatat64         289
-#define __NR_unlinkat          290
-#define __NR_renameat          291
-#define __NR_linkat            292
-#define __NR_symlinkat         293
-#define __NR_readlinkat                294
-#define __NR_fchmodat          295
-#define __NR_faccessat         296
-#define __NR_pselect6          297
-#define __NR_ppoll             298
-#define __NR_unshare           299
-#define __NR_set_robust_list   300
-#define __NR_get_robust_list   301
-#define __NR_migrate_pages     302
-#define __NR_mbind             303
-#define __NR_get_mempolicy     304
-#define __NR_set_mempolicy     305
-#define __NR_kexec_load                306
-#define __NR_move_pages                307
-#define __NR_getcpu            308
-#define __NR_epoll_pwait       309
-#define __NR_utimensat         310
-#define __NR_signalfd          311
-#define __NR_timerfd_create    312
-#define __NR_eventfd           313
-#define __NR_fallocate         314
-#define __NR_timerfd_settime   315
-#define __NR_timerfd_gettime   316
-#define __NR_signalfd4         317
-#define __NR_eventfd2          318
-#define __NR_epoll_create1     319
-#define __NR_dup3              320
-#define __NR_pipe2             321
-#define __NR_inotify_init1     322
-#define __NR_accept4           323
-
-#define NR_SYSCALLS            324
-
-#ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_COMPAT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
-#endif /* __KERNEL__ */
-#endif /* _SPARC64_UNISTD_H */
diff --git a/arch/sparc/kernel/.gitignore b/arch/sparc/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index 2d658209509943ce5d29fd0d6ebd2553097d4d76..53adcaa0348ba8f50d60c1a7baa1951a858882da 100644 (file)
@@ -2,25 +2,98 @@
 # Makefile for the linux kernel.
 #
 
-extra-y                := head.o init_task.o vmlinux.lds
-
-EXTRA_AFLAGS   := -ansi
-
-IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
-obj-y    := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
-           process.o signal.o ioport.o setup.o idprom.o \
-           sys_sparc.o systbls.o \
-           time.o windows.o cpu.o devices.o \
-           tadpole.o tick14.o ptrace.o \
-           unaligned.o una_asm.o muldiv.o \
-           prom.o of_device.o devres.o dma.o
-
-devres-y = ../../../kernel/irq/devres.o
-
-obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
-obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_SUN_PM) += apc.o pmc.o
-obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
-obj-$(CONFIG_SPARC_LED) += led.o
-obj-$(CONFIG_KGDB) += kgdb.o
+asflags-y := -ansi
+ccflags-y := -Werror
+
+extra-y     := head_$(BITS).o
+extra-y     += init_task.o
+extra-y     += vmlinux.lds
+
+obj-$(CONFIG_SPARC32)   += entry.o wof.o wuf.o
+obj-$(CONFIG_SPARC32)   += etrap_32.o
+obj-$(CONFIG_SPARC32)   += rtrap_32.o
+obj-y                   += traps_$(BITS).o
+
+# IRQ
+obj-y                   += irq_$(BITS).o
+obj-$(CONFIG_SPARC32)   += sun4m_irq.o sun4c_irq.o sun4d_irq.o
+
+obj-y                   += process_$(BITS).o
+obj-y                   += signal_$(BITS).o
+obj-$(CONFIG_SPARC32)   += ioport.o
+obj-y                   += setup_$(BITS).o
+obj-y                   += idprom.o
+obj-y                   += sys_sparc_$(BITS).o
+obj-$(CONFIG_SPARC32)   += systbls_32.o
+obj-y                   += time_$(BITS).o
+obj-$(CONFIG_SPARC32)   += windows.o
+obj-y                   += cpu.o
+obj-$(CONFIG_SPARC32)   += devices.o
+obj-$(CONFIG_SPARC32)   += tadpole.o
+obj-$(CONFIG_SPARC32)   += tick14.o
+obj-y                   += ptrace_$(BITS).o
+obj-y                   += unaligned_$(BITS).o
+obj-y                   += una_asm_$(BITS).o
+obj-$(CONFIG_SPARC32)   += muldiv.o
+obj-y                   += prom_common.o
+obj-y                   += prom_$(BITS).o
+obj-y                   += of_device_$(BITS).o
+obj-$(CONFIG_SPARC64)   += prom_irqtrans.o
+
+obj-$(CONFIG_SPARC64)   += reboot.o
+obj-$(CONFIG_SPARC64)   += sysfs.o
+obj-$(CONFIG_SPARC64)   += iommu.o
+obj-$(CONFIG_SPARC64)   += central.o
+obj-$(CONFIG_SPARC64)   += starfire.o
+obj-$(CONFIG_SPARC64)   += power.o
+obj-$(CONFIG_SPARC64)   += sbus.o
+obj-$(CONFIG_SPARC64)   += ebus.o
+obj-$(CONFIG_SPARC64)   += visemul.o
+obj-$(CONFIG_SPARC64)   += hvapi.o
+obj-$(CONFIG_SPARC64)   += sstate.o
+obj-$(CONFIG_SPARC64)   += mdesc.o
+
+# sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
+obj-$(CONFIG_SPARC32)     += devres.o
+devres-y                  := ../../../kernel/irq/devres.o
+
+obj-$(CONFIG_SPARC32)     += dma.o
+
+obj-$(CONFIG_SPARC32_PCI) += pcic.o
+
+obj-$(CONFIG_SMP)         += trampoline_$(BITS).o smp_$(BITS).o
+obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o
+obj-$(CONFIG_SPARC64_SMP) += hvtramp.o
+
+obj-y                     += auxio_$(BITS).o
+obj-$(CONFIG_SUN_PM)      += apc.o pmc.o
+
+obj-$(CONFIG_MODULES)     += module.o
+obj-$(CONFIG_MODULES)     += sparc_ksyms_$(BITS).o
+obj-$(CONFIG_SPARC_LED)   += led.o
+obj-$(CONFIG_KGDB)        += kgdb_$(BITS).o
+
+
+obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
+CFLAGS_REMOVE_ftrace.o := -pg
+
+obj-$(CONFIG_STACKTRACE)     += stacktrace.o
+# sparc64 PCI
+obj-$(CONFIG_SPARC64_PCI)    += pci.o pci_common.o psycho_common.o
+obj-$(CONFIG_SPARC64_PCI)    += pci_psycho.o pci_sabre.o pci_schizo.o
+obj-$(CONFIG_SPARC64_PCI)    += pci_sun4v.o pci_sun4v_asm.o pci_fire.o
+obj-$(CONFIG_PCI_MSI)        += pci_msi.o
+
+obj-$(CONFIG_COMPAT)         += sys32.o sys_sparc32.o signal32.o
+
+# sparc64 cpufreq
+obj-$(CONFIG_US3_FREQ)  += us3_cpufreq.o
+obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
+obj-$(CONFIG_US3_MC)    += chmc.o
+
+obj-$(CONFIG_KPROBES)   += kprobes.o
+obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
+
+obj-$(CONFIG_AUDIT)     += audit.o
+audit--$(CONFIG_AUDIT)  := compat_audit.o
+obj-$(CONFIG_COMPAT)    += $(audit--y)
index b5bb99ed892cc459b5f38f919750c8e33e87bc13..68f7e1118e9b3a7ab845282e1378304630da87df 100644 (file)
 // #include <linux/mm.h>
 #include <linux/kbuild.h>
 
-int foo(void)
+#ifdef CONFIG_SPARC32
+int sparc32_foo(void)
 {
-       DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
-       BLANK();
        DEFINE(AOFF_thread_fork_kpsr,
                        offsetof(struct thread_struct, fork_kpsr));
+       return 0;
+}
+#else
+int sparc64_foo(void)
+{
+       return 0;
+}
+#endif
+
+int foo(void)
+{
+       BLANK();
+       DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
        BLANK();
        DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context));
 
        /* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */
        return 0;
 }
+
similarity index 67%
rename from arch/sparc64/kernel/auxio.c
rename to arch/sparc/kernel/auxio_64.c
index 858beda86524c96fc7c0dfba4b91736104ff4798..8b67347d4221b42dcf6e6e643b7ec338aac9733a 100644 (file)
@@ -27,73 +27,55 @@ enum auxio_type {
 static enum auxio_type auxio_devtype = AUXIO_TYPE_NODEV;
 static DEFINE_SPINLOCK(auxio_lock);
 
-static void __auxio_sbus_set(u8 bits_on, u8 bits_off)
+static void __auxio_rmw(u8 bits_on, u8 bits_off, int ebus)
 {
        if (auxio_register) {
-               unsigned char regval;
                unsigned long flags;
-               unsigned char newval;
+               u8 regval, newval;
 
                spin_lock_irqsave(&auxio_lock, flags);
 
-               regval =  sbus_readb(auxio_register);
+               regval = (ebus ?
+                         (u8) readl(auxio_register) :
+                         sbus_readb(auxio_register));
                newval =  regval | bits_on;
                newval &= ~bits_off;
-               newval &= ~AUXIO_AUX1_MASK;
-               sbus_writeb(newval, auxio_register);
+               if (!ebus)
+                       newval &= ~AUXIO_AUX1_MASK;
+               if (ebus)
+                       writel((u32) newval, auxio_register);
+               else
+                       sbus_writeb(newval, auxio_register);
                
                spin_unlock_irqrestore(&auxio_lock, flags);
        }
 }
 
-static void __auxio_ebus_set(u8 bits_on, u8 bits_off)
+static void __auxio_set_bit(u8 bit, int on, int ebus)
 {
-       if (auxio_register) {
-               unsigned char regval;
-               unsigned long flags;
-               unsigned char newval;
-
-               spin_lock_irqsave(&auxio_lock, flags);
-
-               regval =  (u8)readl(auxio_register);
-               newval =  regval | bits_on;
-               newval &= ~bits_off;
-               writel((u32)newval, auxio_register);
+       u8 bits_on = (ebus ? AUXIO_PCIO_LED : AUXIO_AUX1_LED);
+       u8 bits_off = 0;
 
-               spin_unlock_irqrestore(&auxio_lock, flags);
+       if (!on) {
+               u8 tmp = bits_off;
+               bits_off = bits_on;
+               bits_on = tmp;
        }
-}
-
-static inline void __auxio_ebus_set_led(int on)
-{
-       (on) ? __auxio_ebus_set(AUXIO_PCIO_LED, 0) :
-               __auxio_ebus_set(0, AUXIO_PCIO_LED) ;
-}
-
-static inline void __auxio_sbus_set_led(int on)
-{
-       (on) ? __auxio_sbus_set(AUXIO_AUX1_LED, 0) :
-               __auxio_sbus_set(0, AUXIO_AUX1_LED) ;
+       __auxio_rmw(bits_on, bits_off, ebus);
 }
 
 void auxio_set_led(int on)
 {
-       switch(auxio_devtype) {
-       case AUXIO_TYPE_SBUS:
-               __auxio_sbus_set_led(on);
-               break;
-       case AUXIO_TYPE_EBUS:
-               __auxio_ebus_set_led(on);
-               break;
-       default:
-               break;
-       }
+       int ebus = auxio_devtype == AUXIO_TYPE_EBUS;
+       u8 bit;
+
+       bit = (ebus ? AUXIO_PCIO_LED : AUXIO_AUX1_LED);
+       __auxio_set_bit(bit, on, ebus);
 }
 
-static inline void __auxio_sbus_set_lte(int on)
+static void __auxio_sbus_set_lte(int on)
 {
-       (on) ? __auxio_sbus_set(AUXIO_AUX1_LTE, 0) : 
-               __auxio_sbus_set(0, AUXIO_AUX1_LTE) ;
+       __auxio_set_bit(AUXIO_AUX1_LTE, on, 0);
 }
 
 void auxio_set_lte(int on)
similarity index 98%
rename from arch/sparc64/kernel/cherrs.S
rename to arch/sparc/kernel/cherrs.S
index 89afebd7eca08ef7f00343a4a4484b699242373f..4ee1ad420862d425cff03ba7aad8e395fcb75907 100644 (file)
@@ -102,7 +102,7 @@ cheetah_plus_dcpe_trap_vector:
        .type           do_cheetah_plus_data_parity,#function
 do_cheetah_plus_data_parity:
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -144,7 +144,7 @@ cheetah_plus_icpe_trap_vector:
        .type           do_cheetah_plus_insn_parity,#function
 do_cheetah_plus_insn_parity:
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -492,7 +492,7 @@ cheetah_fast_ecc:
        .type           c_fast_ecc,#function
 c_fast_ecc:
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -528,7 +528,7 @@ cheetah_cee:
        .type           c_cee,#function
 c_cee:
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -564,7 +564,7 @@ cheetah_deferred_trap:
        .type           c_deferred,#function
 c_deferred:
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        ba,pt           %xcc, etrap_irq
         rd             %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
similarity index 91%
rename from arch/sparc64/kernel/compat_audit.c
rename to arch/sparc/kernel/compat_audit.c
index c831b0a4e660b69d1221230a2d5460db62459fef..d865575b25bf5b2162adfbc293aee40628312888 100644 (file)
@@ -1,4 +1,5 @@
-#include <asm/unistd_32.h>
+#define __32bit_syscall_numbers__
+#include <asm/unistd.h>
 
 unsigned sparc32_dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
index 1fc17f59c6bffc24758d3f44d3e8c71a66f1c8f6..6c2da2420f767d879358c98cfd2e04b3bee06767 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
+
+#include <asm/spitfire.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 #include <asm/head.h>
 #include <asm/mbus.h>
 #include <asm/cpudata.h>
 
+#include "kernel.h"
+
 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 
-struct cpu_iu_info {
-  int psr_impl;
-  int psr_vers;
-  char* cpu_name;   /* should be enough I hope... */
+struct cpu_info {
+       int psr_vers;
+       const char *name;
+};
+
+struct fpu_info {
+       int fp_vers;
+       const char *name;
 };
 
-struct cpu_fp_info {
-  int psr_impl;
-  int fp_vers;
-  char* fp_name;
+#define NOCPU 8
+#define NOFPU 8
+
+struct manufacturer_info {
+       int psr_impl;
+       struct cpu_info cpu_info[NOCPU];
+       struct fpu_info fpu_info[NOFPU];
 };
 
+#define CPU(ver, _name) \
+{ .psr_vers = ver, .name = _name }
+
+#define FPU(ver, _name) \
+{ .fp_vers = ver, .name = _name }
+
+static const struct manufacturer_info __initconst manufacturer_info[] = {
+{
+       0,
+       /* Sun4/100, 4/200, SLC */
+       .cpu_info = {
+               CPU(0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"),
+               /* borned STP1012PGA */
+               CPU(4,  "Fujitsu  MB86904"),
+               CPU(5, "Fujitsu TurboSparc MB86907"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(0, "Fujitsu MB86910 or Weitek WTL1164/5"),
+               FPU(1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"),
+               FPU(2, "LSI Logic L64802 or Texas Instruments ACT8847"),
+               /* SparcStation SLC, SparcStation1 */
+               FPU(3, "Weitek WTL3170/2"),
+               /* SPARCstation-5 */
+               FPU(4, "Lsi Logic/Meiko L64804 or compatible"),
+               FPU(-1, NULL)
+       }
+},{
+       1,
+       .cpu_info = {
+               /* SparcStation2, SparcServer 490 & 690 */
+               CPU(0, "LSI Logic Corporation - L64811"),
+               /* SparcStation2 */
+               CPU(1, "Cypress/ROSS CY7C601"),
+               /* Embedded controller */
+               CPU(3, "Cypress/ROSS CY7C611"),
+               /* Ross Technologies HyperSparc */
+               CPU(0xf, "ROSS HyperSparc RT620"),
+               CPU(0xe, "ROSS HyperSparc RT625 or RT626"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(0, "ROSS HyperSparc combined IU/FPU"),
+               FPU(1, "Lsi Logic L64814"),
+               FPU(2, "Texas Instruments TMS390-C602A"),
+               FPU(3, "Cypress CY7C602 FPU"),
+               FPU(-1, NULL)
+       }
+},{
+       2,
+       .cpu_info = {
+               /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+               /* Someone please write the code to support this beast! ;) */
+               CPU(0, "Bipolar Integrated Technology - B5010"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(-1, NULL)
+       }
+},{
+       3,
+       .cpu_info = {
+               CPU(0, "LSI Logic Corporation - unknown-type"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(-1, NULL)
+       }
+},{
+       4,
+       .cpu_info = {
+               CPU(0, "Texas Instruments, Inc. - SuperSparc-(II)"),
+               /* SparcClassic  --  borned STP1010TAB-50*/
+               CPU(1, "Texas Instruments, Inc. - MicroSparc"),
+               CPU(2, "Texas Instruments, Inc. - MicroSparc II"),
+               CPU(3, "Texas Instruments, Inc. - SuperSparc 51"),
+               CPU(4, "Texas Instruments, Inc. - SuperSparc 61"),
+               CPU(5, "Texas Instruments, Inc. - unknown"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               /* SuperSparc 50 module */
+               FPU(0, "SuperSparc on-chip FPU"),
+               /* SparcClassic */
+               FPU(4, "TI MicroSparc on chip FPU"),
+               FPU(-1, NULL)
+       }
+},{
+       5,
+       .cpu_info = {
+               CPU(0, "Matsushita - MN10501"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(0, "Matsushita MN10501"),
+               FPU(-1, NULL)
+       }
+},{
+       6,
+       .cpu_info = {
+               CPU(0, "Philips Corporation - unknown"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(-1, NULL)
+       }
+},{
+       7,
+       .cpu_info = {
+               CPU(0, "Harvest VLSI Design Center, Inc. - unknown"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(-1, NULL)
+       }
+},{
+       8,
+       .cpu_info = {
+               CPU(0, "Systems and Processes Engineering Corporation (SPEC)"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(-1, NULL)
+       }
+},{
+       9,
+       .cpu_info = {
+               /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
+               CPU(0, "Fujitsu or Weitek Power-UP"),
+               CPU(1, "Fujitsu or Weitek Power-UP"),
+               CPU(2, "Fujitsu or Weitek Power-UP"),
+               CPU(3, "Fujitsu or Weitek Power-UP"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(3, "Fujitsu or Weitek on-chip FPU"),
+               FPU(-1, NULL)
+       }
+},{
+       0x17,
+       .cpu_info = {
+               CPU(0x10, "TI UltraSparc I   (SpitFire)"),
+               CPU(0x11, "TI UltraSparc II  (BlackBird)"),
+               CPU(0x12, "TI UltraSparc IIi (Sabre)"),
+               CPU(0x13, "TI UltraSparc IIe (Hummingbird)"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(0x10, "UltraSparc I integrated FPU"),
+               FPU(0x11, "UltraSparc II integrated FPU"),
+               FPU(0x12, "UltraSparc IIi integrated FPU"),
+               FPU(0x13, "UltraSparc IIe integrated FPU"),
+               FPU(-1, NULL)
+       }
+},{
+       0x22,
+       .cpu_info = {
+               CPU(0x10, "TI UltraSparc I   (SpitFire)"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(0x10, "UltraSparc I integrated FPU"),
+               FPU(-1, NULL)
+       }
+},{
+       0x3e,
+       .cpu_info = {
+               CPU(0x14, "TI UltraSparc III (Cheetah)"),
+               CPU(0x15, "TI UltraSparc III+ (Cheetah+)"),
+               CPU(0x16, "TI UltraSparc IIIi (Jalapeno)"),
+               CPU(0x18, "TI UltraSparc IV (Jaguar)"),
+               CPU(0x19, "TI UltraSparc IV+ (Panther)"),
+               CPU(0x22, "TI UltraSparc IIIi+ (Serrano)"),
+               CPU(-1, NULL)
+       },
+       .fpu_info = {
+               FPU(0x14, "UltraSparc III integrated FPU"),
+               FPU(0x15, "UltraSparc III+ integrated FPU"),
+               FPU(0x16, "UltraSparc IIIi integrated FPU"),
+               FPU(0x18, "UltraSparc IV integrated FPU"),
+               FPU(0x19, "UltraSparc IV+ integrated FPU"),
+               FPU(0x22, "UltraSparc IIIi+ integrated FPU"),
+               FPU(-1, NULL)
+       }
+}};
+
 /* In order to get the fpu type correct, you need to take the IDPROM's
  * machine type value into consideration too.  I will fix this.
  */
-static struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
-  { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
-  { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
-  /* SparcStation SLC, SparcStation1 */
-  { 0, 3, "Weitek WTL3170/2"},
-  /* SPARCstation-5 */
-  { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
-  { 0, 5, "reserved"},
-  { 0, 6, "reserved"},
-  { 0, 7, "No FPU"},
-  { 1, 0, "ROSS HyperSparc combined IU/FPU"},
-  { 1, 1, "Lsi Logic L64814"},
-  { 1, 2, "Texas Instruments TMS390-C602A"},
-  { 1, 3, "Cypress CY7C602 FPU"},
-  { 1, 4, "reserved"},
-  { 1, 5, "reserved"},
-  { 1, 6, "reserved"},
-  { 1, 7, "No FPU"},
-  { 2, 0, "BIT B5010 or B5110/20 or B5210"},
-  { 2, 1, "reserved"},
-  { 2, 2, "reserved"},
-  { 2, 3, "reserved"},
-  { 2, 4, "reserved"},
-  { 2, 5, "reserved"},
-  { 2, 6, "reserved"},
-  { 2, 7, "No FPU"},
-  /* SuperSparc 50 module */
-  { 4, 0, "SuperSparc on-chip FPU"},
-  /* SparcClassic */
-  { 4, 4, "TI MicroSparc on chip FPU"},
-  { 5, 0, "Matsushita MN10501"},
-  { 5, 1, "reserved"},
-  { 5, 2, "reserved"},
-  { 5, 3, "reserved"},
-  { 5, 4, "reserved"},
-  { 5, 5, "reserved"},
-  { 5, 6, "reserved"},
-  { 5, 7, "No FPU"},
-  { 9, 3, "Fujitsu or Weitek on-chip FPU"},
-};
 
-#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
-  /* Sun4/100, 4/200, SLC */
-  { 0, 0, "Fujitsu  MB86900/1A or LSI L64831 SparcKIT-40"},
-  /* borned STP1012PGA */
-  { 0, 4, "Fujitsu  MB86904"},
-  { 0, 5, "Fujitsu TurboSparc MB86907"},
-  /* SparcStation2, SparcServer 490 & 690 */
-  { 1, 0, "LSI Logic Corporation - L64811"},
-  /* SparcStation2 */
-  { 1, 1, "Cypress/ROSS CY7C601"},
-  /* Embedded controller */
-  { 1, 3, "Cypress/ROSS CY7C611"},
-  /* Ross Technologies HyperSparc */
-  { 1, 0xf, "ROSS HyperSparc RT620"},
-  { 1, 0xe, "ROSS HyperSparc RT625 or RT626"},
-  /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
-  /* Someone please write the code to support this beast! ;) */
-  { 2, 0, "Bipolar Integrated Technology - B5010"},
-  { 3, 0, "LSI Logic Corporation - unknown-type"},
-  { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"},
-  /* SparcClassic  --  borned STP1010TAB-50*/
-  { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
-  { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
-  { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
-  { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
-  { 4, 5, "Texas Instruments, Inc. - unknown"},
-  { 5, 0, "Matsushita - MN10501"},
-  { 6, 0, "Philips Corporation - unknown"},
-  { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
-  /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
-  { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
-  { 9, 0, "Fujitsu or Weitek Power-UP"},
-  { 9, 1, "Fujitsu or Weitek Power-UP"},
-  { 9, 2, "Fujitsu or Weitek Power-UP"},
-  { 9, 3, "Fujitsu or Weitek Power-UP"},
-  { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-  { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-};
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
 
-#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
+unsigned int fsr_storage;
 
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+static void set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers)
+{
+       sparc_cpu_type = NULL;
+       sparc_fpu_type = NULL;
+       if (psr_impl < ARRAY_SIZE(manufacturer_info))
+       {
+               const struct cpu_info *cpu;
+               const struct fpu_info *fpu;
 
-unsigned int fsr_storage;
+               cpu = &manufacturer_info[psr_impl].cpu_info[0];
+               while (cpu->psr_vers != -1)
+               {
+                       if (cpu->psr_vers == psr_vers) {
+                               sparc_cpu_type = cpu->name;
+                               sparc_fpu_type = "No FPU";
+                               break;
+                       }
+                       cpu++;
+               }
+               fpu =  &manufacturer_info[psr_impl].fpu_info[0];
+               while (fpu->fp_vers != -1)
+               {
+                       if (fpu->fp_vers == fpu_vers) {
+                               sparc_fpu_type = fpu->name;
+                               break;
+                       }
+                       fpu++;
+               }
+       }
+       if (sparc_cpu_type == NULL)
+       {
+               printk(KERN_ERR "CPU: Unknown chip, impl[0x%x] vers[0x%x]\n",
+                      psr_impl, psr_vers);
+               sparc_cpu_type = "Unknown CPU";
+       }
+       if (sparc_fpu_type == NULL)
+       {
+               printk(KERN_ERR "FPU: Unknown chip, impl[0x%x] vers[0x%x]\n",
+                      psr_impl, fpu_vers);
+               sparc_fpu_type = "Unknown FPU";
+       }
+}
 
+#ifdef CONFIG_SPARC32
 void __cpuinit cpu_probe(void)
 {
        int psr_impl, psr_vers, fpu_vers;
-       int i, psr;
+       int psr;
 
-       psr_impl = ((get_psr()>>28)&0xf);
-       psr_vers = ((get_psr()>>24)&0xf);
+       psr_impl = ((get_psr() >> 28) & 0xf);
+       psr_vers = ((get_psr() >> 24) & 0xf);
 
        psr = get_psr();
        put_psr(psr | PSR_EF);
-       fpu_vers = ((get_fsr()>>17)&0x7);
+       fpu_vers = ((get_fsr() >> 17) & 0x7);
        put_psr(psr);
 
-       for(i = 0; i<NSPARCCHIPS; i++) {
-               if(linux_sparc_chips[i].psr_impl == psr_impl)
-                       if(linux_sparc_chips[i].psr_vers == psr_vers) {
-                               sparc_cpu_type = linux_sparc_chips[i].cpu_name;
-                               break;
-                       }
-       }
+       set_cpu_and_fpu(psr_impl, psr_vers, fpu_vers);
+}
+#else
+static void __init sun4v_cpu_probe(void)
+{
+       switch (sun4v_chip_type) {
+       case SUN4V_CHIP_NIAGARA1:
+               sparc_cpu_type = "UltraSparc T1 (Niagara)";
+               sparc_fpu_type = "UltraSparc T1 integrated FPU";
+               break;
 
-       if(i==NSPARCCHIPS)
-               printk("DEBUG: psr.impl = 0x%x   psr.vers = 0x%x\n", psr_impl, 
-                           psr_vers);
+       case SUN4V_CHIP_NIAGARA2:
+               sparc_cpu_type = "UltraSparc T2 (Niagara2)";
+               sparc_fpu_type = "UltraSparc T2 integrated FPU";
+               break;
 
-       for(i = 0; i<NSPARCFPU; i++) {
-               if(linux_sparc_fpu[i].psr_impl == psr_impl)
-                       if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
-                               sparc_fpu_type = linux_sparc_fpu[i].fp_name;
-                               break;
-                       }
+       default:
+               printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
+                      prom_cpu_compatible);
+               sparc_cpu_type = "Unknown SUN4V CPU";
+               sparc_fpu_type = "Unknown SUN4V FPU";
+               break;
        }
+}
+
+static int __init cpu_type_probe(void)
+{
+       if (tlb_type == hypervisor) {
+               sun4v_cpu_probe();
+       } else {
+               unsigned long ver;
+               int manuf, impl;
 
-       if(i == NSPARCFPU) {
-               printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
-                           fpu_vers);
-               sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+               __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+
+               manuf = ((ver >> 48) & 0xffff);
+               impl = ((ver >> 32) & 0xffff);
+               set_cpu_and_fpu(manuf, impl, impl);
        }
+       return 0;
 }
+
+arch_initcall(cpu_type_probe);
+#endif
index ad656b044b8c2b9a560af4cdfaf2a05e65634f2a..b171ae8de90dc5b49aa410c03c166603c37b4d02 100644 (file)
@@ -133,14 +133,12 @@ void __init device_scan(void)
 #endif /* !CONFIG_SMP */
 
        cpu_probe();
-#ifdef CONFIG_SUN_AUXIO
        {
                extern void auxio_probe(void);
                extern void auxio_power_probe(void);
                auxio_probe();
                auxio_power_probe();
        }
-#endif
        clock_stop_probe();
 
        if (ARCH_SUN4C)
similarity index 79%
rename from arch/sparc64/kernel/entry.h
rename to arch/sparc/kernel/entry.h
index 34d7ab5e10d23c7e0023fa31af791814e341b95d..4f53a2395ac6364ed3f52f8226dc94ecb7e5fc4e 100644 (file)
@@ -5,9 +5,43 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
-extern const char *sparc_cpu_type;
-extern const char *sparc_fpu_type;
+/* irq */
+extern void handler_irq(int irq, struct pt_regs *regs);
 
+#ifdef CONFIG_SPARC32
+/* traps */
+extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type);
+extern void do_illegal_instruction(struct pt_regs *regs, unsigned long pc,
+                                   unsigned long npc, unsigned long psr);
+
+extern void do_priv_instruction(struct pt_regs *regs, unsigned long pc,
+                                unsigned long npc, unsigned long psr);
+extern void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc,
+                                   unsigned long npc,
+                                   unsigned long psr);
+extern void do_fpd_trap(struct pt_regs *regs, unsigned long pc,
+                        unsigned long npc, unsigned long psr);
+extern void do_fpe_trap(struct pt_regs *regs, unsigned long pc,
+                        unsigned long npc, unsigned long psr);
+extern void handle_tag_overflow(struct pt_regs *regs, unsigned long pc,
+                                unsigned long npc, unsigned long psr);
+extern void handle_watchpoint(struct pt_regs *regs, unsigned long pc,
+                              unsigned long npc, unsigned long psr);
+extern void handle_reg_access(struct pt_regs *regs, unsigned long pc,
+                              unsigned long npc, unsigned long psr);
+extern void handle_cp_disabled(struct pt_regs *regs, unsigned long pc,
+                               unsigned long npc, unsigned long psr);
+extern void handle_cp_exception(struct pt_regs *regs, unsigned long pc,
+                                unsigned long npc, unsigned long psr);
+
+
+
+/* entry.S */
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+                   void *fpqueue, unsigned long *fpqdepth);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+#else /* CONFIG_SPARC32 */
 extern void __init per_cpu_patch(void);
 extern void __init sun4v_patch(void);
 extern void __init boot_cpu_id_too_large(int cpu);
@@ -188,8 +222,8 @@ struct ino_bucket {
 extern struct ino_bucket *ivector_table;
 extern unsigned long ivector_table_pa;
 
-extern void handler_irq(int irq, struct pt_regs *regs);
 extern void init_irqwork_curcpu(void);
 extern void __cpuinit sun4v_register_mondo_queues(int this_cpu);
 
+#endif /* CONFIG_SPARC32 */
 #endif /* _ENTRY_H */
similarity index 97%
rename from arch/sparc64/kernel/etrap.S
rename to arch/sparc/kernel/etrap_64.S
index 29ce489bc1889d2b01cf59fc432562098b574e55..786b185e6e3fa8d37e6cac8b820b0654b1b787c3 100644 (file)
@@ -16,9 +16,9 @@
 #include <asm/mmu.h>
 
 #define                TASK_REGOFF             (THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ)
-#define                ETRAP_PSTATE1           (PSTATE_RMO | PSTATE_PRIV)
+#define                ETRAP_PSTATE1           (PSTATE_TSO | PSTATE_PRIV)
 #define                ETRAP_PSTATE2           \
-               (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
+               (PSTATE_TSO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
 
 /*
  * On entry, %g7 is return address - 0x4.
@@ -130,7 +130,7 @@ etrap_save: save    %g2, -STACK_BIAS, %sp
                stx     %g6, [%sp + PTREGS_OFF + PT_V9_G6]
                stx     %g7, [%sp + PTREGS_OFF + PT_V9_G7]
                or      %l7, %l0, %l7
-               sethi   %hi(TSTATE_RMO | TSTATE_PEF), %l0
+               sethi   %hi(TSTATE_TSO | TSTATE_PEF), %l0
                or      %l7, %l0, %l7
                wrpr    %l2, %tnpc
                wrpr    %l7, (TSTATE_PRIV | TSTATE_IE), %tstate
similarity index 99%
rename from arch/sparc/kernel/head.S
rename to arch/sparc/kernel/head_32.S
index 51b40426f9c68e1ba0cde5fd4061c19efa02e9cf..f0b4b516304f48cb1863b1ebda7fafa80a0e5ab7 100644 (file)
@@ -990,7 +990,7 @@ sun4c_continue_boot:
 
                /* Zero out our BSS section. */
                set     __bss_start , %o0       ! First address of BSS
-               set     end , %o1               ! Last address of BSS
+               set     _end , %o1              ! Last address of BSS
                add     %o0, 0x1, %o0
 1:     
                stb     %g0, [%o0]
similarity index 99%
rename from arch/sparc64/kernel/head.S
rename to arch/sparc/kernel/head_64.S
index 353226fa023991240653fadf8504b958dc4529ae..8ffee714f932a026fdeea5d2c2973dbcd724bdb0 100644 (file)
@@ -706,7 +706,7 @@ setup_trap_table:
        andn    %l0, PSTATE_IE, %o1
        wrpr    %o1, 0x0, %pstate
        rdpr    %pil, %l1
-       wrpr    %g0, 15, %pil
+       wrpr    %g0, PIL_NORMAL_MAX, %pil
 
        /* Make the firmware call to jump over to the Linux trap table.  */
        sethi   %hi(is_sun4v), %o0
@@ -825,8 +825,8 @@ setup_tba:
         restore
 sparc64_boot_end:
 
-#include "etrap.S"
-#include "rtrap.S"
+#include "etrap_64.S"
+#include "rtrap_64.S"
 #include "winfixup.S"
 #include "fpu_traps.S"
 #include "ivec.S"
@@ -882,7 +882,7 @@ swapper_4m_tsb:
 
 ! 0x0000000000428000
 
-#include "systbls.S"
+#include "systbls_64.S"
 
        .data
        .align  8
similarity index 96%
rename from arch/sparc64/kernel/hvcalls.S
rename to arch/sparc/kernel/hvcalls.S
index e066269d1594191c00c9405e21b8eb24ae915a3d..8a5f35ffb15ef622ddc9a0e8ecdc5c2a26142c01 100644 (file)
@@ -766,3 +766,35 @@ ENTRY(sun4v_mmu_demap_all)
        retl
         nop
 ENDPROC(sun4v_mmu_demap_all)
+
+ENTRY(sun4v_niagara_getperf)
+       mov     %o0, %o4
+       mov     HV_FAST_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+        nop
+ENDPROC(sun4v_niagara_getperf)
+
+ENTRY(sun4v_niagara_setperf)
+       mov     HV_FAST_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+        nop
+ENDPROC(sun4v_niagara_setperf)
+
+ENTRY(sun4v_niagara2_getperf)
+       mov     %o0, %o4
+       mov     HV_FAST_N2_GET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       stx     %o1, [%o4]
+       retl
+        nop
+ENDPROC(sun4v_niagara2_getperf)
+
+ENTRY(sun4v_niagara2_setperf)
+       mov     HV_FAST_N2_SET_PERFREG, %o5
+       ta      HV_FAST_TRAP
+       retl
+        nop
+ENDPROC(sun4v_niagara2_setperf)
similarity index 95%
rename from arch/sparc64/kernel/hvtramp.S
rename to arch/sparc/kernel/hvtramp.S
index 0236c43772faf50385fd5348fb4f16d34dfcc98b..9365432904d64eb7ef017506991eab7bcbea4f2f 100644 (file)
@@ -1,6 +1,6 @@
 /* hvtramp.S: Hypervisor start-cpu trampoline code.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/init.h>
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/head.h>
 #include <asm/asi.h>
+#include <asm/pil.h>
 
        __CPUINIT
        .align          8
@@ -32,7 +33,7 @@
         */
 hv_cpu_startup:
        SET_GL(0)
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        wrpr            %g0, 0, %canrestore
        wrpr            %g0, 0, %otherwin
        wrpr            %g0, 6, %cansave
index 223a6582e1e208c70e622c61443196c1d5de9a61..c16135e0c151bea8337c605d391b5fbf6828c0b1 100644 (file)
 
 #include <asm/oplib.h>
 #include <asm/idprom.h>
-#include <asm/machines.h>  /* Fun with Sun released architectures. */
 
 struct idprom *idprom;
 static struct idprom idprom_buffer;
 
+#ifdef CONFIG_SPARC32
+#include <asm/machines.h>  /* Fun with Sun released architectures. */
+
 /* Here is the master table of Sun machines which use some implementation
  * of the Sparc CPU and have a meaningful IDPROM machtype value that we
  * know about.  See asm-sparc/machines.h for empirical constants.
  */
 static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
 /* First, Sun4's */
-{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
-{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
-{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
-{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+{ .name = "Sun 4/100 Series",        .id_machtype = (SM_SUN4 | SM_4_110) },
+{ .name = "Sun 4/200 Series",        .id_machtype = (SM_SUN4 | SM_4_260) },
+{ .name = "Sun 4/300 Series",        .id_machtype = (SM_SUN4 | SM_4_330) },
+{ .name = "Sun 4/400 Series",        .id_machtype = (SM_SUN4 | SM_4_470) },
 /* Now, Sun4c's */
-{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
-{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
-{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
-{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
-{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
-{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
-{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
+{ .name = "Sun4c SparcStation 1",    .id_machtype = (SM_SUN4C | SM_4C_SS1) },
+{ .name = "Sun4c SparcStation IPC",  .id_machtype = (SM_SUN4C | SM_4C_IPC) },
+{ .name = "Sun4c SparcStation 1+",   .id_machtype = (SM_SUN4C | SM_4C_SS1PLUS) },
+{ .name = "Sun4c SparcStation SLC",  .id_machtype = (SM_SUN4C | SM_4C_SLC) },
+{ .name = "Sun4c SparcStation 2",    .id_machtype = (SM_SUN4C | SM_4C_SS2) },
+{ .name = "Sun4c SparcStation ELC",  .id_machtype = (SM_SUN4C | SM_4C_ELC) },
+{ .name = "Sun4c SparcStation IPX",  .id_machtype = (SM_SUN4C | SM_4C_IPX) },
 /* Finally, early Sun4m's */
-{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
-{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) },
-{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
+{ .name = "Sun4m SparcSystem600",    .id_machtype = (SM_SUN4M | SM_4M_SS60) },
+{ .name = "Sun4m SparcStation10/20", .id_machtype = (SM_SUN4M | SM_4M_SS50) },
+{ .name = "Sun4m SparcStation5",     .id_machtype = (SM_SUN4M | SM_4M_SS40) },
 /* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
-{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
+{ .name = "Sun4M OBP based system",  .id_machtype = (SM_SUN4M_OBP | 0x0) } };
 
 static void __init display_system_type(unsigned char machtype)
 {
@@ -47,21 +49,25 @@ static void __init display_system_type(unsigned char machtype)
        register int i;
 
        for (i = 0; i < NUM_SUN_MACHINES; i++) {
-               if(Sun_Machines[i].id_machtype == machtype) {
+               if (Sun_Machines[i].id_machtype == machtype) {
                        if (machtype != (SM_SUN4M_OBP | 0x00) ||
                            prom_getproperty(prom_root_node, "banner-name",
                                             sysname, sizeof(sysname)) <= 0)
-                               printk("TYPE: %s\n", Sun_Machines[i].name);
+                               printk(KERN_WARNING "TYPE: %s\n",
+                                      Sun_Machines[i].name);
                        else
-                               printk("TYPE: %s\n", sysname);
+                               printk(KERN_WARNING "TYPE: %s\n", sysname);
                        return;
                }
        }
 
-       prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
-       prom_halt();
+       prom_printf("IDPROM: Warning, bogus id_machtype value, 0x%x\n", machtype);
 }
-
+#else
+static void __init display_system_type(unsigned char machtype)
+{
+}
+#endif
 /* Calculate the IDPROM checksum (xor of the data bytes). */
 static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
 {
@@ -80,21 +86,14 @@ void __init idprom_init(void)
 
        idprom = &idprom_buffer;
 
-       if (idprom->id_format != 0x01)  {
-               prom_printf("IDPROM: Unknown format type!\n");
-               prom_halt();
-       }
+       if (idprom->id_format != 0x01)
+               prom_printf("IDPROM: Warning, unknown format type!\n");
 
-       if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
-               prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
+       if (idprom->id_cksum != calc_idprom_cksum(idprom))
+               prom_printf("IDPROM: Warning, checksum failure (nvram=%x, calc=%x)!\n",
                            idprom->id_cksum, calc_idprom_cksum(idprom));
-               prom_halt();
-       }
 
        display_system_type(idprom->id_machtype);
 
-       printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
-                   idprom->id_ethaddr[0], idprom->id_ethaddr[1],
-                   idprom->id_ethaddr[2], idprom->id_ethaddr[3],
-                   idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
+       printk(KERN_WARNING "Ethernet address: %pM\n", idprom->id_ethaddr);
 }
index 8e64ebc445ef8c158f8fd594ed424fd24efda6e6..62126e4cec54c53c2572a93d3bf4055fe22ba709 100644 (file)
@@ -23,6 +23,5 @@ EXPORT_SYMBOL(init_task);
  * in etrap.S which assumes it.
  */
 union thread_union init_thread_union
-       __attribute__((section (".text\"\n\t#")))
-       __attribute__((aligned (THREAD_SIZE)))
+       __attribute__((section (".data.init_task")))
        = { INIT_THREAD_INFO(init_task) };
index 4f025b36934b2e53fb833c5e94f9c071fb4efbda..7ce14f05eb484f2fca5eb51f7dc193025de90cfa 100644 (file)
@@ -552,8 +552,8 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
        /* IIep is write-through, not flushing. */
        for_each_sg(sgl, sg, nents, n) {
                BUG_ON(page_address(sg_page(sg)) == NULL);
-               sg->dvma_address = virt_to_phys(sg_virt(sg));
-               sg->dvma_length = sg->length;
+               sg->dma_address = virt_to_phys(sg_virt(sg));
+               sg->dma_length = sg->length;
        }
        return nents;
 }
similarity index 99%
rename from arch/sparc/kernel/irq.c
rename to arch/sparc/kernel/irq_32.c
index 93e1d1c65290b8008aef53d02d4de1f0e24c250a..f3488c45d57a0d7867b9292af1f2a01c2cbc6c56 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 
+#include "kernel.h"
 #include "irq.h"
 
 #ifdef CONFIG_SMP
@@ -592,19 +593,19 @@ EXPORT_SYMBOL(request_irq);
 
 void disable_irq_nosync(unsigned int irq)
 {
-       return __disable_irq(irq);
+       __disable_irq(irq);
 }
 EXPORT_SYMBOL(disable_irq_nosync);
 
 void disable_irq(unsigned int irq)
 {
-       return __disable_irq(irq);
+       __disable_irq(irq);
 }
 EXPORT_SYMBOL(disable_irq);
 
 void enable_irq(unsigned int irq)
 {
-       return __enable_irq(irq);
+       __enable_irq(irq);
 }
 
 EXPORT_SYMBOL(enable_irq);
similarity index 94%
rename from arch/sparc64/kernel/irq.c
rename to arch/sparc/kernel/irq_64.c
index 52fc836f464d979655c330b43b15736fc6c840a2..a3ea2bcb95de6a39ebb7bf297ee2355f507f178c 100644 (file)
@@ -775,6 +775,69 @@ void do_softirq(void)
        local_irq_restore(flags);
 }
 
+static void unhandled_perf_irq(struct pt_regs *regs)
+{
+       unsigned long pcr, pic;
+
+       read_pcr(pcr);
+       read_pic(pic);
+
+       write_pcr(0);
+
+       printk(KERN_EMERG "CPU %d: Got unexpected perf counter IRQ.\n",
+              smp_processor_id());
+       printk(KERN_EMERG "CPU %d: PCR[%016lx] PIC[%016lx]\n",
+              smp_processor_id(), pcr, pic);
+}
+
+/* Almost a direct copy of the powerpc PMC code.  */
+static DEFINE_SPINLOCK(perf_irq_lock);
+static void *perf_irq_owner_caller; /* mostly for debugging */
+static void (*perf_irq)(struct pt_regs *regs) = unhandled_perf_irq;
+
+/* Invoked from level 15 PIL handler in trap table.  */
+void perfctr_irq(int irq, struct pt_regs *regs)
+{
+       clear_softint(1 << irq);
+       perf_irq(regs);
+}
+
+int register_perfctr_intr(void (*handler)(struct pt_regs *))
+{
+       int ret;
+
+       if (!handler)
+               return -EINVAL;
+
+       spin_lock(&perf_irq_lock);
+       if (perf_irq != unhandled_perf_irq) {
+               printk(KERN_WARNING "register_perfctr_intr: "
+                      "perf IRQ busy (reserved by caller %p)\n",
+                      perf_irq_owner_caller);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       perf_irq_owner_caller = __builtin_return_address(0);
+       perf_irq = handler;
+
+       ret = 0;
+out:
+       spin_unlock(&perf_irq_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(register_perfctr_intr);
+
+void release_perfctr_intr(void (*handler)(struct pt_regs *))
+{
+       spin_lock(&perf_irq_lock);
+       perf_irq_owner_caller = NULL;
+       perf_irq = unhandled_perf_irq;
+       spin_unlock(&perf_irq_lock);
+}
+EXPORT_SYMBOL_GPL(release_perfctr_intr);
+
 #ifdef CONFIG_HOTPLUG_CPU
 void fixup_irqs(void)
 {
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
new file mode 100644 (file)
index 0000000..81a972e
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __SPARC_KERNEL_H
+#define __SPARC_KERNEL_H
+
+#include <linux/interrupt.h>
+
+/* cpu.c */
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
+
+extern unsigned int fsr_storage;
+
+#ifdef CONFIG_SPARC32
+/* cpu.c */
+extern void cpu_probe(void);
+
+/* traps_32.c */
+extern void handle_hw_divzero(struct pt_regs *regs, unsigned long pc,
+                              unsigned long npc, unsigned long psr);
+/* muldiv.c */
+extern int do_user_muldiv (struct pt_regs *, unsigned long);
+
+/* irq_32.c */
+extern struct irqaction static_irqaction[];
+extern int static_irq_count;
+extern spinlock_t irq_action_lock;
+
+extern void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs);
+
+#else /* CONFIG_SPARC32 */
+#endif /* CONFIG_SPARC32 */
+#endif /* !(__SPARC_KERNEL_H) */
similarity index 99%
rename from arch/sparc64/kernel/mdesc.c
rename to arch/sparc/kernel/mdesc.c
index dde52bcf5c64e11daa1cd22558238ebd45eb46b9..3c539a6d7c18095a68532221007e2a43dc4aee9d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 
+#include <asm/cpudata.h>
 #include <asm/hypervisor.h>
 #include <asm/mdesc.h>
 #include <asm/prom.h>
index 598682f31ebfd942eec586fc23fd6919ce42d710..90273765e81f95b7d07250fe35dc29cc5d122ecc 100644 (file)
@@ -1,4 +1,4 @@
-/* Kernel module help for sparc32.
+/* Kernel module help for sparc64.
  *
  * Copyright (C) 2001 Rusty Russell.
  * Copyright (C) 2002 David S. Miller.
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include <asm/processor.h>
+#include <asm/spitfire.h>
+
+#ifdef CONFIG_SPARC64
+static void *module_map(unsigned long size)
+{
+       struct vm_struct *area;
+
+       size = PAGE_ALIGN(size);
+       if (!size || size > MODULES_LEN)
+               return NULL;
+
+       area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
+       if (!area)
+               return NULL;
+
+       return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
+}
+
+static char *dot2underscore(char *name)
+{
+       return name;
+}
+#else
+static void *module_map(unsigned long size)
+{
+       return vmalloc(size);
+}
+
+/* Replace references to .func with _Func */
+static char *dot2underscore(char *name)
+{
+       if (name[0] == '.') {
+               name[0] = '_';
+                name[1] = toupper(name[1]);
+       }
+       return name;
+}
+#endif /* CONFIG_SPARC64 */
 
 void *module_alloc(unsigned long size)
 {
@@ -20,7 +62,7 @@ void *module_alloc(unsigned long size)
        if (size == 0)
                return NULL;
 
-       ret = vmalloc(size);
+       ret = module_map(size);
        if (!ret)
                ret = ERR_PTR(-ENOMEM);
        else
@@ -37,16 +79,14 @@ void module_free(struct module *mod, void *module_region)
            table entries. */
 }
 
-/* Make generic code ignore STT_REGISTER dummy undefined symbols,
- * and replace references to .func with _Func
- */
+/* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
 int module_frob_arch_sections(Elf_Ehdr *hdr,
                              Elf_Shdr *sechdrs,
                              char *secstrings,
                              struct module *mod)
 {
        unsigned int symidx;
-       Elf32_Sym *sym;
+       Elf_Sym *sym;
        char *strtab;
        int i;
 
@@ -56,26 +96,23 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
                        return -ENOEXEC;
                }
        }
-       sym = (Elf32_Sym *)sechdrs[symidx].sh_addr;
+       sym = (Elf_Sym *)sechdrs[symidx].sh_addr;
        strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
 
        for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
                if (sym[i].st_shndx == SHN_UNDEF) {
-                       if (ELF32_ST_TYPE(sym[i].st_info) == STT_REGISTER)
+                       if (ELF_ST_TYPE(sym[i].st_info) == STT_REGISTER) {
                                sym[i].st_shndx = SHN_ABS;
-                       else {
+                       else {
                                char *name = strtab + sym[i].st_name;
-                               if (name[0] == '.') {
-                                       name[0] = '_';
-                                       name[1] = toupper(name[1]);
-                               }
+                               dot2underscore(name);
                        }
                }
        }
        return 0;
 }
 
-int apply_relocate(Elf32_Shdr *sechdrs,
+int apply_relocate(Elf_Shdr *sechdrs,
                   const char *strtab,
                   unsigned int symindex,
                   unsigned int relsec,
@@ -86,32 +123,68 @@ int apply_relocate(Elf32_Shdr *sechdrs,
        return -ENOEXEC;
 }
 
-int apply_relocate_add(Elf32_Shdr *sechdrs,
+int apply_relocate_add(Elf_Shdr *sechdrs,
                       const char *strtab,
                       unsigned int symindex,
                       unsigned int relsec,
                       struct module *me)
 {
        unsigned int i;
-       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf32_Sym *sym;
+       Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf_Sym *sym;
        u8 *location;
        u32 *loc32;
 
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               Elf32_Addr v;
+               Elf_Addr v;
 
                /* This is where to make the change */
                location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
                        + rel[i].r_offset;
                loc32 = (u32 *) location;
+
+#ifdef CONFIG_SPARC64
+               BUG_ON(((u64)location >> (u64)32) != (u64)0);
+#endif /* CONFIG_SPARC64 */
+
                /* This is the symbol it is referring to.  Note that all
                   undefined symbols have been resolved.  */
-               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-                       + ELF32_R_SYM(rel[i].r_info);
+               sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+                       + ELF_R_SYM(rel[i].r_info);
                v = sym->st_value + rel[i].r_addend;
 
-               switch (ELF32_R_TYPE(rel[i].r_info)) {
+               switch (ELF_R_TYPE(rel[i].r_info) & 0xff) {
+#ifdef CONFIG_SPARC64
+               case R_SPARC_64:
+                       location[0] = v >> 56;
+                       location[1] = v >> 48;
+                       location[2] = v >> 40;
+                       location[3] = v >> 32;
+                       location[4] = v >> 24;
+                       location[5] = v >> 16;
+                       location[6] = v >>  8;
+                       location[7] = v >>  0;
+                       break;
+
+               case R_SPARC_DISP32:
+                       v -= (Elf_Addr) location;
+                       *loc32 = v;
+                       break;
+
+               case R_SPARC_WDISP19:
+                       v -= (Elf_Addr) location;
+                       *loc32 = (*loc32 & ~0x7ffff) |
+                               ((v >> 2) & 0x7ffff);
+                       break;
+
+               case R_SPARC_OLO10:
+                       *loc32 = (*loc32 & ~0x1fff) |
+                               (((v & 0x3ff) +
+                                 (ELF_R_TYPE(rel[i].r_info) >> 8))
+                                & 0x1fff);
+                       break;
+#endif /* CONFIG_SPARC64 */
+
                case R_SPARC_32:
                case R_SPARC_UA32:
                        location[0] = v >> 24;
@@ -121,13 +194,13 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                        break;
 
                case R_SPARC_WDISP30:
-                       v -= (Elf32_Addr) location;
+                       v -= (Elf_Addr) location;
                        *loc32 = (*loc32 & ~0x3fffffff) |
                                ((v >> 2) & 0x3fffffff);
                        break;
 
                case R_SPARC_WDISP22:
-                       v -= (Elf32_Addr) location;
+                       v -= (Elf_Addr) location;
                        *loc32 = (*loc32 & ~0x3fffff) |
                                ((v >> 2) & 0x3fffff);
                        break;
@@ -144,19 +217,38 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                default:
                        printk(KERN_ERR "module %s: Unknown relocation: %x\n",
                               me->name,
-                              (int) (ELF32_R_TYPE(rel[i].r_info) & 0xff));
+                              (int) (ELF_R_TYPE(rel[i].r_info) & 0xff));
                        return -ENOEXEC;
                };
        }
        return 0;
 }
 
+#ifdef CONFIG_SPARC64
 int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       /* Cheetah's I-cache is fully coherent.  */
+       if (tlb_type == spitfire) {
+               unsigned long va;
+
+               flushw_all();
+               for (va =  0; va < (PAGE_SIZE << 1); va += 32)
+                       spitfire_put_icache_tag(va, 0x0);
+               __asm__ __volatile__("flush %g6");
+       }
+
        return 0;
 }
+#else
+int module_finalize(const Elf_Ehdr *hdr,
+                    const Elf_Shdr *sechdrs,
+                    struct module *me)
+{
+        return 0;
+}
+#endif /* CONFIG_SPARC64 */
 
 void module_arch_cleanup(struct module *mod)
 {
index e352239e72c8f7423a7a70110f52bd8136ca5a2a..ba960c02bb55eedeb3b7c15cdf6e37e59cd8dd58 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+#include "kernel.h"
+
 /* #define DEBUG_MULDIV */
 
 static inline int has_imm13(int insn)
@@ -88,9 +90,6 @@ store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs)
                return (put_user(result, &win->locals[reg - 16]));
        }
 }
-               
-extern void handle_hw_divzero (struct pt_regs *regs, unsigned long pc,
-                              unsigned long npc, unsigned long psr);
 
 /* Should return 0 if mul/div emulation succeeded and SIGILL should
  * not be issued.
similarity index 98%
rename from arch/sparc64/kernel/of_device.c
rename to arch/sparc/kernel/of_device_64.c
index 0f616ae3246c5a9bc4be334f52c2879fead932f2..46e231f7c5ce2c37cf51b6111a0175f9dcc4280e 100644 (file)
@@ -811,20 +811,20 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
 
        irq = of_get_property(dp, "interrupts", &len);
        if (irq) {
-               memcpy(op->irqs, irq, len);
                op->num_irqs = len / 4;
+
+               /* Prevent overrunning the op->irqs[] array.  */
+               if (op->num_irqs > PROMINTR_MAX) {
+                       printk(KERN_WARNING "%s: Too many irqs (%d), "
+                              "limiting to %d.\n",
+                              dp->full_name, op->num_irqs, PROMINTR_MAX);
+                       op->num_irqs = PROMINTR_MAX;
+               }
+               memcpy(op->irqs, irq, op->num_irqs * 4);
        } else {
                op->num_irqs = 0;
        }
 
-       /* Prevent overrunning the op->irqs[] array.  */
-       if (op->num_irqs > PROMINTR_MAX) {
-               printk(KERN_WARNING "%s: Too many irqs (%d), "
-                      "limiting to %d.\n",
-                      dp->full_name, op->num_irqs, PROMINTR_MAX);
-               op->num_irqs = PROMINTR_MAX;
-       }
-
        build_device_resources(op, parent);
        for (i = 0; i < op->num_irqs; i++)
                op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
index 462584e55fba13bff47a39ab03ca533b8797cd05..75ed98be3edfe21bf08bb4eb2d9a39a7fca87945 100644 (file)
@@ -436,7 +436,7 @@ int pcic_present(void)
        return pcic0_up;
 }
 
-static int __init pdev_to_pnode(struct linux_pbm_info *pbm, 
+static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm,
                                    struct pci_dev *pdev)
 {
        struct linux_prom_pci_registers regs[PROMREG_MAX];
index 2afcfab4f11cc011585ddc9901b64da953ed9b87..5e4563d86f191d39c2cf6ab386f233a13a877585 100644 (file)
  */
 
 #define PMC_OBPNAME    "SUNW,pmc"
-#define PMC_DEVNAME "pmc"
+#define PMC_DEVNAME    "pmc"
 
 #define PMC_IDLE_REG   0x00
-#define PMC_IDLE_ON            0x01
+#define PMC_IDLE_ON    0x01
 
 static u8 __iomem *regs;
 
 #define pmc_readb(offs)                (sbus_readb(regs+offs))
-#define pmc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
+#define pmc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
 
-/* 
+/*
  * CPU idle callback function
  * See .../arch/sparc/kernel/process.c
  */
-void pmc_swift_idle(void)
+static void pmc_swift_idle(void)
 {
 #ifdef PMC_DEBUG_LED
-       set_auxio(0x00, AUXIO_LED); 
+       set_auxio(0x00, AUXIO_LED);
 #endif
 
        pmc_writeb(pmc_readb(PMC_IDLE_REG) | PMC_IDLE_ON, PMC_IDLE_REG);
 
 #ifdef PMC_DEBUG_LED
-       set_auxio(AUXIO_LED, 0x00); 
+       set_auxio(AUXIO_LED, 0x00);
 #endif
-} 
+}
 
 static int __devinit pmc_probe(struct of_device *op,
                               const struct of_device_id *match)
@@ -63,7 +63,7 @@ static int __devinit pmc_probe(struct of_device *op,
 
 #ifndef PMC_NO_IDLE
        /* Assign power management IDLE handler */
-       pm_idle = pmc_swift_idle;       
+       pm_idle = pmc_swift_idle;
 #endif
 
        printk(KERN_INFO "%s: power management initialized\n", PMC_DEVNAME);
similarity index 99%
rename from arch/sparc/kernel/process.c
rename to arch/sparc/kernel/process_32.c
index e8c43ffe317ef120d52094122e5cdab86e8b87d9..69d9315f4a93e10797a92ac46ad3006a2dc24f18 100644 (file)
@@ -168,11 +168,9 @@ void machine_restart(char * cmd)
 
 void machine_power_off(void)
 {
-#ifdef CONFIG_SUN_AUXIO
        if (auxio_power_register &&
            (strcmp(of_console_device->type, "serial") || scons_pwroff))
                *auxio_power_register |= AUXIO_POWER_OFF;
-#endif
        machine_halt();
 }
 
diff --git a/arch/sparc/kernel/prom.h b/arch/sparc/kernel/prom.h
new file mode 100644 (file)
index 0000000..bb0f0fd
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __PROM_H
+#define __PROM_H
+
+#include <linux/spinlock.h>
+#include <asm/prom.h>
+
+extern struct device_node *allnodes;   /* temporary while merging */
+extern rwlock_t devtree_lock;  /* temporary while merging */
+
+extern void * prom_early_alloc(unsigned long size);
+extern void irq_trans_init(struct device_node *dp);
+
+extern unsigned int prom_unique_id;
+
+static inline int is_root_node(const struct device_node *dp)
+{
+       if (!dp)
+               return 0;
+
+       return (dp->parent == NULL);
+}
+
+extern char *build_path_component(struct device_node *dp);
+extern void of_console_init(void);
+extern void of_fill_in_cpu_data(void);
+
+extern unsigned int prom_early_allocated;
+
+#endif /* __PROM_H */
similarity index 51%
rename from arch/sparc/kernel/prom.c
rename to arch/sparc/kernel/prom_32.c
index eee5efcfe50eea300a42d43e887bf4a7b5a54c6a..fe43e80772dbf597e201b7badd87521b364c6e53 100644 (file)
 #include <asm/prom.h>
 #include <asm/oplib.h>
 
-extern struct device_node *allnodes;   /* temporary while merging */
+#include "prom.h"
 
-extern rwlock_t devtree_lock;  /* temporary while merging */
-
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
-       struct device_node *np;
-
-       for (np = allnodes; np != 0; np = np->allnext)
-               if (np->node == handle)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
-int of_getintprop_default(struct device_node *np, const char *name, int def)
-{
-       struct property *prop;
-       int len;
-
-       prop = of_find_property(np, name, &len);
-       if (!prop || len != 4)
-               return def;
-
-       return *(int *) prop->value;
-}
-EXPORT_SYMBOL(of_getintprop_default);
-
-DEFINE_MUTEX(of_set_property_mutex);
-EXPORT_SYMBOL(of_set_property_mutex);
-
-int of_set_property(struct device_node *dp, const char *name, void *val, int len)
-{
-       struct property **prevp;
-       void *new_val;
-       int err;
-
-       new_val = kmalloc(len, GFP_KERNEL);
-       if (!new_val)
-               return -ENOMEM;
-
-       memcpy(new_val, val, len);
-
-       err = -ENODEV;
-
-       write_lock(&devtree_lock);
-       prevp = &dp->properties;
-       while (*prevp) {
-               struct property *prop = *prevp;
-
-               if (!strcasecmp(prop->name, name)) {
-                       void *old_val = prop->value;
-                       int ret;
-
-                       mutex_lock(&of_set_property_mutex);
-                       ret = prom_setprop(dp->node, (char *) name, val, len);
-                       mutex_unlock(&of_set_property_mutex);
-
-                       err = -EINVAL;
-                       if (ret >= 0) {
-                               prop->value = new_val;
-                               prop->length = len;
-
-                               if (OF_IS_DYNAMIC(prop))
-                                       kfree(old_val);
-
-                               OF_MARK_DYNAMIC(prop);
-
-                               err = 0;
-                       }
-                       break;
-               }
-               prevp = &(*prevp)->next;
-       }
-       write_unlock(&devtree_lock);
-
-       /* XXX Upate procfs if necessary... */
-
-       return err;
-}
-EXPORT_SYMBOL(of_set_property);
-
-int of_find_in_proplist(const char *list, const char *match, int len)
-{
-       while (len > 0) {
-               int l;
-
-               if (!strcmp(list, match))
-                       return 1;
-               l = strlen(list) + 1;
-               list += l;
-               len -= l;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(of_find_in_proplist);
-
-static unsigned int prom_early_allocated;
-
-static void * __init prom_early_alloc(unsigned long size)
+void * __init prom_early_alloc(unsigned long size)
 {
        void *ret;
 
@@ -138,14 +40,6 @@ static void * __init prom_early_alloc(unsigned long size)
        return ret;
 }
 
-static int is_root_node(const struct device_node *dp)
-{
-       if (!dp)
-               return 0;
-
-       return (dp->parent == NULL);
-}
-
 /* The following routines deal with the black magic of fully naming a
  * node.
  *
@@ -257,7 +151,7 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
        return sparc32_path_component(dp, tmp_buf);
 }
 
-static char * __init build_path_component(struct device_node *dp)
+char * __init build_path_component(struct device_node *dp)
 {
        char tmp_buf[64], *n;
 
@@ -272,164 +166,9 @@ static char * __init build_path_component(struct device_node *dp)
        return n;
 }
 
-static char * __init build_full_name(struct device_node *dp)
-{
-       int len, ourlen, plen;
-       char *n;
-
-       plen = strlen(dp->parent->full_name);
-       ourlen = strlen(dp->path_component_name);
-       len = ourlen + plen + 2;
-
-       n = prom_early_alloc(len);
-       strcpy(n, dp->parent->full_name);
-       if (!is_root_node(dp->parent)) {
-               strcpy(n + plen, "/");
-               plen++;
-       }
-       strcpy(n + plen, dp->path_component_name);
-
-       return n;
-}
-
-static unsigned int unique_id;
-
-static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
-{
-       static struct property *tmp = NULL;
-       struct property *p;
-       int len;
-       const char *name;
-
-       if (tmp) {
-               p = tmp;
-               memset(p, 0, sizeof(*p) + 32);
-               tmp = NULL;
-       } else {
-               p = prom_early_alloc(sizeof(struct property) + 32);
-               p->unique_id = unique_id++;
-       }
-
-       p->name = (char *) (p + 1);
-       if (special_name) {
-               strcpy(p->name, special_name);
-               p->length = special_len;
-               p->value = prom_early_alloc(special_len);
-               memcpy(p->value, special_val, special_len);
-       } else {
-               if (prev == NULL) {
-                       name = prom_firstprop(node, NULL);
-               } else {
-                       name = prom_nextprop(node, prev, NULL);
-               }
-               if (strlen(name) == 0) {
-                       tmp = p;
-                       return NULL;
-               }
-               strcpy(p->name, name);
-               p->length = prom_getproplen(node, p->name);
-               if (p->length <= 0) {
-                       p->length = 0;
-               } else {
-                       p->value = prom_early_alloc(p->length + 1);
-                       len = prom_getproperty(node, p->name, p->value,
-                                              p->length);
-                       if (len <= 0)
-                               p->length = 0;
-                       ((unsigned char *)p->value)[p->length] = '\0';
-               }
-       }
-       return p;
-}
-
-static struct property * __init build_prop_list(phandle node)
-{
-       struct property *head, *tail;
-
-       head = tail = build_one_prop(node, NULL,
-                                    ".node", &node, sizeof(node));
-
-       tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
-       tail = tail->next;
-       while(tail) {
-               tail->next = build_one_prop(node, tail->name,
-                                           NULL, NULL, 0);
-               tail = tail->next;
-       }
-
-       return head;
-}
-
-static char * __init get_one_property(phandle node, char *name)
-{
-       char *buf = "<NULL>";
-       int len;
-
-       len = prom_getproplen(node, name);
-       if (len > 0) {
-               buf = prom_early_alloc(len);
-               len = prom_getproperty(node, name, buf, len);
-       }
-
-       return buf;
-}
-
-static struct device_node * __init create_node(phandle node)
-{
-       struct device_node *dp;
-
-       if (!node)
-               return NULL;
-
-       dp = prom_early_alloc(sizeof(*dp));
-       dp->unique_id = unique_id++;
-
-       kref_init(&dp->kref);
-
-       dp->name = get_one_property(node, "name");
-       dp->type = get_one_property(node, "device_type");
-       dp->node = node;
-
-       /* Build interrupts later... */
-
-       dp->properties = build_prop_list(node);
-
-       return dp;
-}
-
-static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
-{
-       struct device_node *dp;
-
-       dp = create_node(node);
-       if (dp) {
-               *(*nextp) = dp;
-               *nextp = &dp->allnext;
-
-               dp->parent = parent;
-               dp->path_component_name = build_path_component(dp);
-               dp->full_name = build_full_name(dp);
-
-               dp->child = build_tree(dp, prom_getchild(node), nextp);
-
-               dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
-       }
-
-       return dp;
-}
-
-struct device_node *of_console_device;
-EXPORT_SYMBOL(of_console_device);
-
-char *of_console_path;
-EXPORT_SYMBOL(of_console_path);
-
-char *of_console_options;
-EXPORT_SYMBOL(of_console_options);
-
 extern void restore_current(void);
 
-static void __init of_console_init(void)
+void __init of_console_init(void)
 {
        char *msg = "OF stdout device is: %s\n";
        struct device_node *dp;
@@ -547,20 +286,10 @@ static void __init of_console_init(void)
        printk(msg, of_console_path);
 }
 
-void __init prom_build_devicetree(void)
+void __init of_fill_in_cpu_data(void)
 {
-       struct device_node **nextp;
-
-       allnodes = create_node(prom_root_node);
-       allnodes->path_component_name = "";
-       allnodes->full_name = "/";
-
-       nextp = &allnodes->allnext;
-       allnodes->child = build_tree(allnodes,
-                                    prom_getchild(allnodes->node),
-                                    &nextp);
-       of_console_init();
+}
 
-       printk("PROM: Built device tree with %u bytes of memory.\n",
-              prom_early_allocated);
+void __init irq_trans_init(struct device_node *dp)
+{
 }
diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c
new file mode 100644 (file)
index 0000000..edecca7
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ * 
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com 
+ *
+ *  Adapted for sparc64 by David S. Miller davem@davemloft.net
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the 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/types.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/lmb.h>
+#include <linux/of_device.h>
+
+#include <asm/prom.h>
+#include <asm/oplib.h>
+#include <asm/irq.h>
+#include <asm/asi.h>
+#include <asm/upa.h>
+#include <asm/smp.h>
+
+#include "prom.h"
+
+void * __init prom_early_alloc(unsigned long size)
+{
+       unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES);
+       void *ret;
+
+       if (!paddr) {
+               prom_printf("prom_early_alloc(%lu) failed\n");
+               prom_halt();
+       }
+
+       ret = __va(paddr);
+       memset(ret, 0, size);
+       prom_early_allocated += size;
+
+       return ret;
+}
+
+/* The following routines deal with the black magic of fully naming a
+ * node.
+ *
+ * Certain well known named nodes are just the simple name string.
+ *
+ * Actual devices have an address specifier appended to the base name
+ * string, like this "foo@addr".  The "addr" can be in any number of
+ * formats, and the platform plus the type of the node determine the
+ * format and how it is constructed.
+ *
+ * For children of the ROOT node, the naming convention is fixed and
+ * determined by whether this is a sun4u or sun4v system.
+ *
+ * For children of other nodes, it is bus type specific.  So
+ * we walk up the tree until we discover a "device_type" property
+ * we recognize and we go from there.
+ *
+ * As an example, the boot device on my workstation has a full path:
+ *
+ *     /pci@1e,600000/ide@d/disk@0,0:c
+ */
+static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom64_registers *regs;
+       struct property *rprop;
+       u32 high_bits, low_bits, type;
+
+       rprop = of_find_property(dp, "reg", NULL);
+       if (!rprop)
+               return;
+
+       regs = rprop->value;
+       if (!is_root_node(dp->parent)) {
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name,
+                       (unsigned int) (regs->phys_addr >> 32UL),
+                       (unsigned int) (regs->phys_addr & 0xffffffffUL));
+               return;
+       }
+
+       type = regs->phys_addr >> 60UL;
+       high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL;
+       low_bits = (regs->phys_addr & 0xffffffffUL);
+
+       if (type == 0 || type == 8) {
+               const char *prefix = (type == 0) ? "m" : "i";
+
+               if (low_bits)
+                       sprintf(tmp_buf, "%s@%s%x,%x",
+                               dp->name, prefix,
+                               high_bits, low_bits);
+               else
+                       sprintf(tmp_buf, "%s@%s%x",
+                               dp->name,
+                               prefix,
+                               high_bits);
+       } else if (type == 12) {
+               sprintf(tmp_buf, "%s@%x",
+                       dp->name, high_bits);
+       }
+}
+
+static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom64_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       if (!is_root_node(dp->parent)) {
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name,
+                       (unsigned int) (regs->phys_addr >> 32UL),
+                       (unsigned int) (regs->phys_addr & 0xffffffffUL));
+               return;
+       }
+
+       prop = of_find_property(dp, "upa-portid", NULL);
+       if (!prop)
+               prop = of_find_property(dp, "portid", NULL);
+       if (prop) {
+               unsigned long mask = 0xffffffffUL;
+
+               if (tlb_type >= cheetah)
+                       mask = 0x7fffff;
+
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name,
+                       *(u32 *)prop->value,
+                       (unsigned int) (regs->phys_addr & mask));
+       }
+}
+
+/* "name@slot,offset"  */
+static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               regs->which_io,
+               regs->phys_addr);
+}
+
+/* "name@devnum[,func]" */
+static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom_pci_registers *regs;
+       struct property *prop;
+       unsigned int devfn;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+       devfn = (regs->phys_hi >> 8) & 0xff;
+       if (devfn & 0x07) {
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name,
+                       devfn >> 3,
+                       devfn & 0x07);
+       } else {
+               sprintf(tmp_buf, "%s@%x",
+                       dp->name,
+                       devfn >> 3);
+       }
+}
+
+/* "name@UPA_PORTID,offset" */
+static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom64_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       prop = of_find_property(dp, "upa-portid", NULL);
+       if (!prop)
+               return;
+
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               *(u32 *) prop->value,
+               (unsigned int) (regs->phys_addr & 0xffffffffUL));
+}
+
+/* "name@reg" */
+static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct property *prop;
+       u32 *regs;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       sprintf(tmp_buf, "%s@%x", dp->name, *regs);
+}
+
+/* "name@addrhi,addrlo" */
+static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct linux_prom64_registers *regs;
+       struct property *prop;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name,
+               (unsigned int) (regs->phys_addr >> 32UL),
+               (unsigned int) (regs->phys_addr & 0xffffffffUL));
+}
+
+/* "name@bus,addr" */
+static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct property *prop;
+       u32 *regs;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       /* This actually isn't right... should look at the #address-cells
+        * property of the i2c bus node etc. etc.
+        */
+       sprintf(tmp_buf, "%s@%x,%x",
+               dp->name, regs[0], regs[1]);
+}
+
+/* "name@reg0[,reg1]" */
+static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct property *prop;
+       u32 *regs;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       if (prop->length == sizeof(u32) || regs[1] == 1) {
+               sprintf(tmp_buf, "%s@%x",
+                       dp->name, regs[0]);
+       } else {
+               sprintf(tmp_buf, "%s@%x,%x",
+                       dp->name, regs[0], regs[1]);
+       }
+}
+
+/* "name@reg0reg1[,reg2reg3]" */
+static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct property *prop;
+       u32 *regs;
+
+       prop = of_find_property(dp, "reg", NULL);
+       if (!prop)
+               return;
+
+       regs = prop->value;
+
+       if (regs[2] || regs[3]) {
+               sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
+                       dp->name, regs[0], regs[1], regs[2], regs[3]);
+       } else {
+               sprintf(tmp_buf, "%s@%08x%08x",
+                       dp->name, regs[0], regs[1]);
+       }
+}
+
+static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+{
+       struct device_node *parent = dp->parent;
+
+       if (parent != NULL) {
+               if (!strcmp(parent->type, "pci") ||
+                   !strcmp(parent->type, "pciex")) {
+                       pci_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "sbus")) {
+                       sbus_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "upa")) {
+                       upa_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "ebus")) {
+                       ebus_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->name, "usb") ||
+                   !strcmp(parent->name, "hub")) {
+                       usb_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "i2c")) {
+                       i2c_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "firewire")) {
+                       ieee1394_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "virtual-devices")) {
+                       vdev_path_component(dp, tmp_buf);
+                       return;
+               }
+               /* "isa" is handled with platform naming */
+       }
+
+       /* Use platform naming convention.  */
+       if (tlb_type == hypervisor) {
+               sun4v_path_component(dp, tmp_buf);
+               return;
+       } else {
+               sun4u_path_component(dp, tmp_buf);
+       }
+}
+
+char * __init build_path_component(struct device_node *dp)
+{
+       char tmp_buf[64], *n;
+
+       tmp_buf[0] = '\0';
+       __build_path_component(dp, tmp_buf);
+       if (tmp_buf[0] == '\0')
+               strcpy(tmp_buf, dp->name);
+
+       n = prom_early_alloc(strlen(tmp_buf) + 1);
+       strcpy(n, tmp_buf);
+
+       return n;
+}
+
+static const char *get_mid_prop(void)
+{
+       return (tlb_type == spitfire ? "upa-portid" : "portid");
+}
+
+struct device_node *of_find_node_by_cpuid(int cpuid)
+{
+       struct device_node *dp;
+       const char *mid_prop = get_mid_prop();
+
+       for_each_node_by_type(dp, "cpu") {
+               int id = of_getintprop_default(dp, mid_prop, -1);
+               const char *this_mid_prop = mid_prop;
+
+               if (id < 0) {
+                       this_mid_prop = "cpuid";
+                       id = of_getintprop_default(dp, this_mid_prop, -1);
+               }
+
+               if (id < 0) {
+                       prom_printf("OF: Serious problem, cpu lacks "
+                                   "%s property", this_mid_prop);
+                       prom_halt();
+               }
+               if (cpuid == id)
+                       return dp;
+       }
+       return NULL;
+}
+
+void __init of_fill_in_cpu_data(void)
+{
+       struct device_node *dp;
+       const char *mid_prop;
+
+       if (tlb_type == hypervisor)
+               return;
+
+       mid_prop = get_mid_prop();
+       ncpus_probed = 0;
+       for_each_node_by_type(dp, "cpu") {
+               int cpuid = of_getintprop_default(dp, mid_prop, -1);
+               const char *this_mid_prop = mid_prop;
+               struct device_node *portid_parent;
+               int portid = -1;
+
+               portid_parent = NULL;
+               if (cpuid < 0) {
+                       this_mid_prop = "cpuid";
+                       cpuid = of_getintprop_default(dp, this_mid_prop, -1);
+                       if (cpuid >= 0) {
+                               int limit = 2;
+
+                               portid_parent = dp;
+                               while (limit--) {
+                                       portid_parent = portid_parent->parent;
+                                       if (!portid_parent)
+                                               break;
+                                       portid = of_getintprop_default(portid_parent,
+                                                                      "portid", -1);
+                                       if (portid >= 0)
+                                               break;
+                               }
+                       }
+               }
+
+               if (cpuid < 0) {
+                       prom_printf("OF: Serious problem, cpu lacks "
+                                   "%s property", this_mid_prop);
+                       prom_halt();
+               }
+
+               ncpus_probed++;
+
+#ifdef CONFIG_SMP
+               if (cpuid >= NR_CPUS) {
+                       printk(KERN_WARNING "Ignoring CPU %d which is "
+                              ">= NR_CPUS (%d)\n",
+                              cpuid, NR_CPUS);
+                       continue;
+               }
+#else
+               /* On uniprocessor we only want the values for the
+                * real physical cpu the kernel booted onto, however
+                * cpu_data() only has one entry at index 0.
+                */
+               if (cpuid != real_hard_smp_processor_id())
+                       continue;
+               cpuid = 0;
+#endif
+
+               cpu_data(cpuid).clock_tick =
+                       of_getintprop_default(dp, "clock-frequency", 0);
+
+               if (portid_parent) {
+                       cpu_data(cpuid).dcache_size =
+                               of_getintprop_default(dp, "l1-dcache-size",
+                                                     16 * 1024);
+                       cpu_data(cpuid).dcache_line_size =
+                               of_getintprop_default(dp, "l1-dcache-line-size",
+                                                     32);
+                       cpu_data(cpuid).icache_size =
+                               of_getintprop_default(dp, "l1-icache-size",
+                                                     8 * 1024);
+                       cpu_data(cpuid).icache_line_size =
+                               of_getintprop_default(dp, "l1-icache-line-size",
+                                                     32);
+                       cpu_data(cpuid).ecache_size =
+                               of_getintprop_default(dp, "l2-cache-size", 0);
+                       cpu_data(cpuid).ecache_line_size =
+                               of_getintprop_default(dp, "l2-cache-line-size", 0);
+                       if (!cpu_data(cpuid).ecache_size ||
+                           !cpu_data(cpuid).ecache_line_size) {
+                               cpu_data(cpuid).ecache_size =
+                                       of_getintprop_default(portid_parent,
+                                                             "l2-cache-size",
+                                                             (4 * 1024 * 1024));
+                               cpu_data(cpuid).ecache_line_size =
+                                       of_getintprop_default(portid_parent,
+                                                             "l2-cache-line-size", 64);
+                       }
+
+                       cpu_data(cpuid).core_id = portid + 1;
+                       cpu_data(cpuid).proc_id = portid;
+#ifdef CONFIG_SMP
+                       sparc64_multi_core = 1;
+#endif
+               } else {
+                       cpu_data(cpuid).dcache_size =
+                               of_getintprop_default(dp, "dcache-size", 16 * 1024);
+                       cpu_data(cpuid).dcache_line_size =
+                               of_getintprop_default(dp, "dcache-line-size", 32);
+
+                       cpu_data(cpuid).icache_size =
+                               of_getintprop_default(dp, "icache-size", 16 * 1024);
+                       cpu_data(cpuid).icache_line_size =
+                               of_getintprop_default(dp, "icache-line-size", 32);
+
+                       cpu_data(cpuid).ecache_size =
+                               of_getintprop_default(dp, "ecache-size",
+                                                     (4 * 1024 * 1024));
+                       cpu_data(cpuid).ecache_line_size =
+                               of_getintprop_default(dp, "ecache-line-size", 64);
+
+                       cpu_data(cpuid).core_id = 0;
+                       cpu_data(cpuid).proc_id = -1;
+               }
+
+#ifdef CONFIG_SMP
+               cpu_set(cpuid, cpu_present_map);
+               cpu_set(cpuid, cpu_possible_map);
+#endif
+       }
+
+       smp_fill_in_sib_core_maps();
+}
+
+void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       const char *type;
+       phandle node;
+
+       of_console_path = prom_early_alloc(256);
+       if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+               prom_printf("Cannot obtain path of stdout.\n");
+               prom_halt();
+       }
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       node = prom_inst2pkg(prom_stdout);
+       if (!node) {
+               prom_printf("Cannot resolve stdout node from "
+                           "instance %08x.\n", prom_stdout);
+               prom_halt();
+       }
+
+       dp = of_find_node_by_phandle(node);
+       type = of_get_property(dp, "device_type", NULL);
+       if (!type) {
+               prom_printf("Console stdout lacks device_type property.\n");
+               prom_halt();
+       }
+
+       if (strcmp(type, "display") && strcmp(type, "serial")) {
+               prom_printf("Console device_type is neither display "
+                           "nor serial.\n");
+               prom_halt();
+       }
+
+       of_console_device = dp;
+
+       printk(msg, of_console_path);
+}
diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
new file mode 100644 (file)
index 0000000..4e9af59
--- /dev/null
@@ -0,0 +1,326 @@
+/* prom_common.c: OF device tree support common code.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc by David S. Miller davem@davemloft.net
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the 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/module.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <asm/prom.h>
+#include <asm/oplib.h>
+
+#include "prom.h"
+
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+       struct device_node *np;
+
+       for (np = allnodes; np; np = np->allnext)
+               if (np->node == handle)
+                       break;
+
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+int of_getintprop_default(struct device_node *np, const char *name, int def)
+{
+       struct property *prop;
+       int len;
+
+       prop = of_find_property(np, name, &len);
+       if (!prop || len != 4)
+               return def;
+
+       return *(int *) prop->value;
+}
+EXPORT_SYMBOL(of_getintprop_default);
+
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
+int of_set_property(struct device_node *dp, const char *name, void *val, int len)
+{
+       struct property **prevp;
+       void *new_val;
+       int err;
+
+       new_val = kmalloc(len, GFP_KERNEL);
+       if (!new_val)
+               return -ENOMEM;
+
+       memcpy(new_val, val, len);
+
+       err = -ENODEV;
+
+       write_lock(&devtree_lock);
+       prevp = &dp->properties;
+       while (*prevp) {
+               struct property *prop = *prevp;
+
+               if (!strcasecmp(prop->name, name)) {
+                       void *old_val = prop->value;
+                       int ret;
+
+                       mutex_lock(&of_set_property_mutex);
+                       ret = prom_setprop(dp->node, name, val, len);
+                       mutex_unlock(&of_set_property_mutex);
+
+                       err = -EINVAL;
+                       if (ret >= 0) {
+                               prop->value = new_val;
+                               prop->length = len;
+
+                               if (OF_IS_DYNAMIC(prop))
+                                       kfree(old_val);
+
+                               OF_MARK_DYNAMIC(prop);
+
+                               err = 0;
+                       }
+                       break;
+               }
+               prevp = &(*prevp)->next;
+       }
+       write_unlock(&devtree_lock);
+
+       /* XXX Upate procfs if necessary... */
+
+       return err;
+}
+EXPORT_SYMBOL(of_set_property);
+
+int of_find_in_proplist(const char *list, const char *match, int len)
+{
+       while (len > 0) {
+               int l;
+
+               if (!strcmp(list, match))
+                       return 1;
+               l = strlen(list) + 1;
+               list += l;
+               len -= l;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(of_find_in_proplist);
+
+unsigned int prom_unique_id;
+
+static struct property * __init build_one_prop(phandle node, char *prev,
+                                              char *special_name,
+                                              void *special_val,
+                                              int special_len)
+{
+       static struct property *tmp = NULL;
+       struct property *p;
+       const char *name;
+
+       if (tmp) {
+               p = tmp;
+               memset(p, 0, sizeof(*p) + 32);
+               tmp = NULL;
+       } else {
+               p = prom_early_alloc(sizeof(struct property) + 32);
+               p->unique_id = prom_unique_id++;
+       }
+
+       p->name = (char *) (p + 1);
+       if (special_name) {
+               strcpy(p->name, special_name);
+               p->length = special_len;
+               p->value = prom_early_alloc(special_len);
+               memcpy(p->value, special_val, special_len);
+       } else {
+#ifdef CONFIG_SPARC32
+               if (prev == NULL) {
+                       name = prom_firstprop(node, NULL);
+               } else {
+                       name = prom_nextprop(node, prev, NULL);
+               }
+#else
+               if (prev == NULL) {
+                       prom_firstprop(node, p->name);
+               } else {
+                       prom_nextprop(node, prev, p->name);
+               }
+               name = p->name;
+#endif
+               if (strlen(name) == 0) {
+                       tmp = p;
+                       return NULL;
+               }
+#ifdef CONFIG_SPARC32
+               strcpy(p->name, name);
+#endif
+               p->length = prom_getproplen(node, p->name);
+               if (p->length <= 0) {
+                       p->length = 0;
+               } else {
+                       int len;
+
+                       p->value = prom_early_alloc(p->length + 1);
+                       len = prom_getproperty(node, p->name, p->value,
+                                              p->length);
+                       if (len <= 0)
+                               p->length = 0;
+                       ((unsigned char *)p->value)[p->length] = '\0';
+               }
+       }
+       return p;
+}
+
+static struct property * __init build_prop_list(phandle node)
+{
+       struct property *head, *tail;
+
+       head = tail = build_one_prop(node, NULL,
+                                    ".node", &node, sizeof(node));
+
+       tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
+       tail = tail->next;
+       while(tail) {
+               tail->next = build_one_prop(node, tail->name,
+                                           NULL, NULL, 0);
+               tail = tail->next;
+       }
+
+       return head;
+}
+
+static char * __init get_one_property(phandle node, const char *name)
+{
+       char *buf = "<NULL>";
+       int len;
+
+       len = prom_getproplen(node, name);
+       if (len > 0) {
+               buf = prom_early_alloc(len);
+               len = prom_getproperty(node, name, buf, len);
+       }
+
+       return buf;
+}
+
+static struct device_node * __init prom_create_node(phandle node,
+                                                   struct device_node *parent)
+{
+       struct device_node *dp;
+
+       if (!node)
+               return NULL;
+
+       dp = prom_early_alloc(sizeof(*dp));
+       dp->unique_id = prom_unique_id++;
+       dp->parent = parent;
+
+       kref_init(&dp->kref);
+
+       dp->name = get_one_property(node, "name");
+       dp->type = get_one_property(node, "device_type");
+       dp->node = node;
+
+       dp->properties = build_prop_list(node);
+
+       irq_trans_init(dp);
+
+       return dp;
+}
+
+static char * __init build_full_name(struct device_node *dp)
+{
+       int len, ourlen, plen;
+       char *n;
+
+       plen = strlen(dp->parent->full_name);
+       ourlen = strlen(dp->path_component_name);
+       len = ourlen + plen + 2;
+
+       n = prom_early_alloc(len);
+       strcpy(n, dp->parent->full_name);
+       if (!is_root_node(dp->parent)) {
+               strcpy(n + plen, "/");
+               plen++;
+       }
+       strcpy(n + plen, dp->path_component_name);
+
+       return n;
+}
+
+static struct device_node * __init prom_build_tree(struct device_node *parent,
+                                                  phandle node,
+                                                  struct device_node ***nextp)
+{
+       struct device_node *ret = NULL, *prev_sibling = NULL;
+       struct device_node *dp;
+
+       while (1) {
+               dp = prom_create_node(node, parent);
+               if (!dp)
+                       break;
+
+               if (prev_sibling)
+                       prev_sibling->sibling = dp;
+
+               if (!ret)
+                       ret = dp;
+               prev_sibling = dp;
+
+               *(*nextp) = dp;
+               *nextp = &dp->allnext;
+
+               dp->path_component_name = build_path_component(dp);
+               dp->full_name = build_full_name(dp);
+
+               dp->child = prom_build_tree(dp, prom_getchild(node), nextp);
+
+               node = prom_getsibling(node);
+       }
+
+       return ret;
+}
+
+unsigned int prom_early_allocated __initdata;
+
+void __init prom_build_devicetree(void)
+{
+       struct device_node **nextp;
+
+       allnodes = prom_create_node(prom_root_node, NULL);
+       allnodes->path_component_name = "";
+       allnodes->full_name = "/";
+
+       nextp = &allnodes->allnext;
+       allnodes->child = prom_build_tree(allnodes,
+                                         prom_getchild(allnodes->node),
+                                         &nextp);
+       of_console_init();
+
+       printk("PROM: Built device tree with %u bytes of memory.\n",
+              prom_early_allocated);
+
+       of_fill_in_cpu_data();
+}
similarity index 53%
rename from arch/sparc64/kernel/prom.c
rename to arch/sparc/kernel/prom_irqtrans.c
index dbba82f9b142c3e950911bdcb4a0359707b1b5bd..96958c4dce8ee1d531382b18a369cecba5fa5d40 100644 (file)
-/*
- * Procedures for creating, accessing and interpreting the device tree.
- *
- * Paul Mackerras      August 1996.
- * Copyright (C) 1996-2005 Paul Mackerras.
- * 
- *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
- *    {engebret|bergner}@us.ibm.com 
- *
- *  Adapted for sparc64 by David S. Miller davem@davemloft.net
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the 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/types.h>
 #include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/lmb.h>
-#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
-#include <asm/prom.h>
 #include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/irq.h>
-#include <asm/asi.h>
 #include <asm/upa.h>
-#include <asm/smp.h>
-
-extern struct device_node *allnodes;   /* temporary while merging */
-
-extern rwlock_t devtree_lock;  /* temporary while merging */
-
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
-       struct device_node *np;
-
-       for (np = allnodes; np; np = np->allnext)
-               if (np->node == handle)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
-int of_getintprop_default(struct device_node *np, const char *name, int def)
-{
-       struct property *prop;
-       int len;
-
-       prop = of_find_property(np, name, &len);
-       if (!prop || len != 4)
-               return def;
-
-       return *(int *) prop->value;
-}
-EXPORT_SYMBOL(of_getintprop_default);
-
-DEFINE_MUTEX(of_set_property_mutex);
-EXPORT_SYMBOL(of_set_property_mutex);
-
-int of_set_property(struct device_node *dp, const char *name, void *val, int len)
-{
-       struct property **prevp;
-       void *new_val;
-       int err;
-
-       new_val = kmalloc(len, GFP_KERNEL);
-       if (!new_val)
-               return -ENOMEM;
-
-       memcpy(new_val, val, len);
-
-       err = -ENODEV;
-
-       write_lock(&devtree_lock);
-       prevp = &dp->properties;
-       while (*prevp) {
-               struct property *prop = *prevp;
-
-               if (!strcasecmp(prop->name, name)) {
-                       void *old_val = prop->value;
-                       int ret;
-
-                       mutex_lock(&of_set_property_mutex);
-                       ret = prom_setprop(dp->node, name, val, len);
-                       mutex_unlock(&of_set_property_mutex);
-
-                       err = -EINVAL;
-                       if (ret >= 0) {
-                               prop->value = new_val;
-                               prop->length = len;
-
-                               if (OF_IS_DYNAMIC(prop))
-                                       kfree(old_val);
-
-                               OF_MARK_DYNAMIC(prop);
-
-                               err = 0;
-                       }
-                       break;
-               }
-               prevp = &(*prevp)->next;
-       }
-       write_unlock(&devtree_lock);
-
-       /* XXX Upate procfs if necessary... */
 
-       return err;
-}
-EXPORT_SYMBOL(of_set_property);
-
-int of_find_in_proplist(const char *list, const char *match, int len)
-{
-       while (len > 0) {
-               int l;
-
-               if (!strcmp(list, match))
-                       return 1;
-               l = strlen(list) + 1;
-               list += l;
-               len -= l;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(of_find_in_proplist);
-
-static unsigned int prom_early_allocated __initdata;
-
-static void * __init prom_early_alloc(unsigned long size)
-{
-       unsigned long paddr = lmb_alloc(size, SMP_CACHE_BYTES);
-       void *ret;
-
-       if (!paddr) {
-               prom_printf("prom_early_alloc(%lu) failed\n");
-               prom_halt();
-       }
-
-       ret = __va(paddr);
-       memset(ret, 0, size);
-       prom_early_allocated += size;
-
-       return ret;
-}
+#include "prom.h"
 
 #ifdef CONFIG_PCI
 /* PSYCHO interrupt mapping support. */
@@ -936,7 +800,7 @@ static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
                ((regs->phys_addr >> 32UL) & 0x0fffffff);
 }
 
-static void __init irq_trans_init(struct device_node *dp)
+void __init irq_trans_init(struct device_node *dp)
 {
 #ifdef CONFIG_PCI
        const char *model;
@@ -976,709 +840,3 @@ static void __init irq_trans_init(struct device_node *dp)
                return;
        }
 }
-
-static int is_root_node(const struct device_node *dp)
-{
-       if (!dp)
-               return 0;
-
-       return (dp->parent == NULL);
-}
-
-/* The following routines deal with the black magic of fully naming a
- * node.
- *
- * Certain well known named nodes are just the simple name string.
- *
- * Actual devices have an address specifier appended to the base name
- * string, like this "foo@addr".  The "addr" can be in any number of
- * formats, and the platform plus the type of the node determine the
- * format and how it is constructed.
- *
- * For children of the ROOT node, the naming convention is fixed and
- * determined by whether this is a sun4u or sun4v system.
- *
- * For children of other nodes, it is bus type specific.  So
- * we walk up the tree until we discover a "device_type" property
- * we recognize and we go from there.
- *
- * As an example, the boot device on my workstation has a full path:
- *
- *     /pci@1e,600000/ide@d/disk@0,0:c
- */
-static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom64_registers *regs;
-       struct property *rprop;
-       u32 high_bits, low_bits, type;
-
-       rprop = of_find_property(dp, "reg", NULL);
-       if (!rprop)
-               return;
-
-       regs = rprop->value;
-       if (!is_root_node(dp->parent)) {
-               sprintf(tmp_buf, "%s@%x,%x",
-                       dp->name,
-                       (unsigned int) (regs->phys_addr >> 32UL),
-                       (unsigned int) (regs->phys_addr & 0xffffffffUL));
-               return;
-       }
-
-       type = regs->phys_addr >> 60UL;
-       high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL;
-       low_bits = (regs->phys_addr & 0xffffffffUL);
-
-       if (type == 0 || type == 8) {
-               const char *prefix = (type == 0) ? "m" : "i";
-
-               if (low_bits)
-                       sprintf(tmp_buf, "%s@%s%x,%x",
-                               dp->name, prefix,
-                               high_bits, low_bits);
-               else
-                       sprintf(tmp_buf, "%s@%s%x",
-                               dp->name,
-                               prefix,
-                               high_bits);
-       } else if (type == 12) {
-               sprintf(tmp_buf, "%s@%x",
-                       dp->name, high_bits);
-       }
-}
-
-static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom64_registers *regs;
-       struct property *prop;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-       if (!is_root_node(dp->parent)) {
-               sprintf(tmp_buf, "%s@%x,%x",
-                       dp->name,
-                       (unsigned int) (regs->phys_addr >> 32UL),
-                       (unsigned int) (regs->phys_addr & 0xffffffffUL));
-               return;
-       }
-
-       prop = of_find_property(dp, "upa-portid", NULL);
-       if (!prop)
-               prop = of_find_property(dp, "portid", NULL);
-       if (prop) {
-               unsigned long mask = 0xffffffffUL;
-
-               if (tlb_type >= cheetah)
-                       mask = 0x7fffff;
-
-               sprintf(tmp_buf, "%s@%x,%x",
-                       dp->name,
-                       *(u32 *)prop->value,
-                       (unsigned int) (regs->phys_addr & mask));
-       }
-}
-
-/* "name@slot,offset"  */
-static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom_registers *regs;
-       struct property *prop;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name,
-               regs->which_io,
-               regs->phys_addr);
-}
-
-/* "name@devnum[,func]" */
-static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom_pci_registers *regs;
-       struct property *prop;
-       unsigned int devfn;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-       devfn = (regs->phys_hi >> 8) & 0xff;
-       if (devfn & 0x07) {
-               sprintf(tmp_buf, "%s@%x,%x",
-                       dp->name,
-                       devfn >> 3,
-                       devfn & 0x07);
-       } else {
-               sprintf(tmp_buf, "%s@%x",
-                       dp->name,
-                       devfn >> 3);
-       }
-}
-
-/* "name@UPA_PORTID,offset" */
-static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom64_registers *regs;
-       struct property *prop;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       prop = of_find_property(dp, "upa-portid", NULL);
-       if (!prop)
-               return;
-
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name,
-               *(u32 *) prop->value,
-               (unsigned int) (regs->phys_addr & 0xffffffffUL));
-}
-
-/* "name@reg" */
-static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct property *prop;
-       u32 *regs;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       sprintf(tmp_buf, "%s@%x", dp->name, *regs);
-}
-
-/* "name@addrhi,addrlo" */
-static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct linux_prom64_registers *regs;
-       struct property *prop;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name,
-               (unsigned int) (regs->phys_addr >> 32UL),
-               (unsigned int) (regs->phys_addr & 0xffffffffUL));
-}
-
-/* "name@bus,addr" */
-static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct property *prop;
-       u32 *regs;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       /* This actually isn't right... should look at the #address-cells
-        * property of the i2c bus node etc. etc.
-        */
-       sprintf(tmp_buf, "%s@%x,%x",
-               dp->name, regs[0], regs[1]);
-}
-
-/* "name@reg0[,reg1]" */
-static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct property *prop;
-       u32 *regs;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       if (prop->length == sizeof(u32) || regs[1] == 1) {
-               sprintf(tmp_buf, "%s@%x",
-                       dp->name, regs[0]);
-       } else {
-               sprintf(tmp_buf, "%s@%x,%x",
-                       dp->name, regs[0], regs[1]);
-       }
-}
-
-/* "name@reg0reg1[,reg2reg3]" */
-static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct property *prop;
-       u32 *regs;
-
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop)
-               return;
-
-       regs = prop->value;
-
-       if (regs[2] || regs[3]) {
-               sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
-                       dp->name, regs[0], regs[1], regs[2], regs[3]);
-       } else {
-               sprintf(tmp_buf, "%s@%08x%08x",
-                       dp->name, regs[0], regs[1]);
-       }
-}
-
-static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
-{
-       struct device_node *parent = dp->parent;
-
-       if (parent != NULL) {
-               if (!strcmp(parent->type, "pci") ||
-                   !strcmp(parent->type, "pciex")) {
-                       pci_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->type, "sbus")) {
-                       sbus_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->type, "upa")) {
-                       upa_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->type, "ebus")) {
-                       ebus_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->name, "usb") ||
-                   !strcmp(parent->name, "hub")) {
-                       usb_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->type, "i2c")) {
-                       i2c_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->type, "firewire")) {
-                       ieee1394_path_component(dp, tmp_buf);
-                       return;
-               }
-               if (!strcmp(parent->type, "virtual-devices")) {
-                       vdev_path_component(dp, tmp_buf);
-                       return;
-               }
-               /* "isa" is handled with platform naming */
-       }
-
-       /* Use platform naming convention.  */
-       if (tlb_type == hypervisor) {
-               sun4v_path_component(dp, tmp_buf);
-               return;
-       } else {
-               sun4u_path_component(dp, tmp_buf);
-       }
-}
-
-static char * __init build_path_component(struct device_node *dp)
-{
-       char tmp_buf[64], *n;
-
-       tmp_buf[0] = '\0';
-       __build_path_component(dp, tmp_buf);
-       if (tmp_buf[0] == '\0')
-               strcpy(tmp_buf, dp->name);
-
-       n = prom_early_alloc(strlen(tmp_buf) + 1);
-       strcpy(n, tmp_buf);
-
-       return n;
-}
-
-static char * __init build_full_name(struct device_node *dp)
-{
-       int len, ourlen, plen;
-       char *n;
-
-       plen = strlen(dp->parent->full_name);
-       ourlen = strlen(dp->path_component_name);
-       len = ourlen + plen + 2;
-
-       n = prom_early_alloc(len);
-       strcpy(n, dp->parent->full_name);
-       if (!is_root_node(dp->parent)) {
-               strcpy(n + plen, "/");
-               plen++;
-       }
-       strcpy(n + plen, dp->path_component_name);
-
-       return n;
-}
-
-static unsigned int unique_id;
-
-static struct property * __init build_one_prop(phandle node, char *prev, char *special_name, void *special_val, int special_len)
-{
-       static struct property *tmp = NULL;
-       struct property *p;
-
-       if (tmp) {
-               p = tmp;
-               memset(p, 0, sizeof(*p) + 32);
-               tmp = NULL;
-       } else {
-               p = prom_early_alloc(sizeof(struct property) + 32);
-               p->unique_id = unique_id++;
-       }
-
-       p->name = (char *) (p + 1);
-       if (special_name) {
-               strcpy(p->name, special_name);
-               p->length = special_len;
-               p->value = prom_early_alloc(special_len);
-               memcpy(p->value, special_val, special_len);
-       } else {
-               if (prev == NULL) {
-                       prom_firstprop(node, p->name);
-               } else {
-                       prom_nextprop(node, prev, p->name);
-               }
-               if (strlen(p->name) == 0) {
-                       tmp = p;
-                       return NULL;
-               }
-               p->length = prom_getproplen(node, p->name);
-               if (p->length <= 0) {
-                       p->length = 0;
-               } else {
-                       p->value = prom_early_alloc(p->length + 1);
-                       prom_getproperty(node, p->name, p->value, p->length);
-                       ((unsigned char *)p->value)[p->length] = '\0';
-               }
-       }
-       return p;
-}
-
-static struct property * __init build_prop_list(phandle node)
-{
-       struct property *head, *tail;
-
-       head = tail = build_one_prop(node, NULL,
-                                    ".node", &node, sizeof(node));
-
-       tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
-       tail = tail->next;
-       while(tail) {
-               tail->next = build_one_prop(node, tail->name,
-                                           NULL, NULL, 0);
-               tail = tail->next;
-       }
-
-       return head;
-}
-
-static char * __init get_one_property(phandle node, const char *name)
-{
-       char *buf = "<NULL>";
-       int len;
-
-       len = prom_getproplen(node, name);
-       if (len > 0) {
-               buf = prom_early_alloc(len);
-               prom_getproperty(node, name, buf, len);
-       }
-
-       return buf;
-}
-
-static struct device_node * __init create_node(phandle node, struct device_node *parent)
-{
-       struct device_node *dp;
-
-       if (!node)
-               return NULL;
-
-       dp = prom_early_alloc(sizeof(*dp));
-       dp->unique_id = unique_id++;
-       dp->parent = parent;
-
-       kref_init(&dp->kref);
-
-       dp->name = get_one_property(node, "name");
-       dp->type = get_one_property(node, "device_type");
-       dp->node = node;
-
-       dp->properties = build_prop_list(node);
-
-       irq_trans_init(dp);
-
-       return dp;
-}
-
-static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
-{
-       struct device_node *ret = NULL, *prev_sibling = NULL;
-       struct device_node *dp;
-
-       while (1) {
-               dp = create_node(node, parent);
-               if (!dp)
-                       break;
-
-               if (prev_sibling)
-                       prev_sibling->sibling = dp;
-
-               if (!ret)
-                       ret = dp;
-               prev_sibling = dp;
-
-               *(*nextp) = dp;
-               *nextp = &dp->allnext;
-
-               dp->path_component_name = build_path_component(dp);
-               dp->full_name = build_full_name(dp);
-
-               dp->child = build_tree(dp, prom_getchild(node), nextp);
-
-               node = prom_getsibling(node);
-       }
-
-       return ret;
-}
-
-static const char *get_mid_prop(void)
-{
-       return (tlb_type == spitfire ? "upa-portid" : "portid");
-}
-
-struct device_node *of_find_node_by_cpuid(int cpuid)
-{
-       struct device_node *dp;
-       const char *mid_prop = get_mid_prop();
-
-       for_each_node_by_type(dp, "cpu") {
-               int id = of_getintprop_default(dp, mid_prop, -1);
-               const char *this_mid_prop = mid_prop;
-
-               if (id < 0) {
-                       this_mid_prop = "cpuid";
-                       id = of_getintprop_default(dp, this_mid_prop, -1);
-               }
-
-               if (id < 0) {
-                       prom_printf("OF: Serious problem, cpu lacks "
-                                   "%s property", this_mid_prop);
-                       prom_halt();
-               }
-               if (cpuid == id)
-                       return dp;
-       }
-       return NULL;
-}
-
-static void __init of_fill_in_cpu_data(void)
-{
-       struct device_node *dp;
-       const char *mid_prop = get_mid_prop();
-
-       ncpus_probed = 0;
-       for_each_node_by_type(dp, "cpu") {
-               int cpuid = of_getintprop_default(dp, mid_prop, -1);
-               const char *this_mid_prop = mid_prop;
-               struct device_node *portid_parent;
-               int portid = -1;
-
-               portid_parent = NULL;
-               if (cpuid < 0) {
-                       this_mid_prop = "cpuid";
-                       cpuid = of_getintprop_default(dp, this_mid_prop, -1);
-                       if (cpuid >= 0) {
-                               int limit = 2;
-
-                               portid_parent = dp;
-                               while (limit--) {
-                                       portid_parent = portid_parent->parent;
-                                       if (!portid_parent)
-                                               break;
-                                       portid = of_getintprop_default(portid_parent,
-                                                                      "portid", -1);
-                                       if (portid >= 0)
-                                               break;
-                               }
-                       }
-               }
-
-               if (cpuid < 0) {
-                       prom_printf("OF: Serious problem, cpu lacks "
-                                   "%s property", this_mid_prop);
-                       prom_halt();
-               }
-
-               ncpus_probed++;
-
-#ifdef CONFIG_SMP
-               if (cpuid >= NR_CPUS) {
-                       printk(KERN_WARNING "Ignoring CPU %d which is "
-                              ">= NR_CPUS (%d)\n",
-                              cpuid, NR_CPUS);
-                       continue;
-               }
-#else
-               /* On uniprocessor we only want the values for the
-                * real physical cpu the kernel booted onto, however
-                * cpu_data() only has one entry at index 0.
-                */
-               if (cpuid != real_hard_smp_processor_id())
-                       continue;
-               cpuid = 0;
-#endif
-
-               cpu_data(cpuid).clock_tick =
-                       of_getintprop_default(dp, "clock-frequency", 0);
-
-               if (portid_parent) {
-                       cpu_data(cpuid).dcache_size =
-                               of_getintprop_default(dp, "l1-dcache-size",
-                                                     16 * 1024);
-                       cpu_data(cpuid).dcache_line_size =
-                               of_getintprop_default(dp, "l1-dcache-line-size",
-                                                     32);
-                       cpu_data(cpuid).icache_size =
-                               of_getintprop_default(dp, "l1-icache-size",
-                                                     8 * 1024);
-                       cpu_data(cpuid).icache_line_size =
-                               of_getintprop_default(dp, "l1-icache-line-size",
-                                                     32);
-                       cpu_data(cpuid).ecache_size =
-                               of_getintprop_default(dp, "l2-cache-size", 0);
-                       cpu_data(cpuid).ecache_line_size =
-                               of_getintprop_default(dp, "l2-cache-line-size", 0);
-                       if (!cpu_data(cpuid).ecache_size ||
-                           !cpu_data(cpuid).ecache_line_size) {
-                               cpu_data(cpuid).ecache_size =
-                                       of_getintprop_default(portid_parent,
-                                                             "l2-cache-size",
-                                                             (4 * 1024 * 1024));
-                               cpu_data(cpuid).ecache_line_size =
-                                       of_getintprop_default(portid_parent,
-                                                             "l2-cache-line-size", 64);
-                       }
-
-                       cpu_data(cpuid).core_id = portid + 1;
-                       cpu_data(cpuid).proc_id = portid;
-#ifdef CONFIG_SMP
-                       sparc64_multi_core = 1;
-#endif
-               } else {
-                       cpu_data(cpuid).dcache_size =
-                               of_getintprop_default(dp, "dcache-size", 16 * 1024);
-                       cpu_data(cpuid).dcache_line_size =
-                               of_getintprop_default(dp, "dcache-line-size", 32);
-
-                       cpu_data(cpuid).icache_size =
-                               of_getintprop_default(dp, "icache-size", 16 * 1024);
-                       cpu_data(cpuid).icache_line_size =
-                               of_getintprop_default(dp, "icache-line-size", 32);
-
-                       cpu_data(cpuid).ecache_size =
-                               of_getintprop_default(dp, "ecache-size",
-                                                     (4 * 1024 * 1024));
-                       cpu_data(cpuid).ecache_line_size =
-                               of_getintprop_default(dp, "ecache-line-size", 64);
-
-                       cpu_data(cpuid).core_id = 0;
-                       cpu_data(cpuid).proc_id = -1;
-               }
-
-#ifdef CONFIG_SMP
-               cpu_set(cpuid, cpu_present_map);
-               cpu_set(cpuid, cpu_possible_map);
-#endif
-       }
-
-       smp_fill_in_sib_core_maps();
-}
-
-struct device_node *of_console_device;
-EXPORT_SYMBOL(of_console_device);
-
-char *of_console_path;
-EXPORT_SYMBOL(of_console_path);
-
-char *of_console_options;
-EXPORT_SYMBOL(of_console_options);
-
-static void __init of_console_init(void)
-{
-       char *msg = "OF stdout device is: %s\n";
-       struct device_node *dp;
-       const char *type;
-       phandle node;
-
-       of_console_path = prom_early_alloc(256);
-       if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
-               prom_printf("Cannot obtain path of stdout.\n");
-               prom_halt();
-       }
-       of_console_options = strrchr(of_console_path, ':');
-       if (of_console_options) {
-               of_console_options++;
-               if (*of_console_options == '\0')
-                       of_console_options = NULL;
-       }
-
-       node = prom_inst2pkg(prom_stdout);
-       if (!node) {
-               prom_printf("Cannot resolve stdout node from "
-                           "instance %08x.\n", prom_stdout);
-               prom_halt();
-       }
-
-       dp = of_find_node_by_phandle(node);
-       type = of_get_property(dp, "device_type", NULL);
-       if (!type) {
-               prom_printf("Console stdout lacks device_type property.\n");
-               prom_halt();
-       }
-
-       if (strcmp(type, "display") && strcmp(type, "serial")) {
-               prom_printf("Console device_type is neither display "
-                           "nor serial.\n");
-               prom_halt();
-       }
-
-       of_console_device = dp;
-
-       printk(msg, of_console_path);
-}
-
-void __init prom_build_devicetree(void)
-{
-       struct device_node **nextp;
-
-       allnodes = create_node(prom_root_node, NULL);
-       allnodes->path_component_name = "";
-       allnodes->full_name = "/";
-
-       nextp = &allnodes->allnext;
-       allnodes->child = build_tree(allnodes,
-                                    prom_getchild(allnodes->node),
-                                    &nextp);
-       of_console_init();
-
-       printk("PROM: Built device tree with %u bytes of memory.\n",
-              prom_early_allocated);
-
-       if (tlb_type != hypervisor)
-               of_fill_in_cpu_data();
-}
similarity index 95%
rename from arch/sparc64/kernel/rtrap.S
rename to arch/sparc/kernel/rtrap_64.S
index 97a993c1f7f31bd62e7b310b08077b084622adff..fd3cee4d117c66ddc0fce0c3ef89bd923cd4f3b2 100644 (file)
@@ -14,9 +14,9 @@
 #include <asm/visasm.h>
 #include <asm/processor.h>
 
-#define                RTRAP_PSTATE            (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
-#define                RTRAP_PSTATE_IRQOFF     (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV)
-#define                RTRAP_PSTATE_AG_IRQOFF  (PSTATE_RMO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
+#define                RTRAP_PSTATE            (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
+#define                RTRAP_PSTATE_IRQOFF     (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
+#define                RTRAP_PSTATE_AG_IRQOFF  (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
 
                .text
                .align                  32
@@ -132,6 +132,18 @@ __handle_signal:
                ba,pt                   %xcc, __handle_signal_continue
                 andn                   %l1, %l4, %l1
 
+               /* When returning from a NMI (%pil==15) interrupt we want to
+                * avoid running softirqs, doing IRQ tracing, preempting, etc.
+                */
+               .globl                  rtrap_nmi
+rtrap_nmi:     ldx                     [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+               sethi                   %hi(0xf << 20), %l4
+               and                     %l1, %l4, %l4
+               andn                    %l1, %l4, %l1
+               srl                     %l4, 20, %l4
+               ba,pt                   %xcc, rtrap_no_irq_enable
+                wrpr                   %l4, %pil
+
                .align                  64
                .globl                  rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall
 rtrap_irq:
@@ -161,8 +173,8 @@ rtrap_xcall:
                call                    trace_hardirqs_on
                 nop
                wrpr                    %l4, %pil
-rtrap_no_irq_enable:
 #endif
+rtrap_no_irq_enable:
                andcc                   %l1, TSTATE_PRIV, %l3
                bne,pn                  %icc, to_kernel
                 nop
similarity index 98%
rename from arch/sparc/kernel/setup.c
rename to arch/sparc/kernel/setup_32.c
index 24fe3078bd4bf8d400d4b081745cd3770150e1b8..c96c65d1b58b94362b437964fda1be4e2155896f 100644 (file)
@@ -46,6 +46,8 @@
 #include <asm/cpudata.h>
 #include <asm/setup.h>
 
+#include "kernel.h"
+
 struct screen_info screen_info = {
        0, 0,                   /* orig-x, orig-y */
        0,                      /* unused */
@@ -308,9 +310,6 @@ void __init setup_arch(char **cmdline_p)
        smp_setup_cpu_possible_map();
 }
 
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
-
 static int ncpus_probed;
 
 static int show_cpuinfo(struct seq_file *m, void *__unused)
@@ -328,8 +327,8 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
                   "CPU0ClkTck\t: %ld\n"
 #endif
                   ,
-                  sparc_cpu_type ? sparc_cpu_type : "undetermined",
-                  sparc_fpu_type ? sparc_fpu_type : "undetermined",
+                  sparc_cpu_type,
+                  sparc_fpu_type ,
                   romvec->pv_romvers,
                   prom_rev,
                   romvec->pv_printrev >> 16,
similarity index 99%
rename from arch/sparc64/kernel/setup.c
rename to arch/sparc/kernel/setup_64.c
index c8b03a4f68bf8554a5f7e31b0c873474bac730f7..555db7452ebe2321ffbdcb7f19ca7e1b80522f9d 100644 (file)
@@ -52,6 +52,7 @@
 #endif
 
 #include "entry.h"
+#include "kernel.h"
 
 /* Used to synchronize accesses to NatSemi SUPER I/O chip configure
  * operations in asm/ns87303.h
similarity index 99%
rename from arch/sparc64/kernel/smp.c
rename to arch/sparc/kernel/smp_64.c
index f500b0618bb0d3b4badcdee2c5c8cb20225c97e9..bfe99d82d458702d32bf52a863cf00345e04a8e2 100644 (file)
@@ -163,7 +163,7 @@ static inline long get_delta (long *rt, long *master)
        for (i = 0; i < NUM_ITERS; i++) {
                t0 = tick_ops->get_tick();
                go[MASTER] = 1;
-               membar_storeload();
+               membar_safe("#StoreLoad");
                while (!(tm = go[SLAVE]))
                        rmb();
                go[SLAVE] = 0;
@@ -257,7 +257,7 @@ static void smp_synchronize_one_tick(int cpu)
 
        /* now let the client proceed into his loop */
        go[MASTER] = 0;
-       membar_storeload();
+       membar_safe("#StoreLoad");
 
        spin_lock_irqsave(&itc_sync_lock, flags);
        {
@@ -267,7 +267,7 @@ static void smp_synchronize_one_tick(int cpu)
                        go[MASTER] = 0;
                        wmb();
                        go[SLAVE] = tick_ops->get_tick();
-                       membar_storeload();
+                       membar_safe("#StoreLoad");
                }
        }
        spin_unlock_irqrestore(&itc_sync_lock, flags);
@@ -773,7 +773,7 @@ static void xcall_deliver(u64 data0, u64 data1, u64 data2, const cpumask_t *mask
 
        /* Setup the initial cpu list.  */
        cnt = 0;
-       for_each_cpu_mask_nr(i, *mask) {
+       for_each_cpu(i, mask) {
                if (i == this_cpu || !cpu_online(i))
                        continue;
                cpu_list[cnt++] = i;
@@ -1122,7 +1122,6 @@ void smp_capture(void)
                       smp_processor_id());
 #endif
                penguins_are_doing_time = 1;
-               membar_storestore_loadstore();
                atomic_inc(&smp_capture_registry);
                smp_cross_call(&xcall_capture, 0, 0, 0);
                while (atomic_read(&smp_capture_registry) != ncpus)
@@ -1142,13 +1141,13 @@ void smp_release(void)
                       smp_processor_id());
 #endif
                penguins_are_doing_time = 0;
-               membar_storeload_storestore();
+               membar_safe("#StoreLoad");
                atomic_dec(&smp_capture_registry);
        }
 }
 
-/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
- * can service tlb flush xcalls...
+/* Imprisoned penguins run with %pil == PIL_NORMAL_MAX, but PSTATE_IE
+ * set, so they can service tlb flush xcalls...
  */
 extern void prom_world(int);
 
@@ -1161,7 +1160,7 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
        __asm__ __volatile__("flushw");
        prom_world(1);
        atomic_inc(&smp_capture_registry);
-       membar_storeload_storestore();
+       membar_safe("#StoreLoad");
        while (penguins_are_doing_time)
                rmb();
        atomic_dec(&smp_capture_registry);
similarity index 98%
rename from arch/sparc/kernel/sparc_ksyms.c
rename to arch/sparc/kernel/sparc_ksyms_32.c
index b0dfff84865365a595e39283e480b1ccbd9eb850..a4d45fc29b21e4ac9c9c069bdab7b8c277c2f6f5 100644 (file)
@@ -61,7 +61,6 @@ extern void (*bzero_1page)(void *);
 extern void *__bzero(void *, size_t);
 extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
-extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 
 extern int __ashrdi3(int, int);
@@ -122,10 +121,8 @@ EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(rtc_lock);
-#ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(set_auxio);
 EXPORT_SYMBOL(get_auxio);
-#endif
 EXPORT_SYMBOL(io_remap_pfn_range);
 
 #ifndef CONFIG_SMP
@@ -213,7 +210,6 @@ EXPORT_SYMBOL(bzero_1page);
 EXPORT_SYMBOL(__bzero);
 EXPORT_SYMBOL(__memscan_zero);
 EXPORT_SYMBOL(__memscan_generic);
-EXPORT_SYMBOL(__memcmp);
 EXPORT_SYMBOL(__strncmp);
 EXPORT_SYMBOL(__memmove);
 
similarity index 97%
rename from arch/sparc64/kernel/sparc64_ksyms.c
rename to arch/sparc/kernel/sparc_ksyms_64.c
index 30bba8b0a3b0f91dadcc2aac44b0de329e5ec430..0133211ab6344e10bf60b9defd9165509c984e81 100644 (file)
@@ -49,6 +49,7 @@
 #include <asm/timer.h>
 #include <asm/cpudata.h>
 #include <asm/ftrace.h>
+#include <asm/hypervisor.h>
 
 struct poll {
        int fd;
@@ -61,7 +62,6 @@ extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 extern void *__bzero(void *, size_t);
 extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
-extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
 extern void sys_sigsuspend(void);
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
@@ -148,10 +148,13 @@ EXPORT_SYMBOL(flush_dcache_page);
 EXPORT_SYMBOL(__flush_dcache_range);
 #endif
 
-#ifdef CONFIG_SUN_AUXIO
+EXPORT_SYMBOL(sun4v_niagara_getperf);
+EXPORT_SYMBOL(sun4v_niagara_setperf);
+EXPORT_SYMBOL(sun4v_niagara2_getperf);
+EXPORT_SYMBOL(sun4v_niagara2_setperf);
+
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
-#endif
 #ifdef CONFIG_SBUS
 EXPORT_SYMBOL(sbus_set_sbus64);
 #endif
@@ -177,7 +180,6 @@ EXPORT_SYMBOL(pci_dma_supported);
 EXPORT_SYMBOL(io_remap_pfn_range);
 
 EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(put_fs_struct);
 
 /* math-emu wants this */
 EXPORT_SYMBOL(die_if_kernel);
@@ -219,7 +221,6 @@ EXPORT_SYMBOL(copy_user_page);
 EXPORT_SYMBOL(__bzero);
 EXPORT_SYMBOL(__memscan_zero);
 EXPORT_SYMBOL(__memscan_generic);
-EXPORT_SYMBOL(__memcmp);
 EXPORT_SYMBOL(__memset);
 
 EXPORT_SYMBOL(csum_partial);
similarity index 99%
rename from arch/sparc64/kernel/spiterrs.S
rename to arch/sparc/kernel/spiterrs.S
index ef902c6f8e3cefa641f0267d3c388e31279a4553..c357e40ffd01526ca38a824c12ac077cdba135c6 100644 (file)
@@ -80,7 +80,7 @@ __spitfire_cee_trap_continue:
        cmp             %g2, 1
        rdpr            %pil, %g2
        bleu,pt         %xcc, 1f
-        wrpr           %g0, 15, %pil
+        wrpr           %g0, PIL_NORMAL_MAX, %pil
 
        ba,pt           %xcc, etraptl1
         rd             %pc, %g7
similarity index 60%
rename from arch/sparc64/kernel/stacktrace.c
rename to arch/sparc/kernel/stacktrace.c
index 4e21d4a57d3b3f2ea536ed5707d61fbf6bc94181..acb12f6737570ebb7e4e8a98d8c4e741e1cb50b4 100644 (file)
@@ -7,17 +7,18 @@
 
 #include "kstack.h"
 
-void save_stack_trace(struct stack_trace *trace)
+static void __save_stack_trace(struct thread_info *tp,
+                              struct stack_trace *trace,
+                              bool skip_sched)
 {
-       struct thread_info *tp = task_thread_info(current);
        unsigned long ksp, fp;
 
-       stack_trace_flush();
-
-       __asm__ __volatile__(
-               "mov    %%fp, %0"
-               : "=r" (ksp)
-       );
+       if (tp == current_thread_info()) {
+               stack_trace_flush();
+               __asm__ __volatile__("mov %%fp, %0" : "=r" (ksp));
+       } else {
+               ksp = tp->ksp;
+       }
 
        fp = ksp + STACK_BIAS;
        do {
@@ -43,8 +44,21 @@ void save_stack_trace(struct stack_trace *trace)
 
                if (trace->skip > 0)
                        trace->skip--;
-               else
+               else if (!skip_sched || !in_sched_functions(pc))
                        trace->entries[trace->nr_entries++] = pc;
        } while (trace->nr_entries < trace->max_entries);
 }
+
+void save_stack_trace(struct stack_trace *trace)
+{
+       __save_stack_trace(current_thread_info(), trace, false);
+}
 EXPORT_SYMBOL_GPL(save_stack_trace);
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       struct thread_info *tp = task_thread_info(tsk);
+
+       __save_stack_trace(tp, trace, true);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
index 5dc8a5769489206ba45e64b12e6d471bd7923526..bc3adbf79c6a8006ca61053f905cde8474cec9fd 100644 (file)
@@ -160,6 +160,7 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn)
        sun4c_timers = (void __iomem *) (unsigned long) addr[0];
 
        irq = of_get_property(dp, "intr", NULL);
+       of_node_put(dp);
        if (!irq) {
                prom_printf("sun4c_init_timers: No intr property\n");
                prom_halt();
@@ -200,6 +201,7 @@ void __init sun4c_init_IRQ(void)
        }
 
        addr = of_get_property(dp, "address", NULL);
+       of_node_put(dp);
        if (!addr) {
                prom_printf("sun4c_init_IRQ: No address property\n");
                prom_halt();
index d3cb76ce418bde420d5d7e397679091ba5cd5cf8..3369fef5b4b3acd2749ddcbefd1befd37df2e15b 100644 (file)
@@ -40,6 +40,7 @@
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 
+#include "kernel.h"
 #include "irq.h"
 
 /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
@@ -58,7 +59,6 @@ static struct sun4d_timer_regs __iomem *sun4d_timers;
 #define TIMER_IRQ      10
 
 #define MAX_STATIC_ALLOC       4
-extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 extern int static_irq_count;
 static unsigned char sbus_tid[32];
 
@@ -508,6 +508,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
         * bootbus.
         */
        reg = of_get_property(dp, "reg", NULL);
+       of_node_put(dp);
        if (!reg) {
                prom_printf("sun4d_init_timers: No reg property\n");
                prom_halt();
index f10317179ee607c650ab837a5bb24ef34836e1b7..301892e2d7186fd41d32da167ff6218a5e5ce9d2 100644 (file)
@@ -374,6 +374,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
        }
 
        addr = of_get_property(dp, "address", &len);
+       of_node_put(dp);
        if (!addr) {
                printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
                return;
@@ -437,6 +438,7 @@ void __init sun4m_init_IRQ(void)
        }
 
        addr = of_get_property(dp, "address", &len);
+       of_node_put(dp);
        if (!addr) {
                printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
                return;
similarity index 98%
rename from arch/sparc64/kernel/sun4v_ivec.S
rename to arch/sparc/kernel/sun4v_ivec.S
index e2f8e1b4882a7f8cbc0c9a77c4eef33f473b7cac..559bc5e9c199232d092ec425d705a016b639db9a 100644 (file)
@@ -186,7 +186,7 @@ sun4v_res_mondo:
         * when it's done.
         */
        rdpr    %pil, %g2
-       wrpr    %g0, 15, %pil
+       wrpr    %g0, PIL_NORMAL_MAX, %pil
        mov     %g1, %g4
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
@@ -216,7 +216,7 @@ sun4v_res_mondo_queue_full:
        membar  #Sync
 
        rdpr    %pil, %g2
-       wrpr    %g0, 15, %pil
+       wrpr    %g0, PIL_NORMAL_MAX, %pil
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -297,7 +297,7 @@ sun4v_nonres_mondo:
         * when it's done.
         */
        rdpr    %pil, %g2
-       wrpr    %g0, 15, %pil
+       wrpr    %g0, PIL_NORMAL_MAX, %pil
        mov     %g1, %g4
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
@@ -327,7 +327,7 @@ sun4v_nonres_mondo_queue_full:
        membar  #Sync
 
        rdpr    %pil, %g2
-       wrpr    %g0, 15, %pil
+       wrpr    %g0, PIL_NORMAL_MAX, %pil
        ba,pt   %xcc, etrap_irq
         rd     %pc, %g7
 #ifdef CONFIG_TRACE_IRQFLAGS
similarity index 99%
rename from arch/sparc64/kernel/sysfs.c
rename to arch/sparc/kernel/sysfs.c
index 84e5ce146713383922f07f9e5b1c677874067344..d28f496f466913429dbd727893b824c0fefc39cf 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/percpu.h>
 #include <linux/init.h>
 
+#include <asm/cpudata.h>
 #include <asm/hypervisor.h>
 #include <asm/spitfire.h>
 
similarity index 98%
rename from arch/sparc64/kernel/trampoline.S
rename to arch/sparc/kernel/trampoline_64.S
index 83abd5ae88a49c6458de439ee2bac8846bf5d336..da1b781b5e65bd8f84d210f7bdb2e9d00022ae5c 100644 (file)
@@ -109,7 +109,6 @@ startup_continue:
         */
        sethi           %hi(prom_entry_lock), %g2
 1:     ldstub          [%g2 + %lo(prom_entry_lock)], %g1
-       membar          #StoreLoad | #StoreStore
        brnz,pn         %g1, 1b
         nop
 
@@ -214,7 +213,6 @@ startup_continue:
 
        sethi           %hi(prom_entry_lock), %g2
        stb             %g0, [%g2 + %lo(prom_entry_lock)]
-       membar          #StoreStore | #StoreLoad
 
        ba,pt           %xcc, after_lock_tlb
         nop
@@ -330,7 +328,6 @@ after_lock_tlb:
 
        sethi           %hi(prom_entry_lock), %g2
 1:     ldstub          [%g2 + %lo(prom_entry_lock)], %g1
-       membar          #StoreLoad | #StoreStore
        brnz,pn         %g1, 1b
         nop
 
@@ -394,7 +391,6 @@ after_lock_tlb:
 
 3:     sethi           %hi(prom_entry_lock), %g2
        stb             %g0, [%g2 + %lo(prom_entry_lock)]
-       membar          #StoreStore | #StoreLoad
 
        ldx             [%l0], %g6
        ldx             [%g6 + TI_TASK], %g4
similarity index 94%
rename from arch/sparc/kernel/traps.c
rename to arch/sparc/kernel/traps_32.c
index 2b7d50659036e2daa54e47e7deb23c875f7a6726..716f3946c494de35d74bf74c567c4fc5f7ee79fc 100644 (file)
 #include <asm/unistd.h>
 #include <asm/traps.h>
 
-/* #define TRAP_DEBUG */
-
-struct trap_trace_entry {
-       unsigned long pc;
-       unsigned long type;
-};
-
-void syscall_trace_entry(struct pt_regs *regs)
-{
-       printk("%s[%d]: ", current->comm, task_pid_nr(current));
-       printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
-              (int) regs->u_regs[UREG_I0]);
-}
-
-void syscall_trace_exit(struct pt_regs *regs)
-{
-}
+#include "entry.h"
+#include "kernel.h"
 
-void sun4d_nmi(struct pt_regs *regs)
-{
-       printk("Aieee: sun4d NMI received!\n");
-       printk("you lose buddy boy...\n");
-       show_regs(regs);
-       prom_halt();
-}
+/* #define TRAP_DEBUG */
 
 static void instruction_dump(unsigned long *pc)
 {
@@ -134,7 +113,6 @@ void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
 void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                            unsigned long psr)
 {
-       extern int do_user_muldiv (struct pt_regs *, unsigned long);
        siginfo_t info;
 
        if(psr & PSR_PS)
@@ -195,10 +173,6 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon
        send_sig_info(SIGBUS, &info, current);
 }
 
-extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
-                  void *fpqueue, unsigned long *fpqdepth);
-extern void fpload(unsigned long *fpregs, unsigned long *fsr);
-
 static unsigned long init_fsr = 0x0UL;
 static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
                 { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
@@ -456,8 +430,6 @@ void do_BUG(const char *file, int line)
  * up here so that timer interrupts work during initialization.
  */
 
-extern void sparc_cpu_startup(void);
-
 void trap_init(void)
 {
        extern void thread_info_offsets_are_bolixed_pete(void);
similarity index 99%
rename from arch/sparc64/kernel/traps.c
rename to arch/sparc/kernel/traps_64.c
index 81ccd22e78d45d538225feae4b68a4d9257d1f77..4638af2f55a0bb5d50c9b0b8425001d7e0845279 100644 (file)
@@ -1371,7 +1371,6 @@ static int cheetah_fix_ce(unsigned long physaddr)
        __asm__ __volatile__("ldxa      [%0] %3, %%g0\n\t"
                             "ldxa      [%1] %3, %%g0\n\t"
                             "casxa     [%2] %3, %%g0, %%g0\n\t"
-                            "membar    #StoreLoad | #StoreStore\n\t"
                             "ldxa      [%0] %3, %%g0\n\t"
                             "ldxa      [%1] %3, %%g0\n\t"
                             "membar    #Sync"
@@ -1833,7 +1832,7 @@ static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent,
        }
 }
 
-/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
+/* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate.
  * Log the event and clear the first word of the entry.
  */
 void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
@@ -1881,7 +1880,7 @@ void sun4v_resum_overflow(struct pt_regs *regs)
        atomic_inc(&sun4v_resum_oflow_cnt);
 }
 
-/* We run with %pil set to 15 and PSTATE_IE enabled in %pstate.
+/* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate.
  * Log the event, clear the first word of the entry, and die.
  */
 void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
similarity index 99%
rename from arch/sparc64/kernel/tsb.S
rename to arch/sparc/kernel/tsb.S
index c499214b501d007414e84a7f63d3b505193bf52d..8c91d9b29a2f24023849498a41f440b5ec1e6938 100644 (file)
@@ -317,7 +317,7 @@ tsb_flush:
        srlx    %g1, 32, %o3
        andcc   %o3, %g2, %g0
        bne,pn  %icc, 1b
-        membar #LoadLoad
+        nop
        cmp     %g1, %o1
        mov     1, %o3
        bne,pt  %xcc, 2f
@@ -327,7 +327,7 @@ tsb_flush:
        bne,pn  %xcc, 1b
         nop
 2:     retl
-        TSB_MEMBAR
+        nop
        .size   tsb_flush, .-tsb_flush
 
        /* Reload MMU related context switch state at
@@ -478,7 +478,7 @@ copy_tsb:           /* %o0=old_tsb_base, %o1=old_tsb_size
         nop
 
        retl
-        TSB_MEMBAR
+        nop
        .size           copy_tsb, .-copy_tsb
 
        /* Set the invalid bit in all TSB entries.  */
similarity index 99%
rename from arch/sparc64/kernel/ttable.S
rename to arch/sparc/kernel/ttable.S
index 1ade3d6fb7fc7d1bd748a7c47852c027328efa76..ea925503b42e59fa051d591ebf752eb708243c7d 100644 (file)
@@ -66,7 +66,7 @@ tl0_irq6:     BTRAP(0x46)
 tl0_irq7:      BTRAP(0x47) BTRAP(0x48) BTRAP(0x49)
 tl0_irq10:     BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d)
 tl0_irq14:     TRAP_IRQ(timer_interrupt, 14)
-tl0_irq15:     TRAP_IRQ(handler_irq, 15)
+tl0_irq15:     TRAP_NMI_IRQ(perfctr_irq, 15)
 tl0_resv050:   BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
 tl0_resv056:   BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
 tl0_resv05c:   BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f)
index 5b7e69a8c32f7259497fafbcd1e816242e690423..76267085b13b37f2934282a0dd4b95150cb97ea7 100644 (file)
@@ -1,27 +1,56 @@
-/* ld script to make SparcLinux kernel */
+/* ld script for sparc32/sparc64 kernel */
 
 #include <asm-generic/vmlinux.lds.h>
+
 #include <asm/page.h>
+#include <asm/thread_info.h>
+
+#ifdef CONFIG_SPARC32
+#define INITIAL_ADDRESS  0x10000 + SIZEOF_HEADERS
+#define TEXTSTART      0xf0004000
+
+#define SMP_CACHE_BYTES_SHIFT 5
+
+#else
+#define SMP_CACHE_BYTES_SHIFT 6
+#define INITIAL_ADDRESS 0x4000
+#define TEXTSTART      0x0000000000404000
+
+#endif
+
+#define SMP_CACHE_BYTES (1 << SMP_CACHE_BYTES_SHIFT)
 
+#ifdef CONFIG_SPARC32
 OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc")
 OUTPUT_ARCH(sparc)
 ENTRY(_start)
 jiffies = jiffies_64 + 4;
+#else
+/* sparc64 */
+OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc")
+OUTPUT_ARCH(sparc:v9a)
+ENTRY(_start)
+jiffies = jiffies_64;
+#endif
+
 SECTIONS
 {
-       . = 0x10000 + SIZEOF_HEADERS;
-       .text 0xf0004000 :
+       /* swapper_low_pmd_dir is sparc64 only */
+       swapper_low_pmd_dir = 0x0000000000402000;
+       . = INITIAL_ADDRESS;
+       .text TEXTSTART :
        {
                _text = .;
                *(.text.head)
                TEXT_TEXT
                SCHED_TEXT
                LOCK_TEXT
+               KPROBES_TEXT
                *(.gnu.warning)
        } = 0
        _etext = .;
-       PROVIDE (etext = .);
-       RODATA
+
+       RO_DATA(PAGE_SIZE)
        .data : {
                DATA_DATA
                CONSTRUCTORS
@@ -29,25 +58,38 @@ SECTIONS
        .data1 : {
                *(.data1)
        }
+       . = ALIGN(SMP_CACHE_BYTES);
+       .data.cacheline_aligned : {
+               *(.data.cacheline_aligned)
+       }
+       . = ALIGN(SMP_CACHE_BYTES);
+       .data.read_mostly : {
+               *(.data.read_mostly)
+       }
+       /* End of data section */
        _edata = .;
-       PROVIDE (edata = .);
 
+       /* init_task */
+       . = ALIGN(THREAD_SIZE);
+       .data.init_task : {
+               *(.data.init_task)
+       }
        .fixup : {
                __start___fixup = .;
                *(.fixup)
                __stop___fixup = .;
        }
+       . = ALIGN(16);
        __ex_table : {
                __start___ex_table = .;
                *(__ex_table)
                __stop___ex_table = .;
        }
-
        NOTES
 
        . = ALIGN(PAGE_SIZE);
-       __init_begin = .;
        .init.text : {
+               __init_begin = .;
                _sinittext = .;
                INIT_TEXT
                _einittext = .;
@@ -65,7 +107,7 @@ SECTIONS
        .initcall.init : {
                __initcall_start = .;
                INITCALLS
-       __initcall_end = .;
+               __initcall_end = .;
        }
        .con_initcall.init : {
                __con_initcall_start = .;
@@ -74,38 +116,61 @@ SECTIONS
        }
        SECURITY_INIT
 
+       . = ALIGN(4);
+       .tsb_ldquad_phys_patch : {
+               __tsb_ldquad_phys_patch = .;
+               *(.tsb_ldquad_phys_patch)
+               __tsb_ldquad_phys_patch_end = .;
+       }
+
+       .tsb_phys_patch : {
+               __tsb_phys_patch = .;
+               *(.tsb_phys_patch)
+               __tsb_phys_patch_end = .;
+       }
+
+       .cpuid_patch : {
+               __cpuid_patch = .;
+               *(.cpuid_patch)
+               __cpuid_patch_end = .;
+       }
+
+       .sun4v_1insn_patch : {
+               __sun4v_1insn_patch = .;
+               *(.sun4v_1insn_patch)
+               __sun4v_1insn_patch_end = .;
+       }
+       .sun4v_2insn_patch : {
+               __sun4v_2insn_patch = .;
+               *(.sun4v_2insn_patch)
+               __sun4v_2insn_patch_end = .;
+       }
+
 #ifdef CONFIG_BLK_DEV_INITRD
        . = ALIGN(PAGE_SIZE);
        .init.ramfs : {
-       __initramfs_start = .;
+               __initramfs_start = .;
                *(.init.ramfs)
-       __initramfs_end = .;
+               __initramfs_end = .;
        }
 #endif
 
        PERCPU(PAGE_SIZE)
+
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
-       . = ALIGN(32);
-       .data.cacheline_aligned : {
-               *(.data.cacheline_aligned)
-       }
-       . = ALIGN(32);
-       .data.read_mostly : {
-               *(.data.read_mostly)
-       }
-
        __bss_start = .;
        .sbss : {
                *(.sbss)
-               *(.scommon) }
+               *(.scommon)
+       }
        .bss : {
                *(.dynbss)
                *(.bss)
                *(COMMON)
        }
        _end = . ;
-       PROVIDE (end = .);
+
        /DISCARD/ : {
                EXIT_TEXT
                EXIT_DATA
index 6e303e10c3b94b0d111f2c39676163655cf75801..375016e19144ada6f3972792880b4f7f0a846e54 100644 (file)
@@ -1,13 +1,44 @@
 # Makefile for Sparc library files..
 #
 
-EXTRA_AFLAGS := -ansi -DST_DIV0=0x02
+asflags-y := -ansi -DST_DIV0=0x02
+ccflags-y := -Werror
 
-lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
-         strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
-        strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
-        copy_user.o locks.o atomic.o \
-        lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o \
-        cmpdi2.o
+lib-$(CONFIG_SPARC32) += mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o
+lib-$(CONFIG_SPARC32) += memcpy.o memset.o
+lib-y                 += strlen.o
+lib-y                 += checksum_$(BITS).o
+lib-$(CONFIG_SPARC32) += blockops.o
+lib-y                 += memscan_$(BITS).o memcmp.o strncmp_$(BITS).o
+lib-y                 += strncpy_from_user_$(BITS).o strlen_user_$(BITS).o
+lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
+lib-$(CONFIG_SPARC32) += copy_user.o locks.o
+lib-y                 += atomic_$(BITS).o
+lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
+lib-y                 += rwsem_$(BITS).o
+lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o
 
-obj-y += iomap.o atomic32.o
+lib-$(CONFIG_SPARC64) += PeeCeeI.o copy_page.o clear_page.o bzero.o
+lib-$(CONFIG_SPARC64) += csum_copy.o csum_copy_from_user.o csum_copy_to_user.o
+lib-$(CONFIG_SPARC64) += VISsave.o
+lib-$(CONFIG_SPARC64) += bitops.o
+
+lib-$(CONFIG_SPARC64) += U1memcpy.o U1copy_from_user.o U1copy_to_user.o
+
+lib-$(CONFIG_SPARC64) += U3memcpy.o U3copy_from_user.o U3copy_to_user.o
+lib-$(CONFIG_SPARC64) += U3patch.o
+
+lib-$(CONFIG_SPARC64) += NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o
+lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o
+
+lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o
+lib-$(CONFIG_SPARC64) +=  NG2patch.o NG2page.o
+
+lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
+lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
+
+lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
+lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o
+
+obj-y                 += iomap.o
+obj-$(CONFIG_SPARC32) += atomic32.o
similarity index 84%
rename from arch/sparc64/lib/atomic.S
rename to arch/sparc/lib/atomic_64.S
index 70ac4186f62b7afc4af36eeb5472d6db868688d8..0268210ca1683f7bd0bb018953d93a22e207c701 100644 (file)
@@ -43,29 +43,10 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
        .size   atomic_sub, .-atomic_sub
 
-       /* On SMP we need to use memory barriers to ensure
-        * correct memory operation ordering, nop these out
-        * for uniprocessor.
-        */
-#ifdef CONFIG_SMP
-
-#define ATOMIC_PRE_BARRIER     membar #StoreLoad | #LoadLoad;
-#define ATOMIC_POST_BARRIER    \
-       ba,pt %xcc, 80b;        \
-       membar #StoreLoad | #StoreStore
-
-80:    retl
-        nop
-#else
-#define ATOMIC_PRE_BARRIER
-#define ATOMIC_POST_BARRIER
-#endif
-
        .globl  atomic_add_ret
        .type   atomic_add_ret,#function
 atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        BACKOFF_SETUP(%o2)
-       ATOMIC_PRE_BARRIER
 1:     lduw    [%o1], %g1
        add     %g1, %o0, %g7
        cas     [%o1], %g1, %g7
@@ -73,7 +54,6 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        bne,pn  %icc, 2f
         add    %g7, %o0, %g7
        sra     %g7, 0, %o0
-       ATOMIC_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
@@ -83,7 +63,6 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        .type   atomic_sub_ret,#function
 atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        BACKOFF_SETUP(%o2)
-       ATOMIC_PRE_BARRIER
 1:     lduw    [%o1], %g1
        sub     %g1, %o0, %g7
        cas     [%o1], %g1, %g7
@@ -91,7 +70,6 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        bne,pn  %icc, 2f
         sub    %g7, %o0, %g7
        sra     %g7, 0, %o0
-       ATOMIC_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
@@ -131,7 +109,6 @@ atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */
        .type   atomic64_add_ret,#function
 atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        BACKOFF_SETUP(%o2)
-       ATOMIC_PRE_BARRIER
 1:     ldx     [%o1], %g1
        add     %g1, %o0, %g7
        casx    [%o1], %g1, %g7
@@ -139,7 +116,6 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        bne,pn  %xcc, 2f
         add    %g7, %o0, %g7
        mov     %g7, %o0
-       ATOMIC_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
@@ -149,7 +125,6 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
        .type   atomic64_sub_ret,#function
 atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        BACKOFF_SETUP(%o2)
-       ATOMIC_PRE_BARRIER
 1:     ldx     [%o1], %g1
        sub     %g1, %o0, %g7
        casx    [%o1], %g1, %g7
@@ -157,7 +132,6 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
        bne,pn  %xcc, 2f
         sub    %g7, %o0, %g7
        mov     %g7, %o0
-       ATOMIC_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o2, %o3, 1b)
similarity index 84%
rename from arch/sparc64/lib/bitops.S
rename to arch/sparc/lib/bitops.S
index 6b015a6eefb50017e7d22b2d1edc0637408a1fef..2b7228cb8c2209332000d429257f16f4dbcf730f 100644 (file)
@@ -8,29 +8,10 @@
 
        .text
 
-       /* On SMP we need to use memory barriers to ensure
-        * correct memory operation ordering, nop these out
-        * for uniprocessor.
-        */
-
-#ifdef CONFIG_SMP
-#define BITOP_PRE_BARRIER      membar #StoreLoad | #LoadLoad
-#define BITOP_POST_BARRIER     \
-       ba,pt   %xcc, 80b;      \
-       membar #StoreLoad | #StoreStore
-
-80:    retl
-        nop
-#else
-#define BITOP_PRE_BARRIER
-#define BITOP_POST_BARRIER
-#endif
-
        .globl  test_and_set_bit
        .type   test_and_set_bit,#function
 test_and_set_bit:      /* %o0=nr, %o1=addr */
        BACKOFF_SETUP(%o3)
-       BITOP_PRE_BARRIER
        srlx    %o0, 6, %g1
        mov     1, %o2
        sllx    %g1, 3, %g3
@@ -45,7 +26,6 @@ test_and_set_bit:     /* %o0=nr, %o1=addr */
         and    %g7, %o2, %g2
        clr     %o0
        movrne  %g2, 1, %o0
-       BITOP_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o3, %o4, 1b)
@@ -55,7 +35,6 @@ test_and_set_bit:     /* %o0=nr, %o1=addr */
        .type   test_and_clear_bit,#function
 test_and_clear_bit:    /* %o0=nr, %o1=addr */
        BACKOFF_SETUP(%o3)
-       BITOP_PRE_BARRIER
        srlx    %o0, 6, %g1
        mov     1, %o2
        sllx    %g1, 3, %g3
@@ -70,7 +49,6 @@ test_and_clear_bit:   /* %o0=nr, %o1=addr */
         and    %g7, %o2, %g2
        clr     %o0
        movrne  %g2, 1, %o0
-       BITOP_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o3, %o4, 1b)
@@ -80,7 +58,6 @@ test_and_clear_bit:   /* %o0=nr, %o1=addr */
        .type   test_and_change_bit,#function
 test_and_change_bit:   /* %o0=nr, %o1=addr */
        BACKOFF_SETUP(%o3)
-       BITOP_PRE_BARRIER
        srlx    %o0, 6, %g1
        mov     1, %o2
        sllx    %g1, 3, %g3
@@ -95,7 +72,6 @@ test_and_change_bit:  /* %o0=nr, %o1=addr */
         and    %g7, %o2, %g2
        clr     %o0
        movrne  %g2, 1, %o0
-       BITOP_POST_BARRIER
        retl
         nop
 2:     BACKOFF_SPIN(%o3, %o4, 1b)
index cb4bdb0cc2afe3798674066209995d8cf98072c9..efa106c41ed0af7777d4a6a8b70ca9585d9b694d 100644 (file)
-       .text
-       .align 4
-       .global __memcmp, memcmp
-__memcmp:
-memcmp:
-#if 1
-       cmp     %o2, 0
-       ble     L3
-        mov    0, %g3
-L5:
-       ldub    [%o0], %g2
-       ldub    [%o1], %g3
-       sub     %g2, %g3, %g2
-       mov     %g2, %g3
-       sll     %g2, 24, %g2
-
-       cmp     %g2, 0
-       bne     L3
-        add    %o0, 1, %o0
+/* Sparc optimized memcmp code.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2000, 2008 David S. Miller (davem@davemloft.net)
+ */
 
-       add     %o2, -1, %o2
+#include <linux/linkage.h>
+#include <asm/asm.h>
 
+       .text
+ENTRY(memcmp)
        cmp     %o2, 0
-       bg      L5
-        add    %o1, 1, %o1
-L3:
-       sll     %g3, 24, %o0
-       sra     %o0, 24, %o0
-
-       retl
+1:     BRANCH32(be, pn, 2f)
         nop
-#else
-       save    %sp, -104, %sp
-       mov     %i2, %o4
-       mov     %i0, %o0
-
-       cmp     %o4, 15
-       ble     L72
-        mov    %i1, %i2
-
-       andcc   %i2, 3, %g0
-       be      L161
-        andcc  %o0, 3, %g2
-L75:
-       ldub    [%o0], %g3
-       ldub    [%i2], %g2
-       add     %o0,1, %o0
-
-       subcc   %g3, %g2, %i0
-       bne     L156
-        add    %i2, 1, %i2
-
-       andcc   %i2, 3, %g0
-       bne     L75
-        add    %o4, -1, %o4
-
-       andcc   %o0, 3, %g2
-L161:
-       bne,a   L78
-        mov    %i2, %i1
-
-       mov     %o0, %i5
-       mov     %i2, %i3
-       srl     %o4, 2, %i4
-
-       cmp     %i4, 0
-       bge     L93
-        mov    %i4, %g2
-
-       add %i4, 3, %g2
-L93:
-       sra     %g2, 2, %g2
-       sll     %g2, 2, %g2
-       sub     %i4, %g2, %g2
-
-       cmp     %g2, 1
-       be,a    L88
-        add    %o0, 4, %i5
-
-       bg      L94
-        cmp    %g2, 2
-
-       cmp     %g2, 0
-       be,a    L86
-        ld     [%o0], %g3
-
-       b       L162
-        ld     [%i5], %g3
-L94:
-       be      L81
-        cmp    %g2, 3
-
-       be,a    L83
-        add    %o0, -4, %i5
-
-       b       L162
-        ld     [%i5], %g3
-L81:
-       add     %o0, -8, %i5
-       ld      [%o0], %g3
-       add     %i2, -8, %i3
-       ld      [%i2], %g2
-
-       b       L82
-        add    %i4, 2, %i4
-L83:
-       ld      [%o0], %g4
-       add     %i2, -4, %i3
-       ld      [%i2], %g1
-
-       b       L84
-        add    %i4, 1, %i4
-L86:
-       b       L87
-        ld     [%i2], %g2
-L88:
-       add     %i2, 4, %i3
-       ld      [%o0], %g4
-       add     %i4, -1, %i4
-       ld      [%i2], %g1
-L95:
-       ld      [%i5], %g3
-L162:
-       cmp     %g4, %g1
-       be      L87
-        ld     [%i3], %g2
-
-       cmp     %g4, %g1
-L163:
-       bleu    L114
-        mov    -1, %i0
-
-       b       L114
-        mov    1, %i0
-L87:
-       ld      [%i5 + 4], %g4
-       cmp     %g3, %g2
-       bne     L163
-        ld     [%i3 + 4], %g1
-L84:
-       ld      [%i5 + 8], %g3
-
-       cmp     %g4, %g1
-       bne     L163
-        ld     [%i3 + 8], %g2
-L82:
-       ld      [%i5 + 12], %g4
-       cmp     %g3, %g2
-       bne     L163
-        ld     [%i3 + 12], %g1
-
-       add     %i5, 16, %i5
-
-       addcc   %i4, -4, %i4
-       bne     L95
-        add    %i3, 16, %i3
-
-       cmp     %g4, %g1
-       bne     L163
-        nop
-
-       b       L114
-        mov    0, %i0
-L78:
-       srl     %o4, 2, %i0
-       and     %o0, -4, %i3
-       orcc    %i0, %g0, %g3
-       sll     %g2, 3, %o7
-       mov     32, %g2
-
-       bge     L129
-        sub    %g2, %o7, %o1
-
-       add     %i0, 3, %g3
-L129:
-       sra     %g3, 2, %g2
-       sll     %g2, 2, %g2
-       sub     %i0, %g2, %g2
-
-       cmp     %g2, 1
-       be,a    L124
-        ld     [%i3], %o3
-
-       bg      L130
-        cmp    %g2, 2
-
-       cmp     %g2, 0
-       be,a    L122
-        ld     [%i3], %o2
-
-       b       L164
-       sll     %o3, %o7, %g3
-L130:
-       be      L117
-        cmp    %g2, 3
-
-       be,a    L119
-        ld     [%i3], %g1
-
-       b       L164
-        sll    %o3, %o7, %g3
-L117:
-       ld      [%i3], %g4
-       add     %i2, -8, %i1
-       ld      [%i3 + 4], %o3
-       add     %i0, 2, %i0
-       ld      [%i2], %i4
-
-       b       L118
-        add    %i3, -4, %i3
-L119:
-       ld      [%i3 + 4], %g4
-       add     %i2, -4, %i1
-       ld      [%i2], %i5
-
-       b       L120
-        add    %i0, 1, %i0
-L122:
-       ld      [%i3 + 4], %g1
-       ld      [%i2], %i4
-
-       b       L123
-        add    %i3, 4, %i3
-L124:
-       add     %i2, 4, %i1
-       ld      [%i3 + 4], %o2
-       add     %i0, -1, %i0
-       ld      [%i2], %i5
-       add     %i3, 8, %i3
-L131:
-       sll     %o3, %o7, %g3
-L164:
-       srl     %o2, %o1, %g2
-       ld      [%i3], %g1
-       or      %g3, %g2, %g3
-
-       cmp     %g3, %i5
-       bne     L163
-        ld     [%i1], %i4
-L123:
-       sll     %o2, %o7, %g3
-       srl     %g1, %o1, %g2
-       ld      [%i3 + 4], %g4
-       or      %g3, %g2, %g3
-
-       cmp     %g3, %i4
-       bne     L163
-        ld     [%i1 + 4], %i5
-L120:
-       sll     %g1, %o7, %g3
-       srl     %g4, %o1, %g2
-       ld      [%i3 + 8], %o3
-       or      %g3, %g2, %g3
-
-       cmp     %g3, %i5
-       bne     L163
-        ld     [%i1 + 8], %i4
-L118:
-       sll     %g4, %o7, %g3
-       srl     %o3, %o1, %g2
-       ld      [%i3 + 12], %o2
-       or      %g3, %g2, %g3
-
-       cmp     %g3, %i4
-       bne     L163
-        ld     [%i1 + 12], %i5
-
-       add     %i3, 16, %i3
-       addcc   %i0, -4, %i0
-       bne     L131
-        add    %i1, 16, %i1
-
-       sll     %o3, %o7, %g3
-       srl     %o2, %o1, %g2
-       or      %g3, %g2, %g3
-
-       cmp     %g3, %i5
-       be,a    L114
-        mov    0, %i0
-
-       b,a L163
-L114:
-       cmp     %i0, 0
-       bne     L156
-        and    %o4, -4, %g2
-
-       add     %o0, %g2, %o0
-       add     %i2, %g2, %i2
-       and     %o4, 3, %o4
-L72:
-       cmp     %o4, 0
-       be      L156
-        mov    0, %i0
-
-       ldub    [%o0], %g3
-L165:
-       ldub    [%i2], %g2
+       ldub    [%o0], %g7
+       ldub    [%o1], %g3
+       sub     %o2, 1, %o2
        add     %o0, 1, %o0
-
-       subcc   %g3, %g2, %i0
-       bne     L156
-        add    %i2, 1, %i2
-
-       addcc   %o4, -1, %o4
-       bne,a   L165
-        ldub   [%o0], %g3
-
-       mov     0, %i0
-L156:
-       ret
-       restore
-#endif
+       add     %o1, 1, %o1
+       subcc   %g7, %g3, %g3
+       BRANCH32(be, pt, 1b)
+        cmp    %o2, 0
+       retl
+        mov    %g3, %o0
+2:     retl
+        mov    0, %o0
+ENDPROC(memcmp)
similarity index 92%
rename from arch/sparc64/lib/rwsem.S
rename to arch/sparc/lib/rwsem_64.S
index 1a4cc5654de4668a5d751644115031e87555a53d..91a7d29a79d55cd295651dc1115b7c12f842060b 100644 (file)
@@ -17,7 +17,6 @@ __down_read:
        bne,pn          %icc, 1b
         add            %g7, 1, %g7
        cmp             %g7, 0
-       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
         nop
 2:
@@ -42,7 +41,6 @@ __down_read_trylock:
        cmp             %g1, %g7
        bne,pn          %icc, 1b
         mov            1, %o1
-       membar          #StoreLoad | #StoreStore
 2:     retl
         mov            %o1, %o0
        .size           __down_read_trylock, .-__down_read_trylock
@@ -58,7 +56,6 @@ __down_write:
        cmp             %g3, %g7
        bne,pn          %icc, 1b
         cmp            %g7, 0
-       membar          #StoreLoad | #StoreStore
        bne,pn          %icc, 3f
         nop
 2:     retl
@@ -85,7 +82,6 @@ __down_write_trylock:
        cmp             %g3, %g7
        bne,pn          %icc, 1b
         mov            1, %o1
-       membar          #StoreLoad | #StoreStore
 2:     retl
         mov            %o1, %o0
        .size           __down_write_trylock, .-__down_write_trylock
@@ -99,7 +95,6 @@ __up_read:
        cmp             %g1, %g7
        bne,pn          %icc, 1b
         cmp            %g7, 0
-       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
         nop
 2:     retl
@@ -129,7 +124,6 @@ __up_write:
        bne,pn          %icc, 1b
         sub            %g7, %g1, %g7
        cmp             %g7, 0
-       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
         nop
 2:
@@ -155,7 +149,6 @@ __downgrade_write:
        bne,pn          %icc, 1b
         sub            %g7, %g1, %g7
        cmp             %g7, 0
-       membar          #StoreLoad | #StoreStore
        bl,pn           %icc, 3f
         nop
 2:
index ed9a763368cd4f54632e2ad6e40472d53a3f889c..536f83507fbff1dc669f998f5e6b7336812225a5 100644 (file)
@@ -1,51 +1,40 @@
 /* strlen.S: Sparc optimized strlen code
  * Hand optimized from GNU libc's strlen
  * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996,2008 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
 #define LO_MAGIC 0x01010101
 #define HI_MAGIC 0x80808080
 
-0:
+       .text
+ENTRY(strlen)
+       mov     %o0, %o1
+       andcc   %o0, 3, %g0
+       BRANCH32(be, pt, 9f)
+        sethi  %hi(HI_MAGIC), %o4
        ldub    [%o0], %o5
-       cmp     %o5, 0
-       be      1f
+       BRANCH_REG_ZERO(pn, %o5, 11f)
         add    %o0, 1, %o0
        andcc   %o0, 3, %g0
-       be      4f
+       BRANCH32(be, pn, 4f)
         or     %o4, %lo(HI_MAGIC), %o3
        ldub    [%o0], %o5
-       cmp     %o5, 0
-       be      2f
+       BRANCH_REG_ZERO(pn, %o5, 12f)
         add    %o0, 1, %o0
        andcc   %o0, 3, %g0
-       be      5f
+       BRANCH32(be, pt, 5f)
         sethi  %hi(LO_MAGIC), %o4
        ldub    [%o0], %o5
-       cmp     %o5, 0
-       be      3f
+       BRANCH_REG_ZERO(pn, %o5, 13f)
         add    %o0, 1, %o0
-       b       8f
+       BRANCH32(ba, pt, 8f)
         or     %o4, %lo(LO_MAGIC), %o2
-1:
-       retl
-        mov    0, %o0
-2:
-       retl
-        mov    1, %o0
-3:
-       retl
-        mov    2, %o0
-
-       .align 4
-       .global strlen
-strlen:
-       mov     %o0, %o1
-       andcc   %o0, 3, %g0
-       bne     0b
-        sethi  %hi(HI_MAGIC), %o4
+9:
        or      %o4, %lo(HI_MAGIC), %o3
 4:
        sethi   %hi(LO_MAGIC), %o4
@@ -56,26 +45,36 @@ strlen:
 2:
        sub     %o5, %o2, %o4
        andcc   %o4, %o3, %g0
-       be      8b
+       BRANCH32(be, pt, 8b)
         add    %o0, 4, %o0
 
        /* Check every byte. */
-       srl     %o5, 24, %g5
-       andcc   %g5, 0xff, %g0
-       be      1f
+       srl     %o5, 24, %g7
+       andcc   %g7, 0xff, %g0
+       BRANCH32(be, pn, 1f)
         add    %o0, -4, %o4
-       srl     %o5, 16, %g5
-       andcc   %g5, 0xff, %g0
-       be      1f
+       srl     %o5, 16, %g7
+       andcc   %g7, 0xff, %g0
+       BRANCH32(be, pn, 1f)
         add    %o4, 1, %o4
-       srl     %o5, 8, %g5
-       andcc   %g5, 0xff, %g0
-       be      1f
+       srl     %o5, 8, %g7
+       andcc   %g7, 0xff, %g0
+       BRANCH32(be, pn, 1f)
         add    %o4, 1, %o4
        andcc   %o5, 0xff, %g0
-       bne,a   2b
+       BRANCH32_ANNUL(bne, pt, 2b)
         ld     [%o0], %o5
        add     %o4, 1, %o4
 1:
        retl
         sub    %o4, %o1, %o0
+11:
+       retl
+        mov    0, %o0
+12:
+       retl
+        mov    1, %o0
+13:
+       retl
+        mov    2, %o0
+ENDPROC(strlen)
similarity index 100%
rename from arch/sparc64/lib/xor.S
rename to arch/sparc/lib/xor.S
index 8136987977f45ce598f02f41c65a168254b59270..b9085ecbb27b7f1f8a373af9cd0504f5bde1b0a0 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the FPU instruction emulation.
 #
 
-obj-y    := math.o
+# supress all warnings - as math.c produces a lot!
+ccflags-y := -w
 
-EXTRA_AFLAGS := -ansi
-EXTRA_CFLAGS = -I. -Iinclude/math-emu -w
+obj-y    := math_$(BITS).o
diff --git a/arch/sparc/math-emu/ashldi3.S b/arch/sparc/math-emu/ashldi3.S
deleted file mode 100644 (file)
index 7230ff5..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * ashldi3.S:  Math-emu code creates all kinds of references to
- *              this little routine on the sparc with gcc.
- *
- * Copyright (C) 1998 Jakub Jelinek(jj@ultra.linux.cz)
- */
-
-#include <asm/cprefix.h>
-
-       .globl C_LABEL(__ashldi3)
-C_LABEL(__ashldi3):
-       tst     %o2
-       be      3f
-        mov    32, %g2
-
-       sub     %g2, %o2, %g2
-
-       tst     %g2
-       bg      1f
-        srl    %o1, %g2, %g3
-
-       clr     %o5
-       neg     %g2
-       ba      2f
-        sll    %o1, %g2, %o4
-
-1:
-       sll     %o1, %o2, %o5
-       srl     %o0, %o2, %g2
-       or      %g2, %g3, %o4
-2:
-       mov     %o4, %o0
-       mov     %o5, %o1
-3:
-       jmpl    %o7 + 8, %g0
-        nop
similarity index 99%
rename from arch/sparc/math-emu/math.c
rename to arch/sparc/math-emu/math_32.c
index 8613b3eb877c738ed71adcec2281865bcef924c2..e13f65da17dfd90875e2da6e9e29c609e21ee3a3 100644 (file)
@@ -69,7 +69,7 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
-#include "sfp-util.h"
+#include "sfp-util_32.h"
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 #include <math-emu/double.h>
similarity index 99%
rename from arch/sparc64/math-emu/math.c
rename to arch/sparc/math-emu/math_64.c
index add053e0f3b33fb7b87d29daa35eab815ec18115..6863c9bde25c918926d38dea78497f15f0ba2dbc 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 
-#include "sfp-util.h"
+#include "sfp-util_64.h"
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 #include <math-emu/double.h>
index ea88955d97ffe6f10ee6dd085e57ae593f0f54b1..681abe0a45941a2c4f7f73f9cdc7393be24fc584 100644 (file)
@@ -1,17 +1,25 @@
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 
-EXTRA_AFLAGS := -ansi
+asflags-y := -ansi
+ccflags-y := -Werror
 
-obj-y  := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
-           srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
+obj-$(CONFIG_SPARC64)   += ultra.o tlb.o tsb.o
+obj-y                   += fault_$(BITS).o
+obj-y                   += init_$(BITS).o
+obj-$(CONFIG_SPARC32)   += loadmmu.o
+obj-y                   += generic_$(BITS).o
+obj-$(CONFIG_SPARC32)   += extable.o btfixup.o srmmu.o iommu.o io-unit.o
+obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
 
-ifdef CONFIG_HIGHMEM
-obj-y  += highmem.o
-endif
+# Only used by sparc64
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+
+# Only used by sparc32
+obj-$(CONFIG_HIGHMEM)   += highmem.o
 
 ifdef CONFIG_SMP
-obj-y   += nosun4c.o
+obj-$(CONFIG_SPARC32) += nosun4c.o
 else
-obj-y   += sun4c.o
+obj-$(CONFIG_SPARC32) += sun4c.o
 endif
similarity index 97%
rename from arch/sparc/mm/init.c
rename to arch/sparc/mm/init_32.c
index 677c1e187a23e57b2fd2cf370b4aa1ae8a52ad4a..fec926021f4988e7d6799152eb42606c24600035 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pagemap.h>
 #include <linux/poison.h>
 
+#include <asm/sections.h>
 #include <asm/system.h>
 #include <asm/vac-ops.h>
 #include <asm/page.h>
@@ -48,9 +49,6 @@ unsigned long sparc_unmapped_base;
 
 struct pgtable_cache_struct pgt_quicklists;
 
-/* References to section boundaries */
-extern char __init_begin, __init_end, _start, _end, etext , edata;
-
 /* Initial ramdisk setup */
 extern unsigned int sparc_ramdisk_image;
 extern unsigned int sparc_ramdisk_size;
@@ -450,9 +448,9 @@ void __init mem_init(void)
        
        totalram_pages += totalhigh_pages;
 
-       codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
+       codepages = (((unsigned long) &_etext) - ((unsigned long)&_start));
        codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
-       datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
+       datapages = (((unsigned long) &_edata) - ((unsigned long)&_etext));
        datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
        initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
        initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
@@ -476,8 +474,10 @@ void __init mem_init(void)
 void free_initmem (void)
 {
        unsigned long addr;
+       unsigned long freed;
 
        addr = (unsigned long)(&__init_begin);
+       freed = (unsigned long)(&__init_end) - addr;
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                struct page *p;
 
@@ -490,8 +490,8 @@ void free_initmem (void)
                totalram_pages++;
                num_physpages++;
        }
-       printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
-               (&__init_end - &__init_begin) >> 10);
+       printk(KERN_INFO "Freeing unused kernel memory: %ldk freed\n",
+               freed >> 10);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
similarity index 99%
rename from arch/sparc64/mm/init.c
rename to arch/sparc/mm/init_64.c
index 185f34679110c3e373c99c8eaa3e569e5170c338..6ea73da29312e7397363a1c05237453e7e725c49 100644 (file)
@@ -50,7 +50,7 @@
 #include <asm/cpudata.h>
 #include <asm/irq.h>
 
-#include "init.h"
+#include "init_64.h"
 
 unsigned long kern_linear_pte_xor[2] __read_mostly;
 
@@ -214,7 +214,6 @@ static inline void set_dcache_dirty(struct page *page, int this_cpu)
                             "or        %%g1, %0, %%g1\n\t"
                             "casx      [%2], %%g7, %%g1\n\t"
                             "cmp       %%g7, %%g1\n\t"
-                            "membar    #StoreLoad | #StoreStore\n\t"
                             "bne,pn    %%xcc, 1b\n\t"
                             " nop"
                             : /* no outputs */
@@ -236,7 +235,6 @@ static inline void clear_dcache_dirty_cpu(struct page *page, unsigned long cpu)
                             " andn     %%g7, %1, %%g1\n\t"
                             "casx      [%2], %%g7, %%g1\n\t"
                             "cmp       %%g7, %%g1\n\t"
-                            "membar    #StoreLoad | #StoreStore\n\t"
                             "bne,pn    %%xcc, 1b\n\t"
                             " nop\n"
                             "2:"
@@ -956,7 +954,7 @@ int of_node_to_nid(struct device_node *dp)
        return nid;
 }
 
-static void __init add_node_ranges(void)
+static void add_node_ranges(void)
 {
        int i;
 
index daadf5f88050bb8a11ab728d8a2460233e2914ce..005e758a4db7fe9cb381c3ddd3955137298e4fad 100644 (file)
@@ -156,8 +156,8 @@ static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int
        spin_lock_irqsave(&iounit->lock, flags);
        while (sz != 0) {
                --sz;
-               sg->dvma_address = iounit_get_area(iounit, (unsigned long) sg_virt(sg), sg->length);
-               sg->dvma_length = sg->length;
+               sg->dma_address = iounit_get_area(iounit, (unsigned long) sg_virt(sg), sg->length);
+               sg->dma_length = sg->length;
                sg = sg_next(sg);
        }
        spin_unlock_irqrestore(&iounit->lock, flags);
@@ -186,8 +186,8 @@ static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg,
        spin_lock_irqsave(&iounit->lock, flags);
        while (sz != 0) {
                --sz;
-               len = ((sg->dvma_address & ~PAGE_MASK) + sg->length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
-               vaddr = (sg->dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
+               len = ((sg->dma_address & ~PAGE_MASK) + sg->length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+               vaddr = (sg->dma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
                IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
                for (len += vaddr; vaddr < len; vaddr++)
                        clear_bit(vaddr, iounit->bmap);
index e7a499e3aa3caee28e1622024c885369d876a149..b2e6e73888b52e594e0f7de258c4de76a346d8bd 100644 (file)
@@ -245,8 +245,8 @@ static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *s
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
-               sg->dvma_length = (__u32) sg->length;
+               sg->dma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
+               sg->dma_length = sg->length;
                sg = sg_next(sg);
        }
 }
@@ -259,8 +259,8 @@ static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
-               sg->dvma_length = (__u32) sg->length;
+               sg->dma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
+               sg->dma_length = sg->length;
                sg = sg_next(sg);
        }
 }
@@ -290,8 +290,8 @@ static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg
                        }
                }
 
-               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
-               sg->dvma_length = (__u32) sg->length;
+               sg->dma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
+               sg->dma_length = sg->length;
                sg = sg_next(sg);
        }
 }
@@ -330,8 +330,8 @@ static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, i
                --sz;
 
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
-               sg->dvma_address = 0x21212121;
+               iommu_release_one(dev, sg->dma_address & PAGE_MASK, n);
+               sg->dma_address = 0x21212121;
                sg = sg_next(sg);
        }
 }
index dd8aa36f366c909fe4ca13e3eab297f7700cb127..fe7ed08390bb720e1c4be141aa5a072f58b843ec 100644 (file)
@@ -1312,10 +1312,8 @@ void __init srmmu_paging_init(void)
 #endif
        poke_srmmu();
 
-#ifdef CONFIG_SUN_IO
        srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END);
        srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END);
-#endif
 
        srmmu_allocate_ptable_skeleton(
                __fix_to_virt(__end_of_fixed_addresses - 1), FIXADDR_TOP);
@@ -1916,18 +1914,6 @@ static void __cpuinit poke_viking(void)
        mreg |= VIKING_SBENABLE;
        mreg &= ~(VIKING_ACENABLE);
        srmmu_set_mmureg(mreg);
-
-#ifdef CONFIG_SMP
-       /* Avoid unnecessary cross calls. */
-       BTFIXUPCOPY_CALL(flush_cache_all, local_flush_cache_all);
-       BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm);
-       BTFIXUPCOPY_CALL(flush_cache_range, local_flush_cache_range);
-       BTFIXUPCOPY_CALL(flush_cache_page, local_flush_cache_page);
-       BTFIXUPCOPY_CALL(__flush_page_to_ram, local_flush_page_to_ram);
-       BTFIXUPCOPY_CALL(flush_sig_insns, local_flush_sig_insns);
-       BTFIXUPCOPY_CALL(flush_page_for_dma, local_flush_page_for_dma);
-       btfixup();
-#endif
 }
 
 static void __init init_viking(void)
@@ -2272,6 +2258,17 @@ void __init ld_mmu_srmmu(void)
        BTFIXUPSET_CALL(__flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM);
+
+       if (poke_srmmu == poke_viking) {
+               /* Avoid unnecessary cross calls. */
+               BTFIXUPCOPY_CALL(flush_cache_all, local_flush_cache_all);
+               BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm);
+               BTFIXUPCOPY_CALL(flush_cache_range, local_flush_cache_range);
+               BTFIXUPCOPY_CALL(flush_cache_page, local_flush_cache_page);
+               BTFIXUPCOPY_CALL(__flush_page_to_ram, local_flush_page_to_ram);
+               BTFIXUPCOPY_CALL(flush_sig_insns, local_flush_sig_insns);
+               BTFIXUPCOPY_CALL(flush_page_for_dma, local_flush_page_for_dma);
+       }
 #endif
 
        if (sparc_cpu_model == sun4d)
index fe65aeeb3947a70fafb900fb94014311f43a59df..2ffacd67c42403393013bd73cd191eddbdc3b22f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/seq_file.h>
 #include <linux/scatterlist.h>
 
+#include <asm/sections.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
@@ -240,9 +241,7 @@ void sun4c_complete_all_stores(void)
 
        _unused = sun4c_get_context();
        sun4c_set_context(_unused);
-#ifdef CONFIG_SUN_AUXIO
        _unused = get_auxio();
-#endif
 }
 
 /* Bootup utility functions. */
@@ -1124,8 +1123,8 @@ static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int s
 {
        while (sz != 0) {
                --sz;
-               sg->dvma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length);
-               sg->dvma_length = sg->length;
+               sg->dma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length);
+               sg->dma_length = sg->length;
                sg = sg_next(sg);
        }
 }
@@ -1141,7 +1140,7 @@ static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, i
 {
        while (sz != 0) {
                --sz;
-               sun4c_unlockarea((char *)sg->dvma_address, sg->length);
+               sun4c_unlockarea((char *)sg->dma_address, sg->length);
                sg = sg_next(sg);
        }
 }
@@ -1953,7 +1952,6 @@ void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, p
 }
 
 extern void sparc_context_init(int);
-extern unsigned long end;
 extern unsigned long bootmem_init(unsigned long *pages_avail);
 extern unsigned long last_valid_pfn;
 
@@ -1964,7 +1962,7 @@ void __init sun4c_paging_init(void)
        extern struct resource sparc_iomap;
        unsigned long end_pfn, pages_avail;
 
-       kernel_end = (unsigned long) &end;
+       kernel_end = (unsigned long) &_end;
        kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end);
 
        pages_avail = 0;
similarity index 100%
rename from arch/sparc64/mm/tlb.c
rename to arch/sparc/mm/tlb.c
similarity index 97%
rename from arch/sparc64/mm/tsb.c
rename to arch/sparc/mm/tsb.c
index 587f8efb2e05efb0681fec3a0c0ed0d59b87357b..36a0813f9517b39ec9b7b86c17a03233d442483e 100644 (file)
@@ -41,10 +41,8 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
                                              KERNEL_TSB_NENTRIES);
                struct tsb *ent = &swapper_tsb[hash];
 
-               if (tag_compare(ent->tag, v)) {
+               if (tag_compare(ent->tag, v))
                        ent->tag = (1UL << TSB_TAG_INVALID_BIT);
-                       membar_storeload_storestore();
-               }
        }
 }
 
@@ -267,6 +265,18 @@ void __init pgtable_cache_init(void)
        }
 }
 
+int sysctl_tsb_ratio = -2;
+
+static unsigned long tsb_size_to_rss_limit(unsigned long new_size)
+{
+       unsigned long num_ents = (new_size / sizeof(struct tsb));
+
+       if (sysctl_tsb_ratio < 0)
+               return num_ents - (num_ents >> -sysctl_tsb_ratio);
+       else
+               return num_ents + (num_ents >> sysctl_tsb_ratio);
+}
+
 /* When the RSS of an address space exceeds tsb_rss_limit for a TSB,
  * do_sparc64_fault() invokes this routine to try and grow it.
  *
@@ -297,19 +307,14 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss)
 
        new_cache_index = 0;
        for (new_size = 8192; new_size < max_tsb_size; new_size <<= 1UL) {
-               unsigned long n_entries = new_size / sizeof(struct tsb);
-
-               n_entries = (n_entries * 3) / 4;
-               if (n_entries > rss)
+               new_rss_limit = tsb_size_to_rss_limit(new_size);
+               if (new_rss_limit > rss)
                        break;
-
                new_cache_index++;
        }
 
        if (new_size == max_tsb_size)
                new_rss_limit = ~0UL;
-       else
-               new_rss_limit = ((new_size / sizeof(struct tsb)) * 3) / 4;
 
 retry_tsb_alloc:
        gfp_flags = GFP_KERNEL;
similarity index 99%
rename from arch/sparc64/mm/ultra.S
rename to arch/sparc/mm/ultra.S
index 86773e89dc1bbf29cf71831948e6d79b5d43188b..80c788ec7c321ef7738b005eb57f00e2f89e13fd 100644 (file)
@@ -125,7 +125,6 @@ __spitfire_flush_tlb_mm_slow:
        .align          32
        .globl          __flush_icache_page
 __flush_icache_page:   /* %o0 = phys_page */
-       membar          #StoreStore
        srlx            %o0, PAGE_SHIFT, %o0
        sethi           %uhi(PAGE_OFFSET), %g1
        sllx            %o0, PAGE_SHIFT, %o0
@@ -467,7 +466,7 @@ xcall_sync_tick:
        .previous
 
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        sethi           %hi(109f), %g7
        b,pt            %xcc, etrap_irq
 109:    or             %g7, %lo(109b), %g7
@@ -507,7 +506,6 @@ xcall_fetch_glob_regs:
        sllx            %g2, TRAP_BLOCK_SZ_SHIFT, %g2
        add             %g7, %g2, %g7
        ldx             [%g7 + TRAP_PER_CPU_THREAD], %g3
-       membar          #StoreStore
        stx             %g3, [%g1 + GR_SNAP_THREAD]
        retry
 
@@ -690,7 +688,7 @@ xcall_kgdb_capture:
        .previous
 
        rdpr            %pil, %g2
-       wrpr            %g0, 15, %pil
+       wrpr            %g0, PIL_NORMAL_MAX, %pil
        sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap_irq
 109:    or             %g7, %lo(109b), %g7
index 17bb6035069b7158286ebd50462aac61d07507f4..d6e170c074fc5023b1befcbd7e9525e44f7ad96a 100644 (file)
 #include <linux/errno.h>
 #include <linux/init.h>
  
+#ifdef CONFIG_SPARC64
+#include <asm/hypervisor.h>
+#include <asm/spitfire.h>
+#include <asm/cpudata.h>
+#include <asm/irq.h>
+
+static int nmi_enabled;
+
+struct pcr_ops {
+       u64 (*read)(void);
+       void (*write)(u64);
+};
+static const struct pcr_ops *pcr_ops;
+
+static u64 direct_pcr_read(void)
+{
+       u64 val;
+
+       read_pcr(val);
+       return val;
+}
+
+static void direct_pcr_write(u64 val)
+{
+       write_pcr(val);
+}
+
+static const struct pcr_ops direct_pcr_ops = {
+       .read   = direct_pcr_read,
+       .write  = direct_pcr_write,
+};
+
+static void n2_pcr_write(u64 val)
+{
+       unsigned long ret;
+
+       ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
+       if (val != HV_EOK)
+               write_pcr(val);
+}
+
+static const struct pcr_ops n2_pcr_ops = {
+       .read   = direct_pcr_read,
+       .write  = n2_pcr_write,
+};
+
+/* In order to commonize as much of the implementation as
+ * possible, we use PICH as our counter.  Mostly this is
+ * to accomodate Niagara-1 which can only count insn cycles
+ * in PICH.
+ */
+static u64 picl_value(void)
+{
+       u32 delta = local_cpu_data().clock_tick / HZ;
+
+       return ((u64)((0 - delta) & 0xffffffff)) << 32;
+}
+
+#define PCR_PIC_PRIV           0x00000001 /* PIC access is privileged */
+#define PCR_STRACE             0x00000002 /* Trace supervisor events  */
+#define PCR_UTRACE             0x00000004 /* Trace user events        */
+#define PCR_N2_HTRACE          0x00000008 /* Trace hypervisor events  */
+#define PCR_N2_TOE_OV0         0x00000010 /* Trap if PIC 0 overflows  */
+#define PCR_N2_TOE_OV1         0x00000020 /* Trap if PIC 1 overflows  */
+#define PCR_N2_MASK0           0x00003fc0
+#define PCR_N2_MASK0_SHIFT     6
+#define PCR_N2_SL0             0x0003c000
+#define PCR_N2_SL0_SHIFT       14
+#define PCR_N2_OV0             0x00040000
+#define PCR_N2_MASK1           0x07f80000
+#define PCR_N2_MASK1_SHIFT     19
+#define PCR_N2_SL1             0x78000000
+#define PCR_N2_SL1_SHIFT       27
+#define PCR_N2_OV1             0x80000000
+
+#define PCR_SUN4U_ENABLE       (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE)
+#define PCR_N2_ENABLE          (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \
+                                PCR_N2_TOE_OV1 | \
+                                (2 << PCR_N2_SL1_SHIFT) | \
+                                (0xff << PCR_N2_MASK1_SHIFT))
+
+static u64 pcr_enable = PCR_SUN4U_ENABLE;
+
+static void nmi_handler(struct pt_regs *regs)
+{
+       pcr_ops->write(PCR_PIC_PRIV);
+
+       if (nmi_enabled) {
+               oprofile_add_sample(regs, 0);
+
+               write_pic(picl_value());
+               pcr_ops->write(pcr_enable);
+       }
+}
+
+/* We count "clock cycle" events in the lower 32-bit PIC.
+ * Then configure it such that it overflows every HZ, and thus
+ * generates a level 15 interrupt at that frequency.
+ */
+static void cpu_nmi_start(void *_unused)
+{
+       pcr_ops->write(PCR_PIC_PRIV);
+       write_pic(picl_value());
+
+       pcr_ops->write(pcr_enable);
+}
+
+static void cpu_nmi_stop(void *_unused)
+{
+       pcr_ops->write(PCR_PIC_PRIV);
+}
+
+static int nmi_start(void)
+{
+       int err = register_perfctr_intr(nmi_handler);
+
+       if (!err) {
+               nmi_enabled = 1;
+               wmb();
+               err = on_each_cpu(cpu_nmi_start, NULL, 1);
+               if (err) {
+                       nmi_enabled = 0;
+                       wmb();
+                       on_each_cpu(cpu_nmi_stop, NULL, 1);
+                       release_perfctr_intr(nmi_handler);
+               }
+       }
+
+       return err;
+}
+
+static void nmi_stop(void)
+{
+       nmi_enabled = 0;
+       wmb();
+
+       on_each_cpu(cpu_nmi_stop, NULL, 1);
+       release_perfctr_intr(nmi_handler);
+       synchronize_sched();
+}
+
+static unsigned long perf_hsvc_group;
+static unsigned long perf_hsvc_major;
+static unsigned long perf_hsvc_minor;
+
+static int __init register_perf_hsvc(void)
+{
+       if (tlb_type == hypervisor) {
+               switch (sun4v_chip_type) {
+               case SUN4V_CHIP_NIAGARA1:
+                       perf_hsvc_group = HV_GRP_NIAG_PERF;
+                       break;
+
+               case SUN4V_CHIP_NIAGARA2:
+                       perf_hsvc_group = HV_GRP_N2_CPU;
+                       break;
+
+               default:
+                       return -ENODEV;
+               }
+
+
+               perf_hsvc_major = 1;
+               perf_hsvc_minor = 0;
+               if (sun4v_hvapi_register(perf_hsvc_group,
+                                        perf_hsvc_major,
+                                        &perf_hsvc_minor)) {
+                       printk("perfmon: Could not register N2 hvapi.\n");
+                       return -ENODEV;
+               }
+       }
+       return 0;
+}
+
+static void unregister_perf_hsvc(void)
+{
+       if (tlb_type != hypervisor)
+               return;
+       sun4v_hvapi_unregister(perf_hsvc_group);
+}
+
+static int oprofile_nmi_init(struct oprofile_operations *ops)
+{
+       int err = register_perf_hsvc();
+
+       if (err)
+               return err;
+
+       switch (tlb_type) {
+       case hypervisor:
+               pcr_ops = &n2_pcr_ops;
+               pcr_enable = PCR_N2_ENABLE;
+               break;
+
+       case cheetah:
+       case cheetah_plus:
+               pcr_ops = &direct_pcr_ops;
+               break;
+
+       default:
+               return -ENODEV;
+       }
+
+       ops->create_files = NULL;
+       ops->setup = NULL;
+       ops->shutdown = NULL;
+       ops->start = nmi_start;
+       ops->stop = nmi_stop;
+       ops->cpu_type = "timer";
+
+       printk(KERN_INFO "oprofile: Using perfctr based NMI timer interrupt.\n");
+
+       return 0;
+}
+#endif
+
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       return -ENODEV;
+       int ret = -ENODEV;
+
+#ifdef CONFIG_SPARC64
+       ret = oprofile_nmi_init(ops);
+       if (!ret)
+               return ret;
+#endif
+
+       return ret;
 }
 
 
 void oprofile_arch_exit(void)
 {
+#ifdef CONFIG_SPARC64
+       unregister_perf_hsvc();
+#endif
 }
index 8f7e18546c974f6ba8fec1c6ec8befcc21d5d30d..1b8c073adb44fe341b883f87865b28531d61b95f 100644 (file)
@@ -1,6 +1,21 @@
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
+asflags := -ansi
+ccflags := -Werror
 
-lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
-        palloc.o ranges.o segment.o console.o printf.o tree.o
+lib-y                 := bootstr_$(BITS).o
+lib-$(CONFIG_SPARC32) += devmap.o
+lib-y                 += devops_$(BITS).o
+lib-y                 += init_$(BITS).o
+lib-$(CONFIG_SPARC32) += memory.o
+lib-y                 += misc_$(BITS).o
+lib-$(CONFIG_SPARC32) += mp.o
+lib-$(CONFIG_SPARC32) += palloc.o
+lib-$(CONFIG_SPARC32) += ranges.o
+lib-$(CONFIG_SPARC32) += segment.o
+lib-y                 += console_$(BITS).o
+lib-y                 += printf.o
+lib-y                 += tree_$(BITS).o
+lib-$(CONFIG_SPARC64) += p1275.o
+lib-$(CONFIG_SPARC64) += cif.o
similarity index 98%
rename from arch/sparc/prom/misc.c
rename to arch/sparc/prom/misc_32.c
index 49b5057b9601000660e42220eb5e49d565f83604..cf6c3f6d36c3d6bdecc41edc37aa3436e1a1726e 100644 (file)
@@ -61,9 +61,7 @@ prom_cmdline(void)
        restore_current();
        install_linux_ticker();
        spin_unlock_irqrestore(&prom_lock, flags);
-#ifdef CONFIG_SUN_AUXIO
        set_auxio(AUXIO_LED, 0);
-#endif
 }
 
 /* Drop into the prom, but completely terminate the program.
index a36ab9c5ee08758f0dbf6c667e039e6a1d403ee4..660943ee4c2ac7e431822dc1f99cf9e8bac294e7 100644 (file)
@@ -2,6 +2,7 @@
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
  *
  * We used to warn all over the code: DO NOT USE prom_printf(),
@@ -13,7 +14,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -34,7 +34,7 @@ prom_write(const char *buf, unsigned int n)
 }
 
 void
-prom_printf(char *fmt, ...)
+prom_printf(const char *fmt, ...)
 {
        va_list args;
        int i;
@@ -45,4 +45,3 @@ prom_printf(char *fmt, ...)
 
        prom_write(ppbuf, i);
 }
-EXPORT_SYMBOL(prom_printf);
similarity index 97%
rename from arch/sparc/prom/tree.c
rename to arch/sparc/prom/tree_32.c
index f228fe057b243f80dacf0948038a2311cc0e9ac5..6d81873573311a1d7b4093ae185fd062e546ea32 100644 (file)
@@ -85,7 +85,7 @@ int prom_getsibling(int node)
 /* Return the length in bytes of property 'prop' at node 'node'.
  * Return -1 on error.
  */
-int prom_getproplen(int node, char *prop)
+int prom_getproplen(int node, const char *prop)
 {
        int ret;
        unsigned long flags;
@@ -104,7 +104,7 @@ int prom_getproplen(int node, char *prop)
  * 'buffer' which has a size of 'bufsize'.  If the acquisition
  * was successful the length will be returned, else -1 is returned.
  */
-int prom_getproperty(int node, char *prop, char *buffer, int bufsize)
+int prom_getproperty(int node, const char *prop, char *buffer, int bufsize)
 {
        int plen, ret;
        unsigned long flags;
@@ -303,7 +303,7 @@ int prom_node_has_property(int node, char *prop)
 /* Set property 'pname' at node 'node' to value 'value' which has a length
  * of 'size' bytes.  Return the number of bytes the prom accepted.
  */
-int prom_setprop(int node, char *pname, char *value, int size)
+int prom_setprop(int node, const char *pname, char *value, int size)
 {
        unsigned long flags;
        int ret;
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
deleted file mode 100644 (file)
index 3b96e70..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-# sparc64 configuration
-mainmenu "Linux Kernel Configuration for 64-bit SPARC"
-
-config SPARC
-       bool
-       default y
-       select HAVE_OPROFILE
-       select HAVE_KPROBES
-       select HAVE_KRETPROBES
-
-config SPARC64
-       bool
-       default y
-       select HAVE_FUNCTION_TRACER
-       select HAVE_IDE
-       select HAVE_LMB
-       select HAVE_ARCH_KGDB
-       select USE_GENERIC_SMP_HELPERS if SMP
-       select HAVE_ARCH_TRACEHOOK
-       select ARCH_WANT_OPTIONAL_GPIOLIB
-       select RTC_CLASS
-       select RTC_DRV_M48T59
-       select RTC_DRV_CMOS
-       select RTC_DRV_BQ4802
-       select RTC_DRV_SUN4V
-       select RTC_DRV_STARFIRE
-
-config GENERIC_TIME
-       bool
-       default y
-
-config GENERIC_CMOS_UPDATE
-       bool
-       default y
-
-config GENERIC_CLOCKEVENTS
-       bool
-       default y
-
-config GENERIC_GPIO
-       bool
-       help
-         Generic GPIO API support
-
-config 64BIT
-       def_bool y
-
-config MMU
-       bool
-       default y
-
-config IOMMU_HELPER
-       bool
-       default y
-
-config QUICKLIST
-       bool
-       default y
-
-config STACKTRACE_SUPPORT
-       bool
-       default y
-
-config LOCKDEP_SUPPORT
-       bool
-       default y
-
-config ARCH_MAY_HAVE_PC_FDC
-       bool
-       default y
-
-config ARCH_HAS_ILOG2_U32
-       bool
-       default n
-
-config ARCH_HAS_ILOG2_U64
-       bool
-       default n
-
-config AUDIT_ARCH
-       bool
-       default y
-
-config HAVE_SETUP_PER_CPU_AREA
-       def_bool y
-
-config ARCH_NO_VIRT_TO_BUS
-       def_bool y
-
-config OF
-       def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       bool
-       def_bool y
-
-source "init/Kconfig"
-source "kernel/Kconfig.freezer"
-
-menu "Processor type and features"
-
-choice
-       prompt "Kernel page size"
-       default SPARC64_PAGE_SIZE_8KB
-
-config SPARC64_PAGE_SIZE_8KB
-       bool "8KB"
-       help
-         This lets you select the page size of the kernel.
-
-         8KB and 64KB work quite well, since SPARC ELF sections
-         provide for up to 64KB alignment.
-
-         If you don't know what to do, choose 8KB.
-
-config SPARC64_PAGE_SIZE_64KB
-       bool "64KB"
-
-endchoice
-
-config SECCOMP
-       bool "Enable seccomp to safely compute untrusted bytecode"
-       depends on PROC_FS
-       default y
-       help
-         This kernel feature is useful for number crunching applications
-         that may need to compute untrusted bytecode during their
-         execution. By using pipes or other transports made available to
-         the process as file descriptors supporting the read/write
-         syscalls, it's possible to isolate those applications in
-         their own address space using seccomp. Once seccomp is
-         enabled via /proc/<pid>/seccomp, it cannot be disabled
-         and the task is only allowed to execute a few safe syscalls
-         defined by each seccomp mode.
-
-         If unsure, say Y. Only embedded should say N here.
-
-source kernel/Kconfig.hz
-
-config HOTPLUG_CPU
-       bool "Support for hot-pluggable CPUs"
-       depends on SMP
-       select HOTPLUG
-       help
-         Say Y here to experiment with turning CPUs off and on.  CPUs
-         can be controlled through /sys/devices/system/cpu/cpu#.
-         Say N if you want to disable CPU hotplug.
-
-config GENERIC_HARDIRQS
-       bool
-       default y
-
-source "kernel/time/Kconfig"
-
-config SMP
-       bool "Symmetric multi-processing support"
-       help
-         This enables support for systems with more than one CPU. If you have
-         a system with only one CPU, say N. If you have a system with more than
-         one CPU, say Y.
-
-         If you say N here, the kernel will run on single and multiprocessor
-         machines, but will use only one CPU of a multiprocessor machine. If
-         you say Y here, the kernel will run on single-processor machines.
-         On a single-processor machine, the kernel will run faster if you say
-         N here.
-
-         If you don't know what to do here, say N.
-
-config NR_CPUS
-       int "Maximum number of CPUs (2-1024)"
-       range 2 1024
-       depends on SMP
-       default "64"
-
-source "drivers/cpufreq/Kconfig"
-
-config US3_FREQ
-       tristate "UltraSPARC-III CPU Frequency driver"
-       depends on CPU_FREQ
-       select CPU_FREQ_TABLE
-       help
-         This adds the CPUFreq driver for UltraSPARC-III processors.
-
-         For details, take a look at <file:Documentation/cpu-freq>.
-
-         If in doubt, say N.
-
-config US2E_FREQ
-       tristate "UltraSPARC-IIe CPU Frequency driver"
-       depends on CPU_FREQ
-       select CPU_FREQ_TABLE
-       help
-         This adds the CPUFreq driver for UltraSPARC-IIe processors.
-
-         For details, take a look at <file:Documentation/cpu-freq>.
-
-         If in doubt, say N.
-
-config US3_MC
-       tristate "UltraSPARC-III Memory Controller driver"
-       default y
-       help
-         This adds a driver for the UltraSPARC-III memory controller.
-         Loading this driver allows exact mnemonic strings to be
-         printed in the event of a memory error, so that the faulty DIMM
-         on the motherboard can be matched to the error.
-
-         If in doubt, say Y, as this information can be very useful.
-
-# Global things across all Sun machines.
-config GENERIC_LOCKBREAK
-       bool
-       default y
-       depends on SMP && PREEMPT
-
-config RWSEM_GENERIC_SPINLOCK
-       bool
-
-config RWSEM_XCHGADD_ALGORITHM
-       bool
-       default y
-
-config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
-
-config GENERIC_HWEIGHT
-       bool
-       default y if !ULTRA_HAS_POPULATION_COUNT
-
-config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
-
-choice
-       prompt "SPARC64 Huge TLB Page Size"
-       depends on HUGETLB_PAGE
-       default HUGETLB_PAGE_SIZE_4MB
-
-config HUGETLB_PAGE_SIZE_4MB
-       bool "4MB"
-
-config HUGETLB_PAGE_SIZE_512K
-       bool "512K"
-
-config HUGETLB_PAGE_SIZE_64K
-       depends on !SPARC64_PAGE_SIZE_64KB
-       bool "64K"
-
-endchoice
-
-endmenu
-
-config NUMA
-       bool "NUMA support"
-       depends on SMP
-
-config NODES_SHIFT
-       int
-       default "4"
-       depends on NEED_MULTIPLE_NODES
-
-# Some NUMA nodes have memory ranges that span
-# other nodes.  Even though a pfn is valid and
-# between a node's start and end pfns, it may not
-# reside on that node.  See memmap_init_zone()
-# for details.
-config NODES_SPAN_OTHER_NODES
-       def_bool y
-       depends on NEED_MULTIPLE_NODES
-
-config ARCH_POPULATES_NODE_MAP
-       def_bool y
-
-config ARCH_SELECT_MEMORY_MODEL
-       def_bool y
-
-config ARCH_SPARSEMEM_ENABLE
-       def_bool y
-       select SPARSEMEM_VMEMMAP_ENABLE
-
-config ARCH_SPARSEMEM_DEFAULT
-       def_bool y
-
-source "mm/Kconfig"
-
-config ISA
-       bool
-
-config ISAPNP
-       bool
-
-config EISA
-       bool
-
-config MCA
-       bool
-
-config PCMCIA
-       tristate
-       help
-         Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
-         computer.  These are credit-card size devices such as network cards,
-         modems or hard drives often used with laptops computers.  There are
-         actually two varieties of these cards: the older 16 bit PCMCIA cards
-         and the newer 32 bit CardBus cards.  If you want to use CardBus
-         cards, you need to say Y here and also to "CardBus support" below.
-
-         To use your PC-cards, you will need supporting software from David
-         Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-         for location).  Please also read the PCMCIA-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as modules, choose M here: the
-         modules will be called pcmcia_core and ds.
-
-config SBUS
-       bool
-       default y
-
-config SBUSCHAR
-       bool
-       default y
-
-config SUN_AUXIO
-       bool
-       default y
-
-config SUN_IO
-       bool
-       default y
-
-config SUN_LDOMS
-       bool "Sun Logical Domains support"
-       help
-         Say Y here is you want to support virtual devices via
-         Logical Domains.
-
-config PCI
-       bool "PCI support"
-       select ARCH_SUPPORTS_MSI
-       help
-         Find out whether your system includes a PCI bus. PCI is the name of
-         a bus system, i.e. the way the CPU talks to the other stuff inside
-         your box.  If you say Y here, the kernel will include drivers and
-         infrastructure code to support PCI bus devices.
-
-config PCI_DOMAINS
-       def_bool PCI
-
-config PCI_SYSCALL
-       def_bool PCI
-
-source "drivers/pci/Kconfig"
-
-config SUN_OPENPROMFS
-       tristate "Openprom tree appears in /proc/openprom"
-       help
-         If you say Y, the OpenPROM device tree will be available as a
-         virtual file system, which you can mount to /proc/openprom by "mount
-         -t openpromfs none /proc/openprom".
-
-         To compile the /proc/openprom support as a module, choose M here: the
-         module will be called openpromfs.  If unsure, choose M.
-
-menu "Executable file formats"
-
-source "fs/Kconfig.binfmt"
-
-config COMPAT
-       bool
-       default y
-       select COMPAT_BINFMT_ELF
-
-config SYSVIPC_COMPAT
-       bool
-       depends on COMPAT && SYSVIPC
-       default y
-
-endmenu
-
-config SCHED_SMT
-       bool "SMT (Hyperthreading) scheduler support"
-       depends on SMP
-       default y
-       help
-         SMT scheduler support improves the CPU scheduler's decision making
-         when dealing with SPARC cpus at a cost of slightly increased overhead
-         in some places. If unsure say N here.
-
-config SCHED_MC
-       bool "Multi-core scheduler support"
-       depends on SMP
-       default y
-       help
-         Multi-core scheduler support improves the CPU scheduler's decision
-         making when dealing with multi-core CPU chips at a cost of slightly
-         increased overhead in some places. If unsure say N here.
-
-source "kernel/Kconfig.preempt"
-
-config CMDLINE_BOOL
-       bool "Default bootloader kernel arguments"
-
-config CMDLINE
-       string "Initial kernel command string"
-       depends on CMDLINE_BOOL
-       default "console=ttyS0,9600 root=/dev/sda1"
-       help
-         Say Y here if you want to be able to pass default arguments to
-         the kernel. This will be overridden by the bootloader, if you
-         use one (such as SILO). This is most useful if you want to boot
-         a kernel from TFTP, and want default options to be available
-         with having them passed on the command line.
-
-         NOTE: This option WILL override the PROM bootargs setting!
-
-source "net/Kconfig"
-
-source "drivers/Kconfig"
-
-source "drivers/sbus/char/Kconfig"
-
-source "fs/Kconfig"
-
-source "arch/sparc64/Kconfig.debug"
-
-source "security/Kconfig"
-
-source "crypto/Kconfig"
-
-source "lib/Kconfig"
diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug
deleted file mode 100644 (file)
index c40515c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-menu "Kernel hacking"
-
-config TRACE_IRQFLAGS_SUPPORT
-       bool
-       default y
-
-source "lib/Kconfig.debug"
-
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
-config DEBUG_DCFLUSH
-       bool "D-cache flush debugging"
-       depends on DEBUG_KERNEL
-
-config STACK_DEBUG
-       depends on DEBUG_KERNEL
-       bool "Stack Overflow Detection Support"
-
-config DEBUG_PAGEALLOC
-       bool "Debug page memory allocations"
-       depends on DEBUG_KERNEL && !HIBERNATION
-       help
-         Unmap pages from the kernel linear mapping after free_pages().
-         This results in a large slowdown, but helps to find certain types
-         of memory corruptions.
-
-config MCOUNT
-       bool
-       depends on STACK_DEBUG || FUNCTION_TRACER
-       default y
-
-config FRAME_POINTER
-       bool
-       depends on MCOUNT
-       default y
-
-endmenu
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
deleted file mode 100644 (file)
index c7214ab..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-# sparc64/Makefile
-#
-# Makefile for the architecture dependent flags and dependencies on the
-# 64-bit Sparc.
-#
-# Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu)
-# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
-#
-
-CHECKFLAGS     += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
-
-# Undefine sparc when processing vmlinux.lds - it is used
-# And teach CPP we are doing 64 bit builds (for this case)
-CPPFLAGS_vmlinux.lds += -m64 -Usparc
-
-LDFLAGS                := -m elf64_sparc
-
-KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
-       -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
-       -Wa,--undeclared-regs
-KBUILD_CFLAGS += $(call cc-option,-mtune=ultrasparc3)
-KBUILD_AFLAGS += -m64 -mcpu=ultrasparc -Wa,--undeclared-regs
-
-ifeq ($(CONFIG_MCOUNT),y)
-  KBUILD_CFLAGS += -pg
-endif
-
-head-y := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
-
-core-y                         += arch/sparc64/kernel/ arch/sparc64/mm/
-core-y                         += arch/sparc64/math-emu/
-libs-y                         += arch/sparc64/prom/ arch/sparc64/lib/
-drivers-$(CONFIG_OPROFILE)     += arch/sparc64/oprofile/
-
-boot := arch/sparc64/boot
-
-image tftpboot.img vmlinux.aout: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
-
-archclean:
-       $(Q)$(MAKE) $(clean)=$(boot)
-
-define archhelp
-  echo  '* vmlinux       - Standard sparc64 kernel'
-  echo  '  vmlinux.aout  - a.out kernel for sparc64'
-  echo  '  tftpboot.img  - Image prepared for tftp'
-endef
-
diff --git a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile
deleted file mode 100644 (file)
index 0458b52..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# Makefile for the Sparc64 boot stuff.
-#
-# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
-
-ROOT_IMG       := /usr/src/root.img
-ELFTOAOUT      := elftoaout
-
-hostprogs-y    := piggyback
-targets                := image tftpboot.img vmlinux.aout
-
-quiet_cmd_elftoaout = ELF2AOUT $@
-      cmd_elftoaout = $(ELFTOAOUT) vmlinux -o $@
-quiet_cmd_piggy     = PIGGY   $@
-      cmd_piggy     = $(obj)/piggyback $@ System.map $(ROOT_IMG)
-quiet_cmd_strip     = STRIP   $@
-      cmd_strip     = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@
-
-
-# Actual linking
-$(obj)/image: vmlinux FORCE
-       $(call if_changed,strip)
-       @echo '  kernel: $@ is ready'
-
-$(obj)/tftpboot.img: vmlinux $(obj)/piggyback System.map $(ROOT_IMG) FORCE
-       $(call if_changed,elftoaout)
-       $(call if_changed,piggy)
-       @echo '  kernel: $@ is ready'
-
-$(obj)/vmlinux.aout: vmlinux FORCE
-       $(call if_changed,elftoaout)
-       @echo '  kernel: $@ is ready'
-
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
deleted file mode 100644 (file)
index b3e0b98..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-EXTRA_AFLAGS := -ansi
-EXTRA_CFLAGS := -Werror
-
-CFLAGS_REMOVE_ftrace.o = -pg
-
-extra-y                := head.o init_task.o vmlinux.lds
-
-obj-y          := process.o setup.o cpu.o idprom.o reboot.o \
-                  traps.o auxio.o una_asm.o sysfs.o iommu.o \
-                  irq.o ptrace.o time.o sys_sparc.o signal.o \
-                  unaligned.o central.o starfire.o \
-                  power.o sbus.o sparc64_ksyms.o ebus.o \
-                  visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
-
-obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
-obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI)       += pci.o pci_common.o psycho_common.o \
-                           pci_psycho.o pci_sabre.o pci_schizo.o \
-                           pci_sun4v.o pci_sun4v_asm.o pci_fire.o
-obj-$(CONFIG_PCI_MSI)  += pci_msi.o
-obj-$(CONFIG_SMP)       += smp.o trampoline.o hvtramp.o
-obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
-obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
-obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
-obj-$(CONFIG_US3_MC) += chmc.o
-obj-$(CONFIG_KPROBES) += kprobes.o
-obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
-obj-$(CONFIG_AUDIT) += audit.o
-obj-$(CONFIG_AUDIT)$(CONFIG_COMPAT) += compat_audit.o
-obj-y += $(obj-yy)
-obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/sparc64/kernel/asm-offsets.c b/arch/sparc64/kernel/asm-offsets.c
deleted file mode 100644 (file)
index 9e26311..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* Dummy asm-offsets.c file. Required by kbuild and ready to be used - hint! */
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
deleted file mode 100644 (file)
index 0c9ac83..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/* cpu.c: Dinky routines to look for the kind of Sparc cpu
- *        we are on.
- *
- * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <asm/asi.h>
-#include <asm/system.h>
-#include <asm/fpumacro.h>
-#include <asm/cpudata.h>
-#include <asm/spitfire.h>
-#include <asm/oplib.h>
-
-#include "entry.h"
-
-DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
-
-struct cpu_chip_info {
-       unsigned short  manuf;
-       unsigned short  impl;
-       const char      *cpu_name;
-       const char      *fp_name;
-};
-
-static const struct cpu_chip_info cpu_chips[] = {
-       {
-               .manuf          = 0x17,
-               .impl           = 0x10,
-               .cpu_name       = "TI UltraSparc I   (SpitFire)",
-               .fp_name        = "UltraSparc I integrated FPU",
-       },
-       {
-               .manuf          = 0x22,
-               .impl           = 0x10,
-               .cpu_name       = "TI UltraSparc I   (SpitFire)",
-               .fp_name        = "UltraSparc I integrated FPU",
-       },
-       {
-               .manuf          = 0x17,
-               .impl           = 0x11,
-               .cpu_name       = "TI UltraSparc II  (BlackBird)",
-               .fp_name        = "UltraSparc II integrated FPU",
-       },
-       {
-               .manuf          = 0x17,
-               .impl           = 0x12,
-               .cpu_name       = "TI UltraSparc IIi (Sabre)",
-               .fp_name        = "UltraSparc IIi integrated FPU",
-       },
-       {
-               .manuf          = 0x17,
-               .impl           = 0x13,
-               .cpu_name       = "TI UltraSparc IIe (Hummingbird)",
-               .fp_name        = "UltraSparc IIe integrated FPU",
-       },
-       {
-               .manuf          = 0x3e,
-               .impl           = 0x14,
-               .cpu_name       = "TI UltraSparc III (Cheetah)",
-               .fp_name        = "UltraSparc III integrated FPU",
-       },
-       {
-               .manuf          = 0x3e,
-               .impl           = 0x15,
-               .cpu_name       = "TI UltraSparc III+ (Cheetah+)",
-               .fp_name        = "UltraSparc III+ integrated FPU",
-       },
-       {
-               .manuf          = 0x3e,
-               .impl           = 0x16,
-               .cpu_name       = "TI UltraSparc IIIi (Jalapeno)",
-               .fp_name        = "UltraSparc IIIi integrated FPU",
-       },
-       {
-               .manuf          = 0x3e,
-               .impl           = 0x18,
-               .cpu_name       = "TI UltraSparc IV (Jaguar)",
-               .fp_name        = "UltraSparc IV integrated FPU",
-       },
-       {
-               .manuf          = 0x3e,
-               .impl           = 0x19,
-               .cpu_name       = "TI UltraSparc IV+ (Panther)",
-               .fp_name        = "UltraSparc IV+ integrated FPU",
-       },
-       {
-               .manuf          = 0x3e,
-               .impl           = 0x22,
-               .cpu_name       = "TI UltraSparc IIIi+ (Serrano)",
-               .fp_name        = "UltraSparc IIIi+ integrated FPU",
-       },
-};
-
-#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
-
-const char *sparc_cpu_type;
-const char *sparc_fpu_type;
-
-static void __init sun4v_cpu_probe(void)
-{
-       switch (sun4v_chip_type) {
-       case SUN4V_CHIP_NIAGARA1:
-               sparc_cpu_type = "UltraSparc T1 (Niagara)";
-               sparc_fpu_type = "UltraSparc T1 integrated FPU";
-               break;
-
-       case SUN4V_CHIP_NIAGARA2:
-               sparc_cpu_type = "UltraSparc T2 (Niagara2)";
-               sparc_fpu_type = "UltraSparc T2 integrated FPU";
-               break;
-
-       default:
-               printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
-                      prom_cpu_compatible);
-               sparc_cpu_type = "Unknown SUN4V CPU";
-               sparc_fpu_type = "Unknown SUN4V FPU";
-               break;
-       }
-}
-
-static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf,
-                                                        unsigned short impl)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) {
-               const struct cpu_chip_info *p = &cpu_chips[i];
-
-               if (p->manuf == manuf && p->impl == impl)
-                       return p;
-       }
-       return NULL;
-}
-
-static int __init cpu_type_probe(void)
-{
-       if (tlb_type == hypervisor) {
-               sun4v_cpu_probe();
-       } else {
-               unsigned long ver, manuf, impl;
-               const struct cpu_chip_info *p;
-       
-               __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
-       
-               manuf = ((ver >> 48) & 0xffff);
-               impl = ((ver >> 32) & 0xffff);
-
-               p = find_cpu_chip(manuf, impl);
-               if (p) {
-                       sparc_cpu_type = p->cpu_name;
-                       sparc_fpu_type = p->fp_name;
-               } else {
-                       printk(KERN_ERR "CPU: Unknown chip, manuf[%lx] impl[%lx]\n",
-                              manuf, impl);
-                       sparc_cpu_type = "Unknown CPU";
-                       sparc_fpu_type = "Unknown FPU";
-               }
-       }
-       return 0;
-}
-
-arch_initcall(cpu_type_probe);
diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c
deleted file mode 100644 (file)
index a62ff83..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * idprom.c: Routines to load the idprom into kernel addresses and
- *           interpret the data contained within.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-
-struct idprom *idprom;
-static struct idprom idprom_buffer;
-
-/* Calculate the IDPROM checksum (xor of the data bytes). */
-static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
-{
-       unsigned char cksum, i, *ptr = (unsigned char *)idprom;
-
-       for (i = cksum = 0; i <= 0x0E; i++)
-               cksum ^= *ptr++;
-
-       return cksum;
-}
-
-/* Create a local IDPROM copy and verify integrity. */
-void __init idprom_init(void)
-{
-       prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
-
-       idprom = &idprom_buffer;
-
-       if (idprom->id_format != 0x01)  {
-               prom_printf("IDPROM: Warning, unknown format type!\n");
-       }
-
-       if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
-               prom_printf("IDPROM: Warning, checksum failure (nvram=%x, calc=%x)!\n",
-                           idprom->id_cksum, calc_idprom_cksum(idprom));
-       }
-
-       printk("Ethernet address: %pM\n", idprom->id_ethaddr);
-}
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
deleted file mode 100644 (file)
index d2b3123..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/init_task.h>
-#include <linux/mqueue.h>
-
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-static struct fs_struct init_fs = INIT_FS;
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
-/* .text section in head.S is aligned at 2 page boundary and this gets linked
- * right after that so that the init_thread_union is aligned properly as well.
- * We really don't need this special alignment like the Intel does, but
- * I do it anyways for completeness.
- */
-__asm__ (".text");
-union thread_union init_thread_union = { INIT_THREAD_INFO(init_task) };
-
-/*
- * Initial task structure.
- *
- * All other task structs will be allocated on slabs in fork.c
- */
-EXPORT_SYMBOL(init_task);
-
-__asm__(".data");
-struct task_struct init_task = INIT_TASK(init_task);
diff --git a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c
deleted file mode 100644 (file)
index 158484b..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/* Kernel module help for sparc64.
- *
- * Copyright (C) 2001 Rusty Russell.
- * Copyright (C) 2002 David S. Miller.
- */
-
-#include <linux/moduleloader.h>
-#include <linux/kernel.h>
-#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#include <asm/processor.h>
-#include <asm/spitfire.h>
-
-static void *module_map(unsigned long size)
-{
-       struct vm_struct *area;
-
-       size = PAGE_ALIGN(size);
-       if (!size || size > MODULES_LEN)
-               return NULL;
-
-       area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
-       if (!area)
-               return NULL;
-
-       return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
-}
-
-void *module_alloc(unsigned long size)
-{
-       void *ret;
-
-       /* We handle the zero case fine, unlike vmalloc */
-       if (size == 0)
-               return NULL;
-
-       ret = module_map(size);
-       if (!ret)
-               ret = ERR_PTR(-ENOMEM);
-       else
-               memset(ret, 0, size);
-
-       return ret;
-}
-
-/* Free memory returned from module_core_alloc/module_init_alloc */
-void module_free(struct module *mod, void *module_region)
-{
-       vfree(module_region);
-       /* FIXME: If module_region == mod->init_region, trim exception
-           table entries. */
-}
-
-/* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
-int module_frob_arch_sections(Elf_Ehdr *hdr,
-                             Elf_Shdr *sechdrs,
-                             char *secstrings,
-                             struct module *mod)
-{
-       unsigned int symidx;
-       Elf64_Sym *sym;
-       const char *strtab;
-       int i;
-
-       for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
-               if (symidx == hdr->e_shnum-1) {
-                       printk("%s: no symtab found.\n", mod->name);
-                       return -ENOEXEC;
-               }
-       }
-       sym = (Elf64_Sym *)sechdrs[symidx].sh_addr;
-       strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
-
-       for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
-               if (sym[i].st_shndx == SHN_UNDEF &&
-                   ELF64_ST_TYPE(sym[i].st_info) == STT_REGISTER)
-                       sym[i].st_shndx = SHN_ABS;
-       }
-       return 0;
-}
-
-int apply_relocate(Elf64_Shdr *sechdrs,
-                  const char *strtab,
-                  unsigned int symindex,
-                  unsigned int relsec,
-                  struct module *me)
-{
-       printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n",
-              me->name);
-       return -ENOEXEC;
-}
-
-int apply_relocate_add(Elf64_Shdr *sechdrs,
-                      const char *strtab,
-                      unsigned int symindex,
-                      unsigned int relsec,
-                      struct module *me)
-{
-       unsigned int i;
-       Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-       Elf64_Sym *sym;
-       u8 *location;
-       u32 *loc32;
-
-       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-               Elf64_Addr v;
-
-               /* This is where to make the change */
-               location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-                       + rel[i].r_offset;
-               loc32 = (u32 *) location;
-
-               BUG_ON(((u64)location >> (u64)32) != (u64)0);
-
-               /* This is the symbol it is referring to.  Note that all
-                  undefined symbols have been resolved.  */
-               sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
-                       + ELF64_R_SYM(rel[i].r_info);
-               v = sym->st_value + rel[i].r_addend;
-
-               switch (ELF64_R_TYPE(rel[i].r_info) & 0xff) {
-               case R_SPARC_64:
-                       location[0] = v >> 56;
-                       location[1] = v >> 48;
-                       location[2] = v >> 40;
-                       location[3] = v >> 32;
-                       location[4] = v >> 24;
-                       location[5] = v >> 16;
-                       location[6] = v >>  8;
-                       location[7] = v >>  0;
-                       break;
-
-               case R_SPARC_32:
-                       location[0] = v >> 24;
-                       location[1] = v >> 16;
-                       location[2] = v >>  8;
-                       location[3] = v >>  0;
-                       break;
-
-               case R_SPARC_DISP32:
-                       v -= (Elf64_Addr) location;
-                       *loc32 = v;
-                       break;
-
-               case R_SPARC_WDISP30:
-                       v -= (Elf64_Addr) location;
-                       *loc32 = (*loc32 & ~0x3fffffff) |
-                               ((v >> 2) & 0x3fffffff);
-                       break;
-
-               case R_SPARC_WDISP22:
-                       v -= (Elf64_Addr) location;
-                       *loc32 = (*loc32 & ~0x3fffff) |
-                               ((v >> 2) & 0x3fffff);
-                       break;
-
-               case R_SPARC_WDISP19:
-                       v -= (Elf64_Addr) location;
-                       *loc32 = (*loc32 & ~0x7ffff) |
-                               ((v >> 2) & 0x7ffff);
-                       break;
-
-               case R_SPARC_LO10:
-                       *loc32 = (*loc32 & ~0x3ff) | (v & 0x3ff);
-                       break;
-
-               case R_SPARC_HI22:
-                       *loc32 = (*loc32 & ~0x3fffff) |
-                               ((v >> 10) & 0x3fffff);
-                       break;
-
-               case R_SPARC_OLO10:
-                       *loc32 = (*loc32 & ~0x1fff) |
-                               (((v & 0x3ff) +
-                                 (ELF64_R_TYPE(rel[i].r_info) >> 8))
-                                & 0x1fff);
-                       break;
-
-               default:
-                       printk(KERN_ERR "module %s: Unknown relocation: %x\n",
-                              me->name,
-                              (int) (ELF64_R_TYPE(rel[i].r_info) & 0xff));
-                       return -ENOEXEC;
-               };
-       }
-       return 0;
-}
-
-int module_finalize(const Elf_Ehdr *hdr,
-                   const Elf_Shdr *sechdrs,
-                   struct module *me)
-{
-       /* Cheetah's I-cache is fully coherent.  */
-       if (tlb_type == spitfire) {
-               unsigned long va;
-
-               flushw_all();
-               for (va =  0; va < (PAGE_SIZE << 1); va += 32)
-                       spitfire_put_icache_tag(va, 0x0);
-               __asm__ __volatile__("flush %g6");
-       }
-
-       return 0;
-}
-
-void module_arch_cleanup(struct module *mod)
-{
-}
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
deleted file mode 100644 (file)
index 01f8096..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* ld script to make UltraLinux kernel */
-
-#include <asm/page.h>
-#include <asm-generic/vmlinux.lds.h>
-
-OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc")
-OUTPUT_ARCH(sparc:v9a)
-ENTRY(_start)
-
-jiffies = jiffies_64;
-SECTIONS
-{
-       swapper_low_pmd_dir = 0x0000000000402000;
-       . = 0x4000;
-       .text 0x0000000000404000 : {
-               _text = .;
-               TEXT_TEXT
-               SCHED_TEXT
-               LOCK_TEXT
-               KPROBES_TEXT
-               *(.gnu.warning)
-       } = 0
-       _etext = .;
-       PROVIDE (etext = .);
-
-       RO_DATA(PAGE_SIZE)
-       .data : {
-               DATA_DATA
-               CONSTRUCTORS
-       }
-       .data1 : {
-               *(.data1)
-       }
-       . = ALIGN(64);
-       .data.cacheline_aligned : {
-               *(.data.cacheline_aligned)
-       }
-       . = ALIGN(64);
-       .data.read_mostly : {
-               *(.data.read_mostly)
-       }
-       _edata = .;
-       PROVIDE (edata = .);
-       .fixup : {
-               *(.fixup)
-       }
-       . = ALIGN(16);
-       __ex_table : {
-               __start___ex_table = .;
-               *(__ex_table)
-               __stop___ex_table = .;
-       }
-       NOTES
-
-       . = ALIGN(PAGE_SIZE);
-       .init.text : {
-               __init_begin = .;
-               _sinittext = .;
-               INIT_TEXT
-               _einittext = .;
-       }
-       .init.data : {
-               INIT_DATA
-       }
-       . = ALIGN(16);
-       .init.setup : {
-               __setup_start = .;
-               *(.init.setup)
-               __setup_end = .;
-       }
-       .initcall.init : {
-               __initcall_start = .;
-               INITCALLS
-               __initcall_end = .;
-       }
-       .con_initcall.init : {
-               __con_initcall_start = .;
-               *(.con_initcall.init)
-               __con_initcall_end = .;
-       }
-       SECURITY_INIT
-
-       . = ALIGN(4);
-       .tsb_ldquad_phys_patch : {
-               __tsb_ldquad_phys_patch = .;
-               *(.tsb_ldquad_phys_patch)
-               __tsb_ldquad_phys_patch_end = .;
-       }
-
-       .tsb_phys_patch : {
-               __tsb_phys_patch = .;
-               *(.tsb_phys_patch)
-               __tsb_phys_patch_end = .;
-       }
-
-       .cpuid_patch : {
-               __cpuid_patch = .;
-               *(.cpuid_patch)
-               __cpuid_patch_end = .;
-       }
-
-       .sun4v_1insn_patch : {
-               __sun4v_1insn_patch = .;
-               *(.sun4v_1insn_patch)
-               __sun4v_1insn_patch_end = .;
-       }
-       .sun4v_2insn_patch : {
-               __sun4v_2insn_patch = .;
-               *(.sun4v_2insn_patch)
-               __sun4v_2insn_patch_end = .;
-       }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       . = ALIGN(PAGE_SIZE);
-       .init.ramfs : {
-               __initramfs_start = .;
-               *(.init.ramfs)
-               __initramfs_end = .;
-       }
-#endif
-
-       PERCPU(PAGE_SIZE)
-
-       . = ALIGN(PAGE_SIZE);
-       __init_end = .;
-       __bss_start = .;
-       .sbss : {
-               *(.sbss)
-               *(.scommon)
-       }
-       .bss : {
-               *(.dynbss)
-               *(.bss)
-               *(COMMON)
-       }
-       _end = . ;
-       PROVIDE (end = .);
-
-       /DISCARD/ : {
-               EXIT_TEXT
-               EXIT_DATA
-               *(.exitcall.exit)
-       }
-
-       STABS_DEBUG
-       DWARF_DEBUG
-}
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
deleted file mode 100644 (file)
index f095e13..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Makefile for Sparc64 library files..
-#
-
-EXTRA_AFLAGS := -ansi
-EXTRA_CFLAGS := -Werror
-
-lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
-        memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-        bzero.o csum_copy.o csum_copy_from_user.o csum_copy_to_user.o \
-        VISsave.o atomic.o bitops.o \
-        U1memcpy.o U1copy_from_user.o U1copy_to_user.o \
-        U3memcpy.o U3copy_from_user.o U3copy_to_user.o U3patch.o \
-        NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
-        NGpage.o NGbzero.o \
-        NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o NG2patch.o \
-        NG2page.o \
-        GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o GENpatch.o \
-        GENpage.o GENbzero.o \
-        copy_in_user.o user_fixup.o memmove.o \
-        mcount.o ipcsum.o rwsem.o xor.o
-
-obj-y += iomap.o
diff --git a/arch/sparc64/lib/iomap.c b/arch/sparc64/lib/iomap.c
deleted file mode 100644 (file)
index 7120ebb..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Implement the sparc64 iomap interfaces
- */
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <asm/io.h>
-
-/* Create a virtual mapping cookie for an IO port range */
-void __iomem *ioport_map(unsigned long port, unsigned int nr)
-{
-       return (void __iomem *) (unsigned long) port;
-}
-
-void ioport_unmap(void __iomem *addr)
-{
-       /* Nothing to do */
-}
-EXPORT_SYMBOL(ioport_map);
-EXPORT_SYMBOL(ioport_unmap);
-
-/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-{
-       resource_size_t start = pci_resource_start(dev, bar);
-       resource_size_t len = pci_resource_len(dev, bar);
-       unsigned long flags = pci_resource_flags(dev, bar);
-
-       if (!len || !start)
-               return NULL;
-       if (maxlen && len > maxlen)
-               len = maxlen;
-       if (flags & IORESOURCE_IO)
-               return ioport_map(start, len);
-       if (flags & IORESOURCE_MEM) {
-               if (flags & IORESOURCE_CACHEABLE)
-                       return ioremap(start, len);
-               return ioremap_nocache(start, len);
-       }
-       /* What? */
-       return NULL;
-}
-
-void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
-{
-       /* nothing to do */
-}
-EXPORT_SYMBOL(pci_iomap);
-EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/sparc64/lib/memcmp.S b/arch/sparc64/lib/memcmp.S
deleted file mode 100644 (file)
index d3fdaa8..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Sparc64 optimized memcmp code.
- *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 2000 David S. Miller (davem@redhat.com)
- */
-
-       .text
-       .align  32
-       .globl  __memcmp, memcmp
-__memcmp:
-memcmp:
-       cmp     %o2, 0          ! IEU1  Group
-loop:  be,pn   %icc, ret_0     ! CTI
-        nop                    ! IEU0
-       ldub    [%o0], %g7      ! LSU   Group
-       ldub    [%o1], %g3      ! LSU   Group
-       sub     %o2, 1, %o2     ! IEU0
-       add     %o0, 1, %o0     ! IEU1
-       add     %o1, 1, %o1     ! IEU0  Group
-       subcc   %g7, %g3, %g3   ! IEU1  Group
-       be,pt   %icc, loop      ! CTI
-        cmp    %o2, 0          ! IEU1  Group
-
-ret_n0:        retl
-        mov    %g3, %o0
-ret_0: retl
-        mov    0, %o0
diff --git a/arch/sparc64/lib/strlen.S b/arch/sparc64/lib/strlen.S
deleted file mode 100644 (file)
index e9ba192..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* strlen.S: Sparc64 optimized strlen code
- * Hand optimized from GNU libc's strlen
- * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#define LO_MAGIC 0x01010101
-#define HI_MAGIC 0x80808080
-
-       .align  32
-       .globl  strlen
-       .type   strlen,#function
-strlen:
-       mov     %o0, %o1
-       andcc   %o0, 3, %g0
-       be,pt   %icc, 9f
-        sethi  %hi(HI_MAGIC), %o4
-       ldub    [%o0], %o5
-       brz,pn  %o5, 11f
-        add    %o0, 1, %o0
-       andcc   %o0, 3, %g0
-       be,pn   %icc, 4f
-        or     %o4, %lo(HI_MAGIC), %o3
-       ldub    [%o0], %o5
-       brz,pn  %o5, 12f
-        add    %o0, 1, %o0
-       andcc   %o0, 3, %g0
-       be,pt   %icc, 5f
-        sethi  %hi(LO_MAGIC), %o4
-       ldub    [%o0], %o5
-       brz,pn  %o5, 13f
-        add    %o0, 1, %o0
-       ba,pt   %icc, 8f
-        or     %o4, %lo(LO_MAGIC), %o2
-9:
-       or      %o4, %lo(HI_MAGIC), %o3
-4:
-       sethi   %hi(LO_MAGIC), %o4
-5:
-       or      %o4, %lo(LO_MAGIC), %o2
-8:
-       ld      [%o0], %o5
-2:
-       sub     %o5, %o2, %o4
-       andcc   %o4, %o3, %g0
-       be,pt   %icc, 8b
-        add    %o0, 4, %o0
-
-       /* Check every byte. */
-       srl     %o5, 24, %g7
-       andcc   %g7, 0xff, %g0
-       be,pn   %icc, 1f
-        add    %o0, -4, %o4
-       srl     %o5, 16, %g7
-       andcc   %g7, 0xff, %g0
-       be,pn   %icc, 1f
-        add    %o4, 1, %o4
-       srl     %o5, 8, %g7
-       andcc   %g7, 0xff, %g0
-       be,pn   %icc, 1f
-        add    %o4, 1, %o4
-       andcc   %o5, 0xff, %g0
-       bne,a,pt %icc, 2b
-        ld     [%o0], %o5
-       add     %o4, 1, %o4
-1:
-       retl
-        sub    %o4, %o1, %o0
-11:
-       retl
-        mov    0, %o0
-12:
-       retl
-        mov    1, %o0
-13:
-       retl
-        mov    2, %o0
-
-       .size   strlen, .-strlen
diff --git a/arch/sparc64/math-emu/Makefile b/arch/sparc64/math-emu/Makefile
deleted file mode 100644 (file)
index cc5cb9b..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the FPU instruction emulation.
-#
-
-obj-y    := math.o
-
-EXTRA_CFLAGS = -Iinclude/math-emu -w
diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile
deleted file mode 100644 (file)
index 68d04c0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Makefile for the linux Sparc64-specific parts of the memory manager.
-#
-
-EXTRA_AFLAGS := -ansi
-EXTRA_CFLAGS := -Werror
-
-obj-y    := ultra.o tlb.o tsb.o fault.o init.o generic.o
-
-obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/sparc64/oprofile/Makefile b/arch/sparc64/oprofile/Makefile
deleted file mode 100644 (file)
index e9feca1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-obj-$(CONFIG_OPROFILE) += oprofile.o
-
-DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
-               oprof.o cpu_buffer.o buffer_sync.o \
-               event_buffer.o oprofile_files.o \
-               oprofilefs.o oprofile_stats.o \
-               timer_int.o )
-
-oprofile-y                             := $(DRIVER_OBJS) init.o
diff --git a/arch/sparc64/oprofile/init.c b/arch/sparc64/oprofile/init.c
deleted file mode 100644 (file)
index 17bb603..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @file init.c
- *
- * @remark Copyright 2002 OProfile authors
- * @remark Read the file COPYING
- *
- * @author John Levon <levon@movementarian.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/oprofile.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-int __init oprofile_arch_init(struct oprofile_operations *ops)
-{
-       return -ENODEV;
-}
-
-
-void oprofile_arch_exit(void)
-{
-}
diff --git a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile
deleted file mode 100644 (file)
index 8c94483..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Makefile for the Sun Boot PROM interface library under
-# Linux.
-#
-
-EXTRA_AFLAGS := -ansi
-EXTRA_CFLAGS := -Werror
-
-lib-y   := bootstr.o devops.o init.o misc.o \
-          tree.o console.o printf.o p1275.o cif.o
diff --git a/arch/sparc64/prom/printf.c b/arch/sparc64/prom/printf.c
deleted file mode 100644 (file)
index 660943e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * printf.c:  Internal prom library printf facility.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (c) 2002 Pete Zaitcev (zaitcev@yahoo.com)
- *
- * We used to warn all over the code: DO NOT USE prom_printf(),
- * and yet people do. Anton's banking code was outputting banks
- * with prom_printf for most of the 2.4 lifetime. Since an effective
- * stick is not available, we deployed a carrot: an early printk
- * through PROM by means of -p boot option. This ought to fix it.
- * USE printk; if you need, deploy -p.
- */
-
-#include <linux/kernel.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-
-static char ppbuf[1024];
-
-void
-prom_write(const char *buf, unsigned int n)
-{
-       char ch;
-
-       while (n != 0) {
-               --n;
-               if ((ch = *buf++) == '\n')
-                       prom_putchar('\r');
-               prom_putchar(ch);
-       }
-}
-
-void
-prom_printf(const char *fmt, ...)
-{
-       va_list args;
-       int i;
-
-       va_start(args, fmt);
-       i = vscnprintf(ppbuf, sizeof(ppbuf), fmt, args);
-       va_end(args);
-
-       prom_write(ppbuf, i);
-}
index 753346e2cdfd64d5d472f3388014952f5d0ca4ff..ae5f94d6317d584c051fbcea83533431e4b635d7 100644 (file)
@@ -11,21 +11,21 @@ extern int get_signals(void);
 extern void block_signals(void);
 extern void unblock_signals(void);
 
-#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
+#define raw_local_save_flags(flags) do { typecheck(unsigned long, flags); \
                                     (flags) = get_signals(); } while(0)
-#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \
+#define raw_local_irq_restore(flags) do { typecheck(unsigned long, flags); \
                                      set_signals(flags); } while(0)
 
-#define local_irq_save(flags) do { local_save_flags(flags); \
-                                   local_irq_disable(); } while(0)
+#define raw_local_irq_save(flags) do { raw_local_save_flags(flags); \
+                                   raw_local_irq_disable(); } while(0)
 
-#define local_irq_enable() unblock_signals()
-#define local_irq_disable() block_signals()
+#define raw_local_irq_enable() unblock_signals()
+#define raw_local_irq_disable() block_signals()
 
 #define irqs_disabled()                 \
 ({                                      \
         unsigned long flags;            \
-        local_save_flags(flags);        \
+        raw_local_save_flags(flags);        \
         (flags == 0);                   \
 })
 
index 98a0ed52b5c39ec9d728d89c557353f97f986a32..0f44add3e0b7850e676cf8cc45d8514ebc94a5ea 100644 (file)
@@ -247,6 +247,28 @@ config X86_HAS_BOOT_CPU_ID
        def_bool y
        depends on X86_VOYAGER
 
+config SPARSE_IRQ
+       bool "Support sparse irq numbering"
+       depends on PCI_MSI || HT_IRQ
+       help
+         This enables support for sparse irqs. This is useful for distro
+         kernels that want to define a high CONFIG_NR_CPUS value but still
+         want to have low kernel memory footprint on smaller machines.
+
+         ( Sparse IRQs can also be beneficial on NUMA boxes, as they spread
+           out the irq_desc[] array in a more NUMA-friendly way. )
+
+         If you don't know what to do here, say N.
+
+config NUMA_MIGRATE_IRQ_DESC
+       bool "Move irq desc when changing irq smp_affinity"
+       depends on SPARSE_IRQ && NUMA
+       default n
+       help
+         This enables moving irq_desc to cpu/node that irq will use handled.
+
+         If you don't know what to do here, say N.
+
 config X86_FIND_SMP_CONFIG
        def_bool y
        depends on X86_MPPARSE || X86_VOYAGER
@@ -479,7 +501,7 @@ config HPET_TIMER
          The HPET provides a stable time base on SMP
          systems, unlike the TSC, but it is more expensive to access,
          as it is off-chip.  You can find the HPET spec at
-         <http://www.intel.com/hardwaredesign/hpetspec.htm>.
+         <http://www.intel.com/hardwaredesign/hpetspec_1.pdf>.
 
          You can safely choose Y here.  However, HPET will only be
          activated if the platform and the BIOS support this feature.
index dc22c0733282b9ce631250d69cbcc00e0cd46617..4035357f5b9d6b830a16b09f39d30e90810aae9e 100644 (file)
@@ -65,7 +65,7 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
                return dma_ops;
        else
                return dev->archdata.dma_ops;
-#endif /* _ASM_X86_DMA_MAPPING_H */
+#endif
 }
 
 /* Make sure we keep the same behaviour */
index e475e009ae5d4e60dc0e828ad96373ef91f2799a..7a1f44ac1f17e127e054852d2ccc8baefb27b528 100644 (file)
@@ -198,17 +198,14 @@ extern void restore_IO_APIC_setup(void);
 extern void reinit_intr_remapped_IO_APIC(int);
 #endif
 
-extern int probe_nr_irqs(void);
+extern void probe_nr_irqs_gsi(void);
 
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 static const int timer_through_8259 = 0;
-static inline void ioapic_init_mappings(void) { }
+static inline void ioapic_init_mappings(void)  { }
 
-static inline int probe_nr_irqs(void)
-{
-       return NR_IRQS;
-}
+static inline void probe_nr_irqs_gsi(void)     { }
 #endif
 
 #endif /* _ASM_X86_IO_APIC_H */
index 295b13193f4df09b05aad53ec09c81c601a17a9f..a6ee9e6f530f89cc2e86a5607ceff6597c9d1757 100644 (file)
@@ -7,8 +7,6 @@ extern struct dma_mapping_ops nommu_dma_ops;
 extern int force_iommu, no_iommu;
 extern int iommu_detected;
 
-extern unsigned long iommu_nr_pages(unsigned long addr, unsigned long len);
-
 /* 10 seconds */
 #define DMAR_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000)
 
index 0005adb0f941f5f564cbad634538db8b149f0f46..f7ff65032b9d66aee077fcc3ddbcddd40bd4f75d 100644 (file)
 #define LAST_VM86_IRQ          15
 #define invalid_vm86_irq(irq)  ((irq) < 3 || (irq) > 15)
 
+#define NR_IRQS_LEGACY         16
+
 #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
+
+#ifndef CONFIG_SPARSE_IRQ
 # if NR_CPUS < MAX_IO_APICS
 #  define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
 # else
 #  define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))
 # endif
+#else
+# if (8 * NR_CPUS) > (32 * MAX_IO_APICS)
+#  define NR_IRQS (NR_VECTORS + (8 * NR_CPUS))
+# else
+#  define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))
+# endif
+#endif
 
 #elif defined(CONFIG_X86_VOYAGER)
 
index 647781298e7ef7cbc98b14ad75f2552b0092507f..66834c41c0493eccf1b117b1565443c10ec706b6 100644 (file)
@@ -84,6 +84,8 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
 static inline void early_quirks(void) { }
 #endif
 
+extern void pci_iommu_alloc(void);
+
 #endif  /* __KERNEL__ */
 
 #ifdef CONFIG_X86_32
index d02d936840a3ed8e3b7f94fade13929c9a3d6413..4da207982777e75a970fca5fee80cb2883381e4e 100644 (file)
@@ -23,7 +23,6 @@ extern int (*pci_config_write)(int seg, int bus, int dev, int fn,
                               int reg, int len, u32 value);
 
 extern void dma32_reserve_bootmem(void);
-extern void pci_iommu_alloc(void);
 
 /* The PCI address space does equal the physical memory
  * address space.  The networking and block device layers use
index 580c3ee6c58c4d0479dbce9ea491c78049255e04..4340055b755918fb8fd777df62f811ba5e26820c 100644 (file)
@@ -157,6 +157,7 @@ extern int __get_user_bad(void);
        int __ret_gu;                                                   \
        unsigned long __val_gu;                                         \
        __chk_user_ptr(ptr);                                            \
+       might_fault();                                                  \
        switch (sizeof(*(ptr))) {                                       \
        case 1:                                                         \
                __get_user_x(1, __ret_gu, __val_gu, ptr);               \
@@ -241,6 +242,7 @@ extern void __put_user_8(void);
        int __ret_pu;                                           \
        __typeof__(*(ptr)) __pu_val;                            \
        __chk_user_ptr(ptr);                                    \
+       might_fault();                                          \
        __pu_val = x;                                           \
        switch (sizeof(*(ptr))) {                               \
        case 1:                                                 \
index d095a3aeea1b44d3063f0165c956d0a156c6ca38..5e06259e90e5a736539948ae22e1de25444ba485 100644 (file)
@@ -82,8 +82,8 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 static __always_inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       might_sleep();
-       return __copy_to_user_inatomic(to, from, n);
+       might_fault();
+       return __copy_to_user_inatomic(to, from, n);
 }
 
 static __always_inline unsigned long
@@ -137,7 +137,7 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 static __always_inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (__builtin_constant_p(n)) {
                unsigned long ret;
 
@@ -159,7 +159,7 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
 static __always_inline unsigned long __copy_from_user_nocache(void *to,
                                const void __user *from, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (__builtin_constant_p(n)) {
                unsigned long ret;
 
index f8cfd00db450f2e0f948ce7128a2d44867aebf59..84210c479fca83524c6cef4c6bc069bcff76e272 100644 (file)
@@ -29,6 +29,8 @@ static __always_inline __must_check
 int __copy_from_user(void *dst, const void __user *src, unsigned size)
 {
        int ret = 0;
+
+       might_fault();
        if (!__builtin_constant_p(size))
                return copy_user_generic(dst, (__force void *)src, size);
        switch (size) {
@@ -71,6 +73,8 @@ static __always_inline __must_check
 int __copy_to_user(void __user *dst, const void *src, unsigned size)
 {
        int ret = 0;
+
+       might_fault();
        if (!__builtin_constant_p(size))
                return copy_user_generic((__force void *)dst, src, size);
        switch (size) {
@@ -113,6 +117,8 @@ static __always_inline __must_check
 int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 {
        int ret = 0;
+
+       might_fault();
        if (!__builtin_constant_p(size))
                return copy_user_generic((__force void *)dst,
                                         (__force void *)src, size);
index 88dd768eab6d34980d14aff41178115ed881045e..d364df03c1d6419ce4473e23b420d86167343775 100644 (file)
@@ -109,6 +109,8 @@ obj-$(CONFIG_MICROCODE)                     += microcode.o
 
 obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
 
+obj-$(CONFIG_SWIOTLB)                  += pci-swiotlb_64.o # NB rename without _64
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
@@ -122,7 +124,6 @@ ifeq ($(CONFIG_X86_64),y)
         obj-$(CONFIG_GART_IOMMU)       += pci-gart_64.o aperture_64.o
         obj-$(CONFIG_CALGARY_IOMMU)    += pci-calgary_64.o tce_64.o
         obj-$(CONFIG_AMD_IOMMU)                += amd_iommu_init.o amd_iommu.o
-        obj-$(CONFIG_SWIOTLB)          += pci-swiotlb_64.o
 
         obj-$(CONFIG_PCI_MMCONFIG)     += mmconf-fam10h_64.o
 endif
index 3f0a3edf0a573a2f5f2d1051b32285ebffcdbb36..845ea097383ee4051a24b54bca8da4c29bd9f6d1 100644 (file)
@@ -813,7 +813,7 @@ int __init hpet_enable(void)
 
 out_nohpet:
        hpet_clear_mapping();
-       boot_hpet_disable = 1;
+       hpet_address = 0;
        return 0;
 }
 
@@ -836,10 +836,11 @@ static __init int hpet_late_init(void)
 
                hpet_address = force_hpet_address;
                hpet_enable();
-               if (!hpet_virt_address)
-                       return -ENODEV;
        }
 
+       if (!hpet_virt_address)
+               return -ENODEV;
+
        hpet_reserve_platform_timers(hpet_readl(HPET_ID));
 
        for_each_online_cpu(cpu) {
index 679e7bbbbcd6b07230a2e7fdbd2ebe38e04f0563..f6ea94b74da146072cca138aa824ed5a3d5eeec7 100644 (file)
@@ -108,93 +108,252 @@ static int __init parse_noapic(char *str)
 early_param("noapic", parse_noapic);
 
 struct irq_pin_list;
+
+/*
+ * This is performance-critical, we want to do it O(1)
+ *
+ * the indexing order of this array favors 1:1 mappings
+ * between pins and IRQs.
+ */
+
+struct irq_pin_list {
+       int apic, pin;
+       struct irq_pin_list *next;
+};
+
+static struct irq_pin_list *get_one_free_irq_2_pin(int cpu)
+{
+       struct irq_pin_list *pin;
+       int node;
+
+       node = cpu_to_node(cpu);
+
+       pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
+       printk(KERN_DEBUG "  alloc irq_2_pin on cpu %d node %d\n", cpu, node);
+
+       return pin;
+}
+
 struct irq_cfg {
-       unsigned int irq;
        struct irq_pin_list *irq_2_pin;
        cpumask_t domain;
        cpumask_t old_domain;
        unsigned move_cleanup_count;
        u8 vector;
        u8 move_in_progress : 1;
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+       u8 move_desc_pending : 1;
+#endif
 };
 
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
+#ifdef CONFIG_SPARSE_IRQ
+static struct irq_cfg irq_cfgx[] = {
+#else
 static struct irq_cfg irq_cfgx[NR_IRQS] = {
-       [0]  = { .irq =  0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR,  },
-       [1]  = { .irq =  1, .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR,  },
-       [2]  = { .irq =  2, .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR,  },
-       [3]  = { .irq =  3, .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR,  },
-       [4]  = { .irq =  4, .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR,  },
-       [5]  = { .irq =  5, .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR,  },
-       [6]  = { .irq =  6, .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR,  },
-       [7]  = { .irq =  7, .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR,  },
-       [8]  = { .irq =  8, .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR,  },
-       [9]  = { .irq =  9, .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR,  },
-       [10] = { .irq = 10, .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
-       [11] = { .irq = 11, .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
-       [12] = { .irq = 12, .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
-       [13] = { .irq = 13, .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
-       [14] = { .irq = 14, .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
-       [15] = { .irq = 15, .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
+#endif
+       [0]  = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR,  },
+       [1]  = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR,  },
+       [2]  = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR,  },
+       [3]  = { .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR,  },
+       [4]  = { .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR,  },
+       [5]  = { .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR,  },
+       [6]  = { .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR,  },
+       [7]  = { .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR,  },
+       [8]  = { .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR,  },
+       [9]  = { .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR,  },
+       [10] = { .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
+       [11] = { .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
+       [12] = { .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
+       [13] = { .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
+       [14] = { .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
+       [15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
 };
 
-#define for_each_irq_cfg(irq, cfg)             \
-       for (irq = 0, cfg = irq_cfgx; irq < nr_irqs; irq++, cfg++)
+void __init arch_early_irq_init(void)
+{
+       struct irq_cfg *cfg;
+       struct irq_desc *desc;
+       int count;
+       int i;
+
+       cfg = irq_cfgx;
+       count = ARRAY_SIZE(irq_cfgx);
+
+       for (i = 0; i < count; i++) {
+               desc = irq_to_desc(i);
+               desc->chip_data = &cfg[i];
+       }
+}
 
+#ifdef CONFIG_SPARSE_IRQ
 static struct irq_cfg *irq_cfg(unsigned int irq)
 {
-       return irq < nr_irqs ? irq_cfgx + irq : NULL;
+       struct irq_cfg *cfg = NULL;
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+       if (desc)
+               cfg = desc->chip_data;
+
+       return cfg;
 }
 
-static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
+static struct irq_cfg *get_one_free_irq_cfg(int cpu)
 {
-       return irq_cfg(irq);
+       struct irq_cfg *cfg;
+       int node;
+
+       node = cpu_to_node(cpu);
+
+       cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
+       printk(KERN_DEBUG "  alloc irq_cfg on cpu %d node %d\n", cpu, node);
+
+       return cfg;
 }
 
-/*
- * Rough estimation of how many shared IRQs there are, can be changed
- * anytime.
- */
-#define MAX_PLUS_SHARED_IRQS NR_IRQS
-#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
+void arch_init_chip_data(struct irq_desc *desc, int cpu)
+{
+       struct irq_cfg *cfg;
 
-/*
- * This is performance-critical, we want to do it O(1)
- *
- * the indexing order of this array favors 1:1 mappings
- * between pins and IRQs.
- */
+       cfg = desc->chip_data;
+       if (!cfg) {
+               desc->chip_data = get_one_free_irq_cfg(cpu);
+               if (!desc->chip_data) {
+                       printk(KERN_ERR "can not alloc irq_cfg\n");
+                       BUG_ON(1);
+               }
+       }
+}
 
-struct irq_pin_list {
-       int apic, pin;
-       struct irq_pin_list *next;
-};
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+
+static void
+init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
+{
+       struct irq_pin_list *old_entry, *head, *tail, *entry;
+
+       cfg->irq_2_pin = NULL;
+       old_entry = old_cfg->irq_2_pin;
+       if (!old_entry)
+               return;
 
-static struct irq_pin_list irq_2_pin_head[PIN_MAP_SIZE];
-static struct irq_pin_list *irq_2_pin_ptr;
+       entry = get_one_free_irq_2_pin(cpu);
+       if (!entry)
+               return;
 
-static void __init irq_2_pin_init(void)
+       entry->apic     = old_entry->apic;
+       entry->pin      = old_entry->pin;
+       head            = entry;
+       tail            = entry;
+       old_entry       = old_entry->next;
+       while (old_entry) {
+               entry = get_one_free_irq_2_pin(cpu);
+               if (!entry) {
+                       entry = head;
+                       while (entry) {
+                               head = entry->next;
+                               kfree(entry);
+                               entry = head;
+                       }
+                       /* still use the old one */
+                       return;
+               }
+               entry->apic     = old_entry->apic;
+               entry->pin      = old_entry->pin;
+               tail->next      = entry;
+               tail            = entry;
+               old_entry       = old_entry->next;
+       }
+
+       tail->next = NULL;
+       cfg->irq_2_pin = head;
+}
+
+static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
 {
-       struct irq_pin_list *pin = irq_2_pin_head;
-       int i;
+       struct irq_pin_list *entry, *next;
 
-       for (i = 1; i < PIN_MAP_SIZE; i++)
-               pin[i-1].next = &pin[i];
+       if (old_cfg->irq_2_pin == cfg->irq_2_pin)
+               return;
+
+       entry = old_cfg->irq_2_pin;
 
-       irq_2_pin_ptr = &pin[0];
+       while (entry) {
+               next = entry->next;
+               kfree(entry);
+               entry = next;
+       }
+       old_cfg->irq_2_pin = NULL;
 }
 
-static struct irq_pin_list *get_one_free_irq_2_pin(void)
+void arch_init_copy_chip_data(struct irq_desc *old_desc,
+                                struct irq_desc *desc, int cpu)
 {
-       struct irq_pin_list *pin = irq_2_pin_ptr;
+       struct irq_cfg *cfg;
+       struct irq_cfg *old_cfg;
 
-       if (!pin)
-               panic("can not get more irq_2_pin\n");
+       cfg = get_one_free_irq_cfg(cpu);
 
-       irq_2_pin_ptr = pin->next;
-       pin->next = NULL;
-       return pin;
+       if (!cfg)
+               return;
+
+       desc->chip_data = cfg;
+
+       old_cfg = old_desc->chip_data;
+
+       memcpy(cfg, old_cfg, sizeof(struct irq_cfg));
+
+       init_copy_irq_2_pin(old_cfg, cfg, cpu);
+}
+
+static void free_irq_cfg(struct irq_cfg *old_cfg)
+{
+       kfree(old_cfg);
+}
+
+void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
+{
+       struct irq_cfg *old_cfg, *cfg;
+
+       old_cfg = old_desc->chip_data;
+       cfg = desc->chip_data;
+
+       if (old_cfg == cfg)
+               return;
+
+       if (old_cfg) {
+               free_irq_2_pin(old_cfg, cfg);
+               free_irq_cfg(old_cfg);
+               old_desc->chip_data = NULL;
+       }
+}
+
+static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
+{
+       struct irq_cfg *cfg = desc->chip_data;
+
+       if (!cfg->move_in_progress) {
+               /* it means that domain is not changed */
+               if (!cpus_intersects(desc->affinity, mask))
+                       cfg->move_desc_pending = 1;
+       }
 }
+#endif
+
+#else
+static struct irq_cfg *irq_cfg(unsigned int irq)
+{
+       return irq < nr_irqs ? irq_cfgx + irq : NULL;
+}
+
+#endif
+
+#ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC
+static inline void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
+{
+}
+#endif
 
 struct io_apic {
        unsigned int index;
@@ -237,11 +396,10 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
        writel(value, &io_apic->data);
 }
 
-static bool io_apic_level_ack_pending(unsigned int irq)
+static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
 {
        struct irq_pin_list *entry;
        unsigned long flags;
-       struct irq_cfg *cfg = irq_cfg(irq);
 
        spin_lock_irqsave(&ioapic_lock, flags);
        entry = cfg->irq_2_pin;
@@ -323,13 +481,12 @@ static void ioapic_mask_entry(int apic, int pin)
 }
 
 #ifdef CONFIG_SMP
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
 {
        int apic, pin;
-       struct irq_cfg *cfg;
        struct irq_pin_list *entry;
+       u8 vector = cfg->vector;
 
-       cfg = irq_cfg(irq);
        entry = cfg->irq_2_pin;
        for (;;) {
                unsigned int reg;
@@ -359,24 +516,27 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
        }
 }
 
-static int assign_irq_vector(int irq, cpumask_t mask);
+static int assign_irq_vector(int irq, struct irq_cfg *cfg, cpumask_t mask);
 
-static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+static void set_ioapic_affinity_irq_desc(struct irq_desc *desc, cpumask_t mask)
 {
        struct irq_cfg *cfg;
        unsigned long flags;
        unsigned int dest;
        cpumask_t tmp;
-       struct irq_desc *desc;
+       unsigned int irq;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
                return;
 
-       cfg = irq_cfg(irq);
-       if (assign_irq_vector(irq, mask))
+       irq = desc->irq;
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
        /*
@@ -384,12 +544,20 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
         */
        dest = SET_APIC_LOGICAL_ID(dest);
 
-       desc = irq_to_desc(irq);
        spin_lock_irqsave(&ioapic_lock, flags);
-       __target_IO_APIC_irq(irq, dest, cfg->vector);
+       __target_IO_APIC_irq(irq, dest, cfg);
        desc->affinity = mask;
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
+
+static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+
+       set_ioapic_affinity_irq_desc(desc, mask);
+}
 #endif /* CONFIG_SMP */
 
 /*
@@ -397,16 +565,18 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq(unsigned int irq, int apic, int pin)
+static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
 {
-       struct irq_cfg *cfg;
        struct irq_pin_list *entry;
 
-       /* first time to refer irq_cfg, so with new */
-       cfg = irq_cfg_alloc(irq);
        entry = cfg->irq_2_pin;
        if (!entry) {
-               entry = get_one_free_irq_2_pin();
+               entry = get_one_free_irq_2_pin(cpu);
+               if (!entry) {
+                       printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n",
+                                       apic, pin);
+                       return;
+               }
                cfg->irq_2_pin = entry;
                entry->apic = apic;
                entry->pin = pin;
@@ -421,7 +591,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
                entry = entry->next;
        }
 
-       entry->next = get_one_free_irq_2_pin();
+       entry->next = get_one_free_irq_2_pin(cpu);
        entry = entry->next;
        entry->apic = apic;
        entry->pin = pin;
@@ -430,11 +600,10 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 /*
  * Reroute an IRQ to a different pin.
  */
-static void __init replace_pin_at_irq(unsigned int irq,
+static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu,
                                      int oldapic, int oldpin,
                                      int newapic, int newpin)
 {
-       struct irq_cfg *cfg = irq_cfg(irq);
        struct irq_pin_list *entry = cfg->irq_2_pin;
        int replaced = 0;
 
@@ -451,18 +620,16 @@ static void __init replace_pin_at_irq(unsigned int irq,
 
        /* why? call replace before add? */
        if (!replaced)
-               add_pin_to_irq(irq, newapic, newpin);
+               add_pin_to_irq_cpu(cfg, cpu, newapic, newpin);
 }
 
-static inline void io_apic_modify_irq(unsigned int irq,
+static inline void io_apic_modify_irq(struct irq_cfg *cfg,
                                int mask_and, int mask_or,
                                void (*final)(struct irq_pin_list *entry))
 {
        int pin;
-       struct irq_cfg *cfg;
        struct irq_pin_list *entry;
 
-       cfg = irq_cfg(irq);
        for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) {
                unsigned int reg;
                pin = entry->pin;
@@ -475,9 +642,9 @@ static inline void io_apic_modify_irq(unsigned int irq,
        }
 }
 
-static void __unmask_IO_APIC_irq(unsigned int irq)
+static void __unmask_IO_APIC_irq(struct irq_cfg *cfg)
 {
-       io_apic_modify_irq(irq, ~IO_APIC_REDIR_MASKED, 0, NULL);
+       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
 }
 
 #ifdef CONFIG_X86_64
@@ -492,47 +659,64 @@ void io_apic_sync(struct irq_pin_list *entry)
        readl(&io_apic->data);
 }
 
-static void __mask_IO_APIC_irq(unsigned int irq)
+static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
 {
-       io_apic_modify_irq(irq, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
+       io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
 }
 #else /* CONFIG_X86_32 */
-static void __mask_IO_APIC_irq(unsigned int irq)
+static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
 {
-       io_apic_modify_irq(irq, ~0, IO_APIC_REDIR_MASKED, NULL);
+       io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, NULL);
 }
 
-static void __mask_and_edge_IO_APIC_irq(unsigned int irq)
+static void __mask_and_edge_IO_APIC_irq(struct irq_cfg *cfg)
 {
-       io_apic_modify_irq(irq, ~IO_APIC_REDIR_LEVEL_TRIGGER,
+       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_LEVEL_TRIGGER,
                        IO_APIC_REDIR_MASKED, NULL);
 }
 
-static void __unmask_and_level_IO_APIC_irq(unsigned int irq)
+static void __unmask_and_level_IO_APIC_irq(struct irq_cfg *cfg)
 {
-       io_apic_modify_irq(irq, ~IO_APIC_REDIR_MASKED,
+       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED,
                        IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
 }
 #endif /* CONFIG_X86_32 */
 
-static void mask_IO_APIC_irq (unsigned int irq)
+static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
 {
+       struct irq_cfg *cfg = desc->chip_data;
        unsigned long flags;
 
+       BUG_ON(!cfg);
+
        spin_lock_irqsave(&ioapic_lock, flags);
-       __mask_IO_APIC_irq(irq);
+       __mask_IO_APIC_irq(cfg);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void unmask_IO_APIC_irq (unsigned int irq)
+static void unmask_IO_APIC_irq_desc(struct irq_desc *desc)
 {
+       struct irq_cfg *cfg = desc->chip_data;
        unsigned long flags;
 
        spin_lock_irqsave(&ioapic_lock, flags);
-       __unmask_IO_APIC_irq(irq);
+       __unmask_IO_APIC_irq(cfg);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
+static void mask_IO_APIC_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       mask_IO_APIC_irq_desc(desc);
+}
+static void unmask_IO_APIC_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       unmask_IO_APIC_irq_desc(desc);
+}
+
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
        struct IO_APIC_route_entry entry;
@@ -809,7 +993,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
  */
 static int EISA_ELCR(unsigned int irq)
 {
-       if (irq < 16) {
+       if (irq < NR_IRQS_LEGACY) {
                unsigned int port = 0x4d0 + (irq >> 3);
                return (inb(port) >> (irq & 7)) & 1;
        }
@@ -1034,7 +1218,7 @@ void unlock_vector_lock(void)
        spin_unlock(&vector_lock);
 }
 
-static int __assign_irq_vector(int irq, cpumask_t mask)
+static int __assign_irq_vector(int irq, struct irq_cfg *cfg, cpumask_t mask)
 {
        /*
         * NOTE! The local APIC isn't very good at handling
@@ -1050,16 +1234,13 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
        static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
        unsigned int old_vector;
        int cpu;
-       struct irq_cfg *cfg;
 
-       cfg = irq_cfg(irq);
+       if ((cfg->move_in_progress) || cfg->move_cleanup_count)
+               return -EBUSY;
 
        /* Only try and allocate irqs on cpus that are present */
        cpus_and(mask, mask, cpu_online_map);
 
-       if ((cfg->move_in_progress) || cfg->move_cleanup_count)
-               return -EBUSY;
-
        old_vector = cfg->vector;
        if (old_vector) {
                cpumask_t tmp;
@@ -1113,24 +1294,22 @@ next:
        return -ENOSPC;
 }
 
-static int assign_irq_vector(int irq, cpumask_t mask)
+static int assign_irq_vector(int irq, struct irq_cfg *cfg, cpumask_t mask)
 {
        int err;
        unsigned long flags;
 
        spin_lock_irqsave(&vector_lock, flags);
-       err = __assign_irq_vector(irq, mask);
+       err = __assign_irq_vector(irq, cfg, mask);
        spin_unlock_irqrestore(&vector_lock, flags);
        return err;
 }
 
-static void __clear_irq_vector(int irq)
+static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
 {
-       struct irq_cfg *cfg;
        cpumask_t mask;
        int cpu, vector;
 
-       cfg = irq_cfg(irq);
        BUG_ON(!cfg->vector);
 
        vector = cfg->vector;
@@ -1162,9 +1341,13 @@ void __setup_vector_irq(int cpu)
        /* This function must be called with vector_lock held */
        int irq, vector;
        struct irq_cfg *cfg;
+       struct irq_desc *desc;
 
        /* Mark the inuse vectors */
-       for_each_irq_cfg(irq, cfg) {
+       for_each_irq_desc(irq, desc) {
+               if (!desc)
+                       continue;
+               cfg = desc->chip_data;
                if (!cpu_isset(cpu, cfg->domain))
                        continue;
                vector = cfg->vector;
@@ -1215,11 +1398,8 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 #endif
 
-static void ioapic_register_intr(int irq, unsigned long trigger)
+static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long trigger)
 {
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
            trigger == IOAPIC_LEVEL)
@@ -1311,7 +1491,7 @@ static int setup_ioapic_entry(int apic, int irq,
        return 0;
 }
 
-static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
+static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, struct irq_desc *desc,
                              int trigger, int polarity)
 {
        struct irq_cfg *cfg;
@@ -1321,10 +1501,10 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
        if (!IO_APIC_IRQ(irq))
                return;
 
-       cfg = irq_cfg(irq);
+       cfg = desc->chip_data;
 
        mask = TARGET_CPUS;
-       if (assign_irq_vector(irq, mask))
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
        cpus_and(mask, cfg->domain, mask);
@@ -1341,12 +1521,12 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
                               cfg->vector)) {
                printk("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
                       mp_ioapics[apic].mp_apicid, pin);
-               __clear_irq_vector(irq);
+               __clear_irq_vector(irq, cfg);
                return;
        }
 
-       ioapic_register_intr(irq, trigger);
-       if (irq < 16)
+       ioapic_register_intr(irq, desc, trigger);
+       if (irq < NR_IRQS_LEGACY)
                disable_8259A_irq(irq);
 
        ioapic_write_entry(apic, pin, entry);
@@ -1356,6 +1536,9 @@ static void __init setup_IO_APIC_irqs(void)
 {
        int apic, pin, idx, irq;
        int notcon = 0;
+       struct irq_desc *desc;
+       struct irq_cfg *cfg;
+       int cpu = boot_cpu_id;
 
        apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
 
@@ -1387,9 +1570,15 @@ static void __init setup_IO_APIC_irqs(void)
                        if (multi_timer_check(apic, irq))
                                continue;
 #endif
-                       add_pin_to_irq(irq, apic, pin);
+                       desc = irq_to_desc_alloc_cpu(irq, cpu);
+                       if (!desc) {
+                               printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+                               continue;
+                       }
+                       cfg = desc->chip_data;
+                       add_pin_to_irq_cpu(cfg, cpu, apic, pin);
 
-                       setup_IO_APIC_irq(apic, pin, irq,
+                       setup_IO_APIC_irq(apic, pin, irq, desc,
                                        irq_trigger(idx), irq_polarity(idx));
                }
        }
@@ -1448,6 +1637,7 @@ __apicdebuginit(void) print_IO_APIC(void)
        union IO_APIC_reg_03 reg_03;
        unsigned long flags;
        struct irq_cfg *cfg;
+       struct irq_desc *desc;
        unsigned int irq;
 
        if (apic_verbosity == APIC_QUIET)
@@ -1537,8 +1727,13 @@ __apicdebuginit(void) print_IO_APIC(void)
        }
        }
        printk(KERN_DEBUG "IRQ to pin mappings:\n");
-       for_each_irq_cfg(irq, cfg) {
-               struct irq_pin_list *entry = cfg->irq_2_pin;
+       for_each_irq_desc(irq, desc) {
+               struct irq_pin_list *entry;
+
+               if (!desc)
+                       continue;
+               cfg = desc->chip_data;
+               entry = cfg->irq_2_pin;
                if (!entry)
                        continue;
                printk(KERN_DEBUG "IRQ%d ", irq);
@@ -2022,14 +2217,16 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
 {
        int was_pending = 0;
        unsigned long flags;
+       struct irq_cfg *cfg;
 
        spin_lock_irqsave(&ioapic_lock, flags);
-       if (irq < 16) {
+       if (irq < NR_IRQS_LEGACY) {
                disable_8259A_irq(irq);
                if (i8259A_irq_pending(irq))
                        was_pending = 1;
        }
-       __unmask_IO_APIC_irq(irq);
+       cfg = irq_cfg(irq);
+       __unmask_IO_APIC_irq(cfg);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return was_pending;
@@ -2092,35 +2289,37 @@ static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
  * as simple as edge triggered migration and we can do the irq migration
  * with a simple atomic update to IO-APIC RTE.
  */
-static void migrate_ioapic_irq(int irq, cpumask_t mask)
+static void migrate_ioapic_irq_desc(struct irq_desc *desc, cpumask_t mask)
 {
        struct irq_cfg *cfg;
-       struct irq_desc *desc;
        cpumask_t tmp, cleanup_mask;
        struct irte irte;
        int modify_ioapic_rte;
        unsigned int dest;
        unsigned long flags;
+       unsigned int irq;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
                return;
 
+       irq = desc->irq;
        if (get_irte(irq, &irte))
                return;
 
-       if (assign_irq_vector(irq, mask))
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
-       cfg = irq_cfg(irq);
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
-       desc = irq_to_desc(irq);
        modify_ioapic_rte = desc->status & IRQ_LEVEL;
        if (modify_ioapic_rte) {
                spin_lock_irqsave(&ioapic_lock, flags);
-               __target_IO_APIC_irq(irq, dest, cfg->vector);
+               __target_IO_APIC_irq(irq, dest, cfg);
                spin_unlock_irqrestore(&ioapic_lock, flags);
        }
 
@@ -2142,14 +2341,14 @@ static void migrate_ioapic_irq(int irq, cpumask_t mask)
        desc->affinity = mask;
 }
 
-static int migrate_irq_remapped_level(int irq)
+static int migrate_irq_remapped_level_desc(struct irq_desc *desc)
 {
        int ret = -1;
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_cfg *cfg = desc->chip_data;
 
-       mask_IO_APIC_irq(irq);
+       mask_IO_APIC_irq_desc(desc);
 
-       if (io_apic_level_ack_pending(irq)) {
+       if (io_apic_level_ack_pending(cfg)) {
                /*
                 * Interrupt in progress. Migrating irq now will change the
                 * vector information in the IO-APIC RTE and that will confuse
@@ -2161,14 +2360,15 @@ static int migrate_irq_remapped_level(int irq)
        }
 
        /* everthing is clear. we have right of way */
-       migrate_ioapic_irq(irq, desc->pending_mask);
+       migrate_ioapic_irq_desc(desc, desc->pending_mask);
 
        ret = 0;
        desc->status &= ~IRQ_MOVE_PENDING;
        cpus_clear(desc->pending_mask);
 
 unmask:
-       unmask_IO_APIC_irq(irq);
+       unmask_IO_APIC_irq_desc(desc);
+
        return ret;
 }
 
@@ -2178,6 +2378,9 @@ static void ir_irq_migration(struct work_struct *work)
        struct irq_desc *desc;
 
        for_each_irq_desc(irq, desc) {
+               if (!desc)
+                       continue;
+
                if (desc->status & IRQ_MOVE_PENDING) {
                        unsigned long flags;
 
@@ -2198,18 +2401,22 @@ static void ir_irq_migration(struct work_struct *work)
 /*
  * Migrates the IRQ destination in the process context.
  */
-static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, cpumask_t mask)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
        if (desc->status & IRQ_LEVEL) {
                desc->status |= IRQ_MOVE_PENDING;
                desc->pending_mask = mask;
-               migrate_irq_remapped_level(irq);
+               migrate_irq_remapped_level_desc(desc);
                return;
        }
 
-       migrate_ioapic_irq(irq, mask);
+       migrate_ioapic_irq_desc(desc, mask);
+}
+static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       set_ir_ioapic_affinity_irq_desc(desc, mask);
 }
 #endif
 
@@ -2228,6 +2435,9 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
                struct irq_cfg *cfg;
                irq = __get_cpu_var(vector_irq)[vector];
 
+               if (irq == -1)
+                       continue;
+
                desc = irq_to_desc(irq);
                if (!desc)
                        continue;
@@ -2249,19 +2459,40 @@ unlock:
        irq_exit();
 }
 
-static void irq_complete_move(unsigned int irq)
+static void irq_complete_move(struct irq_desc **descp)
 {
-       struct irq_cfg *cfg = irq_cfg(irq);
+       struct irq_desc *desc = *descp;
+       struct irq_cfg *cfg = desc->chip_data;
        unsigned vector, me;
 
-       if (likely(!cfg->move_in_progress))
+       if (likely(!cfg->move_in_progress)) {
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+               if (likely(!cfg->move_desc_pending))
+                       return;
+
+               /* domain has not changed, but affinity did */
+               me = smp_processor_id();
+               if (cpu_isset(me, desc->affinity)) {
+                       *descp = desc = move_irq_desc(desc, me);
+                       /* get the new one */
+                       cfg = desc->chip_data;
+                       cfg->move_desc_pending = 0;
+               }
+#endif
                return;
+       }
 
        vector = ~get_irq_regs()->orig_ax;
        me = smp_processor_id();
        if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
                cpumask_t cleanup_mask;
 
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+               *descp = desc = move_irq_desc(desc, me);
+               /* get the new one */
+               cfg = desc->chip_data;
+#endif
+
                cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
                cfg->move_cleanup_count = cpus_weight(cleanup_mask);
                send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
@@ -2269,8 +2500,9 @@ static void irq_complete_move(unsigned int irq)
        }
 }
 #else
-static inline void irq_complete_move(unsigned int irq) {}
+static inline void irq_complete_move(struct irq_desc **descp) {}
 #endif
+
 #ifdef CONFIG_INTR_REMAP
 static void ack_x2apic_level(unsigned int irq)
 {
@@ -2281,11 +2513,14 @@ static void ack_x2apic_edge(unsigned int irq)
 {
        ack_x2APIC_irq();
 }
+
 #endif
 
 static void ack_apic_edge(unsigned int irq)
 {
-       irq_complete_move(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       irq_complete_move(&desc);
        move_native_irq(irq);
        ack_APIC_irq();
 }
@@ -2294,18 +2529,21 @@ atomic_t irq_mis_count;
 
 static void ack_apic_level(unsigned int irq)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
+
 #ifdef CONFIG_X86_32
        unsigned long v;
        int i;
 #endif
+       struct irq_cfg *cfg;
        int do_unmask_irq = 0;
 
-       irq_complete_move(irq);
+       irq_complete_move(&desc);
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        /* If we are moving the irq we need to mask it */
-       if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) {
+       if (unlikely(desc->status & IRQ_MOVE_PENDING)) {
                do_unmask_irq = 1;
-               mask_IO_APIC_irq(irq);
+               mask_IO_APIC_irq_desc(desc);
        }
 #endif
 
@@ -2329,7 +2567,8 @@ static void ack_apic_level(unsigned int irq)
        * operation to prevent an edge-triggered interrupt escaping meanwhile.
        * The idea is from Manfred Spraul.  --macro
        */
-       i = irq_cfg(irq)->vector;
+       cfg = desc->chip_data;
+       i = cfg->vector;
 
        v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 #endif
@@ -2368,17 +2607,18 @@ static void ack_apic_level(unsigned int irq)
                 * accurate and is causing problems then it is a hardware bug
                 * and you can go talk to the chipset vendor about it.
                 */
-               if (!io_apic_level_ack_pending(irq))
+               cfg = desc->chip_data;
+               if (!io_apic_level_ack_pending(cfg))
                        move_masked_irq(irq);
-               unmask_IO_APIC_irq(irq);
+               unmask_IO_APIC_irq_desc(desc);
        }
 
 #ifdef CONFIG_X86_32
        if (!(v & (1 << (i & 0x1f)))) {
                atomic_inc(&irq_mis_count);
                spin_lock(&ioapic_lock);
-               __mask_and_edge_IO_APIC_irq(irq);
-               __unmask_and_level_IO_APIC_irq(irq);
+               __mask_and_edge_IO_APIC_irq(cfg);
+               __unmask_and_level_IO_APIC_irq(cfg);
                spin_unlock(&ioapic_lock);
        }
 #endif
@@ -2429,20 +2669,22 @@ static inline void init_IO_APIC_traps(void)
         * Also, we've got to be careful not to trash gate
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
-       for_each_irq_cfg(irq, cfg) {
-               if (IO_APIC_IRQ(irq) && !cfg->vector) {
+       for_each_irq_desc(irq, desc) {
+               if (!desc)
+                       continue;
+
+               cfg = desc->chip_data;
+               if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
                        /*
                         * Hmm.. We don't have an entry for this,
                         * so default to an old-fashioned 8259
                         * interrupt if we can..
                         */
-                       if (irq < 16)
+                       if (irq < NR_IRQS_LEGACY)
                                make_8259A_irq(irq);
-                       else {
-                               desc = irq_to_desc(irq);
+                       else
                                /* Strange. Oh, well.. */
                                desc->chip = &no_irq_chip;
-                       }
                }
        }
 }
@@ -2467,7 +2709,7 @@ static void unmask_lapic_irq(unsigned int irq)
        apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
 }
 
-static void ack_lapic_irq (unsigned int irq)
+static void ack_lapic_irq(unsigned int irq)
 {
        ack_APIC_irq();
 }
@@ -2479,11 +2721,8 @@ static struct irq_chip lapic_chip __read_mostly = {
        .ack            = ack_lapic_irq,
 };
 
-static void lapic_register_intr(int irq)
+static void lapic_register_intr(int irq, struct irq_desc *desc)
 {
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
        desc->status &= ~IRQ_LEVEL;
        set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
                                      "edge");
@@ -2587,7 +2826,9 @@ int timer_through_8259 __initdata;
  */
 static inline void __init check_timer(void)
 {
-       struct irq_cfg *cfg = irq_cfg(0);
+       struct irq_desc *desc = irq_to_desc(0);
+       struct irq_cfg *cfg = desc->chip_data;
+       int cpu = boot_cpu_id;
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
        unsigned int ver;
@@ -2602,7 +2843,7 @@ static inline void __init check_timer(void)
         * get/set the timer IRQ vector:
         */
        disable_8259A_irq(0);
-       assign_irq_vector(0, TARGET_CPUS);
+       assign_irq_vector(0, cfg, TARGET_CPUS);
 
        /*
         * As IRQ0 is to be enabled in the 8259A, the virtual
@@ -2653,10 +2894,10 @@ static inline void __init check_timer(void)
                 * Ok, does IRQ0 through the IOAPIC work?
                 */
                if (no_pin1) {
-                       add_pin_to_irq(0, apic1, pin1);
+                       add_pin_to_irq_cpu(cfg, cpu, apic1, pin1);
                        setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
                }
-               unmask_IO_APIC_irq(0);
+               unmask_IO_APIC_irq_desc(desc);
                if (timer_irq_works()) {
                        if (nmi_watchdog == NMI_IO_APIC) {
                                setup_nmi();
@@ -2682,9 +2923,9 @@ static inline void __init check_timer(void)
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
-               replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
+               replace_pin_at_irq_cpu(cfg, cpu, apic1, pin1, apic2, pin2);
                setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
-               unmask_IO_APIC_irq(0);
+               unmask_IO_APIC_irq_desc(desc);
                enable_8259A_irq(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
@@ -2716,7 +2957,7 @@ static inline void __init check_timer(void)
        apic_printk(APIC_QUIET, KERN_INFO
                    "...trying to set up timer as Virtual Wire IRQ...\n");
 
-       lapic_register_intr(0);
+       lapic_register_intr(0, desc);
        apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector);     /* Fixed mode */
        enable_8259A_irq(0);
 
@@ -2901,22 +3142,26 @@ unsigned int create_irq_nr(unsigned int irq_want)
        unsigned int irq;
        unsigned int new;
        unsigned long flags;
-       struct irq_cfg *cfg_new;
-
-       irq_want = nr_irqs - 1;
+       struct irq_cfg *cfg_new = NULL;
+       int cpu = boot_cpu_id;
+       struct irq_desc *desc_new = NULL;
 
        irq = 0;
        spin_lock_irqsave(&vector_lock, flags);
-       for (new = irq_want; new > 0; new--) {
+       for (new = irq_want; new < NR_IRQS; new++) {
                if (platform_legacy_irq(new))
                        continue;
-               cfg_new = irq_cfg(new);
-               if (cfg_new && cfg_new->vector != 0)
+
+               desc_new = irq_to_desc_alloc_cpu(new, cpu);
+               if (!desc_new) {
+                       printk(KERN_INFO "can not get irq_desc for %d\n", new);
                        continue;
-               /* check if need to create one */
-               if (!cfg_new)
-                       cfg_new = irq_cfg_alloc(new);
-               if (__assign_irq_vector(new, TARGET_CPUS) == 0)
+               }
+               cfg_new = desc_new->chip_data;
+
+               if (cfg_new->vector != 0)
+                       continue;
+               if (__assign_irq_vector(new, cfg_new, TARGET_CPUS) == 0)
                        irq = new;
                break;
        }
@@ -2924,15 +3169,21 @@ unsigned int create_irq_nr(unsigned int irq_want)
 
        if (irq > 0) {
                dynamic_irq_init(irq);
+               /* restore it, in case dynamic_irq_init clear it */
+               if (desc_new)
+                       desc_new->chip_data = cfg_new;
        }
        return irq;
 }
 
+static int nr_irqs_gsi = NR_IRQS_LEGACY;
 int create_irq(void)
 {
+       unsigned int irq_want;
        int irq;
 
-       irq = create_irq_nr(nr_irqs - 1);
+       irq_want = nr_irqs_gsi;
+       irq = create_irq_nr(irq_want);
 
        if (irq == 0)
                irq = -1;
@@ -2943,14 +3194,22 @@ int create_irq(void)
 void destroy_irq(unsigned int irq)
 {
        unsigned long flags;
+       struct irq_cfg *cfg;
+       struct irq_desc *desc;
 
+       /* store it, in case dynamic_irq_cleanup clear it */
+       desc = irq_to_desc(irq);
+       cfg = desc->chip_data;
        dynamic_irq_cleanup(irq);
+       /* connect back irq_cfg */
+       if (desc)
+               desc->chip_data = cfg;
 
 #ifdef CONFIG_INTR_REMAP
        free_irte(irq);
 #endif
        spin_lock_irqsave(&vector_lock, flags);
-       __clear_irq_vector(irq);
+       __clear_irq_vector(irq, cfg);
        spin_unlock_irqrestore(&vector_lock, flags);
 }
 
@@ -2965,12 +3224,12 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
        unsigned dest;
        cpumask_t tmp;
 
+       cfg = irq_cfg(irq);
        tmp = TARGET_CPUS;
-       err = assign_irq_vector(irq, tmp);
+       err = assign_irq_vector(irq, cfg, tmp);
        if (err)
                return err;
 
-       cfg = irq_cfg(irq);
        cpus_and(tmp, cfg->domain, tmp);
        dest = cpu_mask_to_apicid(tmp);
 
@@ -3028,35 +3287,35 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
 #ifdef CONFIG_SMP
 static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
        struct msi_msg msg;
        unsigned int dest;
        cpumask_t tmp;
-       struct irq_desc *desc;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
                return;
 
-       if (assign_irq_vector(irq, mask))
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
-       cfg = irq_cfg(irq);
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
-       read_msi_msg(irq, &msg);
+       read_msi_msg_desc(desc, &msg);
 
        msg.data &= ~MSI_DATA_VECTOR_MASK;
        msg.data |= MSI_DATA_VECTOR(cfg->vector);
        msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
-       write_msi_msg(irq, &msg);
-       desc = irq_to_desc(irq);
+       write_msi_msg_desc(desc, &msg);
        desc->affinity = mask;
 }
-
 #ifdef CONFIG_INTR_REMAP
 /*
  * Migrate the MSI irq to another cpumask. This migration is
@@ -3064,11 +3323,11 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
  */
 static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
        unsigned int dest;
        cpumask_t tmp, cleanup_mask;
        struct irte irte;
-       struct irq_desc *desc;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
@@ -3077,10 +3336,12 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
        if (get_irte(irq, &irte))
                return;
 
-       if (assign_irq_vector(irq, mask))
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
-       cfg = irq_cfg(irq);
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
@@ -3104,9 +3365,9 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
                cfg->move_in_progress = 0;
        }
 
-       desc = irq_to_desc(irq);
        desc->affinity = mask;
 }
+
 #endif
 #endif /* CONFIG_SMP */
 
@@ -3165,7 +3426,7 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
 }
 #endif
 
-static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
+static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 {
        int ret;
        struct msi_msg msg;
@@ -3174,7 +3435,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
        if (ret < 0)
                return ret;
 
-       set_irq_msi(irq, desc);
+       set_irq_msi(irq, msidesc);
        write_msi_msg(irq, &msg);
 
 #ifdef CONFIG_INTR_REMAP
@@ -3194,26 +3455,13 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
        return 0;
 }
 
-static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
-{
-       unsigned int irq;
-
-       irq = dev->bus->number;
-       irq <<= 8;
-       irq |= dev->devfn;
-       irq <<= 12;
-
-       return irq;
-}
-
-int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc)
 {
        unsigned int irq;
        int ret;
        unsigned int irq_want;
 
-       irq_want = build_irq_for_pci_dev(dev) + 0x100;
-
+       irq_want = nr_irqs_gsi;
        irq = create_irq_nr(irq_want);
        if (irq == 0)
                return -1;
@@ -3227,7 +3475,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
                goto error;
 no_ir:
 #endif
-       ret = setup_msi_irq(dev, desc, irq);
+       ret = setup_msi_irq(dev, msidesc, irq);
        if (ret < 0) {
                destroy_irq(irq);
                return ret;
@@ -3245,7 +3493,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
        unsigned int irq;
        int ret, sub_handle;
-       struct msi_desc *desc;
+       struct msi_desc *msidesc;
        unsigned int irq_want;
 
 #ifdef CONFIG_INTR_REMAP
@@ -3253,10 +3501,11 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        int index = 0;
 #endif
 
-       irq_want = build_irq_for_pci_dev(dev) + 0x100;
+       irq_want = nr_irqs_gsi;
        sub_handle = 0;
-       list_for_each_entry(desc, &dev->msi_list, list) {
-               irq = create_irq_nr(irq_want--);
+       list_for_each_entry(msidesc, &dev->msi_list, list) {
+               irq = create_irq_nr(irq_want);
+               irq_want++;
                if (irq == 0)
                        return -1;
 #ifdef CONFIG_INTR_REMAP
@@ -3288,7 +3537,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                }
 no_ir:
 #endif
-               ret = setup_msi_irq(dev, desc, irq);
+               ret = setup_msi_irq(dev, msidesc, irq);
                if (ret < 0)
                        goto error;
                sub_handle++;
@@ -3309,20 +3558,22 @@ void arch_teardown_msi_irq(unsigned int irq)
 #ifdef CONFIG_SMP
 static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
        struct msi_msg msg;
        unsigned int dest;
        cpumask_t tmp;
-       struct irq_desc *desc;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
                return;
 
-       if (assign_irq_vector(irq, mask))
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
-       cfg = irq_cfg(irq);
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
@@ -3334,9 +3585,9 @@ static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        dmar_msi_write(irq, &msg);
-       desc = irq_to_desc(irq);
        desc->affinity = mask;
 }
+
 #endif /* CONFIG_SMP */
 
 struct irq_chip dmar_msi_type = {
@@ -3370,8 +3621,8 @@ int arch_setup_dmar_msi(unsigned int irq)
 #ifdef CONFIG_SMP
 static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
-       struct irq_desc *desc;
        struct msi_msg msg;
        unsigned int dest;
        cpumask_t tmp;
@@ -3380,10 +3631,12 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
        if (cpus_empty(tmp))
                return;
 
-       if (assign_irq_vector(irq, mask))
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
-       cfg = irq_cfg(irq);
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
@@ -3395,9 +3648,9 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        hpet_msi_write(irq, &msg);
-       desc = irq_to_desc(irq);
        desc->affinity = mask;
 }
+
 #endif /* CONFIG_SMP */
 
 struct irq_chip hpet_msi_type = {
@@ -3452,26 +3705,28 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
 
 static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
 {
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irq_cfg *cfg;
        unsigned int dest;
        cpumask_t tmp;
-       struct irq_desc *desc;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
                return;
 
-       if (assign_irq_vector(irq, mask))
+       cfg = desc->chip_data;
+       if (assign_irq_vector(irq, cfg, mask))
                return;
 
-       cfg = irq_cfg(irq);
+       set_extra_move_desc(desc, mask);
+
        cpus_and(tmp, cfg->domain, mask);
        dest = cpu_mask_to_apicid(tmp);
 
        target_ht_irq(irq, dest, cfg->vector);
-       desc = irq_to_desc(irq);
        desc->affinity = mask;
 }
+
 #endif
 
 static struct irq_chip ht_irq_chip = {
@@ -3491,13 +3746,13 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
        int err;
        cpumask_t tmp;
 
+       cfg = irq_cfg(irq);
        tmp = TARGET_CPUS;
-       err = assign_irq_vector(irq, tmp);
+       err = assign_irq_vector(irq, cfg, tmp);
        if (!err) {
                struct ht_irq_msg msg;
                unsigned dest;
 
-               cfg = irq_cfg(irq);
                cpus_and(tmp, cfg->domain, tmp);
                dest = cpu_mask_to_apicid(tmp);
 
@@ -3543,7 +3798,9 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        unsigned long flags;
        int err;
 
-       err = assign_irq_vector(irq, *eligible_cpu);
+       cfg = irq_cfg(irq);
+
+       err = assign_irq_vector(irq, cfg, *eligible_cpu);
        if (err != 0)
                return err;
 
@@ -3552,8 +3809,6 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
                                      irq_name);
        spin_unlock_irqrestore(&vector_lock, flags);
 
-       cfg = irq_cfg(irq);
-
        mmr_value = 0;
        entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
        BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
@@ -3605,9 +3860,16 @@ int __init io_apic_get_redir_entries (int ioapic)
        return reg_01.bits.entries;
 }
 
-int __init probe_nr_irqs(void)
+void __init probe_nr_irqs_gsi(void)
 {
-       return NR_IRQS;
+       int idx;
+       int nr = 0;
+
+       for (idx = 0; idx < nr_ioapics; idx++)
+               nr += io_apic_get_redir_entries(idx) + 1;
+
+       if (nr > nr_irqs_gsi)
+               nr_irqs_gsi = nr;
 }
 
 /* --------------------------------------------------------------------------
@@ -3706,19 +3968,31 @@ int __init io_apic_get_version(int ioapic)
 
 int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
 {
+       struct irq_desc *desc;
+       struct irq_cfg *cfg;
+       int cpu = boot_cpu_id;
+
        if (!IO_APIC_IRQ(irq)) {
                apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
                        ioapic);
                return -EINVAL;
        }
 
+       desc = irq_to_desc_alloc_cpu(irq, cpu);
+       if (!desc) {
+               printk(KERN_INFO "can not get irq_desc %d\n", irq);
+               return 0;
+       }
+
        /*
         * IRQs < 16 are already in the irq_2_pin[] map
         */
-       if (irq >= 16)
-               add_pin_to_irq(irq, ioapic, pin);
+       if (irq >= NR_IRQS_LEGACY) {
+               cfg = desc->chip_data;
+               add_pin_to_irq_cpu(cfg, cpu, ioapic, pin);
+       }
 
-       setup_IO_APIC_irq(ioapic, pin, irq, triggering, polarity);
+       setup_IO_APIC_irq(ioapic, pin, irq, desc, triggering, polarity);
 
        return 0;
 }
@@ -3772,9 +4046,10 @@ void __init setup_ioapic_dest(void)
                         * when you have too many devices, because at that time only boot
                         * cpu is online.
                         */
-                       cfg = irq_cfg(irq);
+                       desc = irq_to_desc(irq);
+                       cfg = desc->chip_data;
                        if (!cfg->vector) {
-                               setup_IO_APIC_irq(ioapic, pin, irq,
+                               setup_IO_APIC_irq(ioapic, pin, irq, desc,
                                                  irq_trigger(irq_entry),
                                                  irq_polarity(irq_entry));
                                continue;
@@ -3784,7 +4059,6 @@ void __init setup_ioapic_dest(void)
                        /*
                         * Honour affinities which have been set in early boot
                         */
-                       desc = irq_to_desc(irq);
                        if (desc->status &
                            (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
                                mask = desc->affinity;
@@ -3793,10 +4067,10 @@ void __init setup_ioapic_dest(void)
 
 #ifdef CONFIG_INTR_REMAP
                        if (intr_remapping_enabled)
-                               set_ir_ioapic_affinity_irq(irq, mask);
+                               set_ir_ioapic_affinity_irq_desc(desc, mask);
                        else
 #endif
-                               set_ioapic_affinity_irq(irq, mask);
+                               set_ioapic_affinity_irq_desc(desc, mask);
                }
 
        }
@@ -3845,7 +4119,6 @@ void __init ioapic_init_mappings(void)
        struct resource *ioapic_res;
        int i;
 
-       irq_2_pin_init();
        ioapic_res = ioapic_setup_resources();
        for (i = 0; i < nr_ioapics; i++) {
                if (smp_found_config) {
index d1d4dc52f649cdd90f360d042b1055d7694f4e59..3f1d9d18df679c858bda94daae4d578c0d8cbf93 100644 (file)
@@ -118,6 +118,9 @@ int show_interrupts(struct seq_file *p, void *v)
        }
 
        desc = irq_to_desc(i);
+       if (!desc)
+               return 0;
+
        spin_lock_irqsave(&desc->lock, flags);
 #ifndef CONFIG_SMP
        any_count = kstat_irqs(i);
index a51382672de0c5e5fb291bd6ff6bce13396a8f73..119fc9c8ff7f29135b0e353cc31722cd6abe452f 100644 (file)
@@ -242,6 +242,8 @@ void fixup_irqs(cpumask_t map)
        for_each_irq_desc(irq, desc) {
                cpumask_t mask;
 
+               if (!desc)
+                       continue;
                if (irq == 2)
                        continue;
 
index 1df869e5bd0b935fc12e5a65b254eeb985df3f6f..a174a217eb1aefc25c971c2d6155e483d2d50192 100644 (file)
@@ -91,6 +91,8 @@ void fixup_irqs(cpumask_t map)
                int break_affinity = 0;
                int set_affinity = 1;
 
+               if (!desc)
+                       continue;
                if (irq == 2)
                        continue;
 
index 607db63044a5e6f2ea383f71378a6a79ce85797b..203384ed2b5d85342f0ad9ea4f85adf45385acb5 100644 (file)
@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
        /*
         * 16 old-style INTA-cycle interrupts:
         */
-       for (i = 0; i < 16; i++) {
-               /* first time call this irq_desc */
+       for (i = 0; i < NR_IRQS_LEGACY; i++) {
                struct irq_desc *desc = irq_to_desc(i);
 
                desc->status = IRQ_DISABLED;
index 8670b3ce626e7ee6bf0d379c610959a699d79aef..6190e6ef546cfc197e63d0a716861d94905b9a59 100644 (file)
@@ -76,8 +76,7 @@ void __init init_ISA_irqs(void)
        init_bsp_APIC();
        init_8259A(0);
 
-       for (i = 0; i < 16; i++) {
-               /* first time call this irq_desc */
+       for (i = 0; i < NR_IRQS_LEGACY; i++) {
                struct irq_desc *desc = irq_to_desc(i);
 
                desc->status = IRQ_DISABLED;
index 7a3dfceb90e47a341295ca3f1201c232b5beb814..19a1044a0cd94fbdc64b6ffd1e3df8ecde4530c9 100644 (file)
@@ -101,11 +101,15 @@ static void __init dma32_free_bootmem(void)
        dma32_bootmem_ptr = NULL;
        dma32_bootmem_size = 0;
 }
+#endif
 
 void __init pci_iommu_alloc(void)
 {
+#ifdef CONFIG_X86_64
        /* free the range so iommu could get some range less than 4G */
        dma32_free_bootmem();
+#endif
+
        /*
         * The order of these functions is important for
         * fall-back/fail-over reasons
@@ -121,15 +125,6 @@ void __init pci_iommu_alloc(void)
        pci_swiotlb_init();
 }
 
-unsigned long iommu_nr_pages(unsigned long addr, unsigned long len)
-{
-       unsigned long size = roundup((addr & ~PAGE_MASK) + len, PAGE_SIZE);
-
-       return size >> PAGE_SHIFT;
-}
-EXPORT_SYMBOL(iommu_nr_pages);
-#endif
-
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t flag)
 {
index 3c539d111abbacc9d2826ec6bcee5bbda30bfe44..242c3440687faea181b67e9f1607f76d04ee9780 100644 (file)
@@ -3,6 +3,8 @@
 #include <linux/pci.h>
 #include <linux/cache.h>
 #include <linux/module.h>
+#include <linux/swiotlb.h>
+#include <linux/bootmem.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/iommu.h>
 
 int swiotlb __read_mostly;
 
+void *swiotlb_alloc_boot(size_t size, unsigned long nslabs)
+{
+       return alloc_bootmem_low_pages(size);
+}
+
+void *swiotlb_alloc(unsigned order, unsigned long nslabs)
+{
+       return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
+}
+
+dma_addr_t swiotlb_phys_to_bus(phys_addr_t paddr)
+{
+       return paddr;
+}
+
+phys_addr_t swiotlb_bus_to_phys(dma_addr_t baddr)
+{
+       return baddr;
+}
+
+int __weak swiotlb_arch_range_needs_mapping(void *ptr, size_t size)
+{
+       return 0;
+}
+
 static dma_addr_t
 swiotlb_map_single_phys(struct device *hwdev, phys_addr_t paddr, size_t size,
                        int direction)
@@ -50,8 +77,10 @@ struct dma_mapping_ops swiotlb_dma_ops = {
 void __init pci_swiotlb_init(void)
 {
        /* don't initialize swiotlb if iommu=off (no_iommu=1) */
+#ifdef CONFIG_X86_64
        if (!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN)
               swiotlb = 1;
+#endif
        if (swiotlb_force)
                swiotlb = 1;
        if (swiotlb) {
index 67465ed8931088b52d9b521cb3a116511cef9e42..309949e9e1c1a9e65969507cb7dea1097a2410d9 100644 (file)
@@ -168,6 +168,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
                         ich_force_enable_hpet);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4,
+                        ich_force_enable_hpet);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7,
                         ich_force_enable_hpet);
 
index 08e02e8453c9a147d838daab9c21421708d22350..ae0d8042cf69527542b4e554d4567eea154eff45 100644 (file)
@@ -953,7 +953,7 @@ void __init setup_arch(char **cmdline_p)
        ioapic_init_mappings();
 
        /* need to wait for io_apic is mapped */
-       nr_irqs = probe_nr_irqs();
+       probe_nr_irqs_gsi();
 
        kvm_guest_init();
 
index 5c7cef34c9e70d31d96fc47e002fd6b6bcd8d590..10b9bd35a8ff9fbfb233883f23b970264eeb34d9 100644 (file)
@@ -30,21 +30,6 @@ ENTRY(lguest_entry)
        movl $lguest_data - __PAGE_OFFSET, %edx
        int $LGUEST_TRAP_ENTRY
 
-       /* The Host put the toplevel pagetable in lguest_data.pgdir.  The movsl
-        * instruction uses %esi implicitly as the source for the copy we're
-        * about to do. */
-       movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi
-
-       /* Copy first 32 entries of page directory to __PAGE_OFFSET entries.
-        * This means the first 128M of kernel memory will be mapped at
-        * PAGE_OFFSET where the kernel expects to run.  This will get it far
-        * enough through boot to switch to its own pagetables. */
-       movl $32, %ecx
-       movl %esi, %edi
-       addl $((__PAGE_OFFSET >> 22) * 4), %edi
-       rep
-       movsl
-
        /* Set up the initial stack so we can run C code. */
        movl $(init_thread_union+THREAD_SIZE),%esp
 
index 9e68075544f6dbb5e9a6fbc002e3a2df3091dc6c..4a20b2f9a381a360b46246c2c21c941258c1367a 100644 (file)
@@ -39,7 +39,7 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon
 #define __do_strncpy_from_user(dst, src, count, res)                      \
 do {                                                                      \
        int __d0, __d1, __d2;                                              \
-       might_sleep();                                                     \
+       might_fault();                                                     \
        __asm__ __volatile__(                                              \
                "       testl %1,%1\n"                                     \
                "       jz 2f\n"                                           \
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(strncpy_from_user);
 #define __do_clear_user(addr,size)                                     \
 do {                                                                   \
        int __d0;                                                       \
-       might_sleep();                                                  \
+       might_fault();                                                  \
        __asm__ __volatile__(                                           \
                "0:     rep; stosl\n"                                   \
                "       movl %2,%0\n"                                   \
@@ -155,7 +155,7 @@ do {                                                                        \
 unsigned long
 clear_user(void __user *to, unsigned long n)
 {
-       might_sleep();
+       might_fault();
        if (access_ok(VERIFY_WRITE, to, n))
                __do_clear_user(to, n);
        return n;
@@ -197,7 +197,7 @@ long strnlen_user(const char __user *s, long n)
        unsigned long mask = -__addr_ok(s);
        unsigned long res, tmp;
 
-       might_sleep();
+       might_fault();
 
        __asm__ __volatile__(
                "       testl %0, %0\n"
index f4df6e7c718be506a59ef157bda9591dfb1790a6..64d6c84e6353e9d50ce3d7f7cda6ee7178ca3494 100644 (file)
@@ -15,7 +15,7 @@
 #define __do_strncpy_from_user(dst,src,count,res)                         \
 do {                                                                      \
        long __d0, __d1, __d2;                                             \
-       might_sleep();                                                     \
+       might_fault();                                                     \
        __asm__ __volatile__(                                              \
                "       testq %1,%1\n"                                     \
                "       jz 2f\n"                                           \
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(strncpy_from_user);
 unsigned long __clear_user(void __user *addr, unsigned long size)
 {
        long __d0;
-       might_sleep();
+       might_fault();
        /* no memory constraint because it doesn't change any memory gcc knows
           about */
        asm volatile(
index 800e1d94c1b5580e627ddb0a2ef81cfd10d031cd..8655b5bb0963f807a0fe49dcd3da367db19379f0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/pci.h>
 #include <linux/pfn.h>
 #include <linux/poison.h>
 #include <linux/bootmem.h>
@@ -967,6 +968,8 @@ void __init mem_init(void)
        int codesize, reservedpages, datasize, initsize;
        int tmp;
 
+       pci_iommu_alloc();
+
 #ifdef CONFIG_FLATMEM
        BUG_ON(!mem_map);
 #endif
index 509513760a6e45c6ccade4b0054cf93f508add84..98658f25f542b0be2a62116f1dcd61cb6d4e09a7 100644 (file)
@@ -65,11 +65,13 @@ static unsigned long reset_value[NUM_COUNTERS];
 #define IBS_FETCH_BEGIN 3
 #define IBS_OP_BEGIN    4
 
-/* The function interface needs to be fixed, something like add
-   data. Should then be added to linux/oprofile.h. */
+/*
+ * The function interface needs to be fixed, something like add
+ * data. Should then be added to linux/oprofile.h.
+ */
 extern void
-oprofile_add_ibs_sample(struct pt_regs *const regs,
-                       unsigned int *const ibs_sample, int ibs_code);
+oprofile_add_ibs_sample(struct pt_regs * const regs,
+                       unsigned int * const ibs_sample, int ibs_code);
 
 struct ibs_fetch_sample {
        /* MSRC001_1031 IBS Fetch Linear Address Register */
@@ -104,11 +106,6 @@ struct ibs_op_sample {
        unsigned int ibs_dc_phys_high;
 };
 
-/*
- * unitialize the APIC for the IBS interrupts if needed on AMD Family10h+
-*/
-static void clear_ibs_nmi(void);
-
 static int ibs_allowed;        /* AMD Family10h and later */
 
 struct op_ibs_config {
@@ -223,7 +220,7 @@ op_amd_handle_ibs(struct pt_regs * const regs,
                                                (unsigned int *)&ibs_fetch,
                                                IBS_FETCH_BEGIN);
 
-                       /*reenable the IRQ */
+                       /* reenable the IRQ */
                        rdmsr(MSR_AMD64_IBSFETCHCTL, low, high);
                        high &= ~IBS_FETCH_HIGH_VALID_BIT;
                        high |= IBS_FETCH_HIGH_ENABLE;
@@ -331,8 +328,10 @@ static void op_amd_stop(struct op_msrs const * const msrs)
        unsigned int low, high;
        int i;
 
-       /* Subtle: stop on all counters to avoid race with
-        * setting our pm callback */
+       /*
+        * Subtle: stop on all counters to avoid race with setting our
+        * pm callback
+        */
        for (i = 0 ; i < NUM_COUNTERS ; ++i) {
                if (!reset_value[i])
                        continue;
@@ -343,13 +342,15 @@ static void op_amd_stop(struct op_msrs const * const msrs)
 
 #ifdef CONFIG_OPROFILE_IBS
        if (ibs_allowed && ibs_config.fetch_enabled) {
-               low = 0;                /* clear max count and enable */
+               /* clear max count and enable */
+               low = 0;
                high = 0;
                wrmsr(MSR_AMD64_IBSFETCHCTL, low, high);
        }
 
        if (ibs_allowed && ibs_config.op_enabled) {
-               low = 0;                /* clear max count and enable */
+               /* clear max count and enable */
+               low = 0;
                high = 0;
                wrmsr(MSR_AMD64_IBSOPCTL, low, high);
        }
@@ -370,18 +371,7 @@ static void op_amd_shutdown(struct op_msrs const * const msrs)
        }
 }
 
-#ifndef CONFIG_OPROFILE_IBS
-
-/* no IBS support */
-
-static int op_amd_init(struct oprofile_operations *ops)
-{
-       return 0;
-}
-
-static void op_amd_exit(void) {}
-
-#else
+#ifdef CONFIG_OPROFILE_IBS
 
 static u8 ibs_eilvt_off;
 
@@ -395,7 +385,7 @@ static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
        setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
 }
 
-static int pfm_amd64_setup_eilvt(void)
+static int init_ibs_nmi(void)
 {
 #define IBSCTL_LVTOFFSETVAL            (1 << 8)
 #define IBSCTL                         0x1cc
@@ -443,18 +433,22 @@ static int pfm_amd64_setup_eilvt(void)
        return 0;
 }
 
-/*
- * initialize the APIC for the IBS interrupts
- * if available (AMD Family10h rev B0 and later)
- */
-static void setup_ibs(void)
+/* uninitialize the APIC for the IBS interrupts if needed */
+static void clear_ibs_nmi(void)
+{
+       if (ibs_allowed)
+               on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+}
+
+/* initialize the APIC for the IBS interrupts if available */
+static void ibs_init(void)
 {
        ibs_allowed = boot_cpu_has(X86_FEATURE_IBS);
 
        if (!ibs_allowed)
                return;
 
-       if (pfm_amd64_setup_eilvt()) {
+       if (init_ibs_nmi()) {
                ibs_allowed = 0;
                return;
        }
@@ -462,14 +456,12 @@ static void setup_ibs(void)
        printk(KERN_INFO "oprofile: AMD IBS detected\n");
 }
 
-
-/*
- * unitialize the APIC for the IBS interrupts if needed on AMD Family10h
- * rev B0 and later */
-static void clear_ibs_nmi(void)
+static void ibs_exit(void)
 {
-       if (ibs_allowed)
-               on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
+       if (!ibs_allowed)
+               return;
+
+       clear_ibs_nmi();
 }
 
 static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
@@ -519,7 +511,7 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root)
 
 static int op_amd_init(struct oprofile_operations *ops)
 {
-       setup_ibs();
+       ibs_init();
        create_arch_files = ops->create_files;
        ops->create_files = setup_ibs_files;
        return 0;
@@ -527,10 +519,21 @@ static int op_amd_init(struct oprofile_operations *ops)
 
 static void op_amd_exit(void)
 {
-       clear_ibs_nmi();
+       ibs_exit();
 }
 
-#endif
+#else
+
+/* no IBS support */
+
+static int op_amd_init(struct oprofile_operations *ops)
+{
+       return 0;
+}
+
+static void op_amd_exit(void) {}
+
+#endif /* CONFIG_OPROFILE_IBS */
 
 struct op_x86_model_spec const op_amd_spec = {
        .init                   = op_amd_init,
index 290b219fad9c5a1b825d495c8ea427bda7b04c5c..ac0956f77785ad55cd9d771ab65b9ce7c4797716 100644 (file)
@@ -24,21 +24,17 @@ menuconfig BLOCK
 if BLOCK
 
 config LBD
-       bool "Support for Large Block Devices"
+       bool "Support for large block devices and files"
        depends on !64BIT
        help
-         Enable block devices of size 2TB and larger.
+         Enable block devices or files of size 2TB and larger.
 
          This option is required to support the full capacity of large
          (2TB+) block devices, including RAID, disk, Network Block Device,
          Logical Volume Manager (LVM) and loopback.
-
-         For example, RAID devices are frequently bigger than the capacity
-         of the largest individual hard drive.
-
-         This option is not required if you have individual disk drives
-         which total 2TB+ and you are not aggregating the capacity into
-         a large block device (e.g. using RAID or LVM).
+       
+         This option also enables support for single files larger than
+         2TB.
 
          If unsure, say N.
 
@@ -58,15 +54,6 @@ config BLK_DEV_IO_TRACE
 
          If unsure, say N.
 
-config LSF
-       bool "Support for Large Single Files"
-       depends on !64BIT
-       help
-         Say Y here if you want to be able to handle very large files (2TB
-         and larger), otherwise say N.
-
-         If unsure, say Y.
-
 config BLK_DEV_BSG
        bool "Block layer SG support v4 (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index 71f0abb219eee2556d41dcc9f1f1e01834b6d8aa..631f6f44460a2bd7ad7218f89d5e15bb90742ee6 100644 (file)
@@ -1339,12 +1339,12 @@ static int as_may_queue(struct request_queue *q, int rw)
        return ret;
 }
 
-static void as_exit_queue(elevator_t *e)
+static void as_exit_queue(struct elevator_queue *e)
 {
        struct as_data *ad = e->elevator_data;
 
        del_timer_sync(&ad->antic_timer);
-       kblockd_flush_work(&ad->antic_work);
+       cancel_work_sync(&ad->antic_work);
 
        BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC]));
        BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC]));
@@ -1409,7 +1409,7 @@ as_var_store(unsigned long *var, const char *page, size_t count)
        return count;
 }
 
-static ssize_t est_time_show(elevator_t *e, char *page)
+static ssize_t est_time_show(struct elevator_queue *e, char *page)
 {
        struct as_data *ad = e->elevator_data;
        int pos = 0;
@@ -1427,7 +1427,7 @@ static ssize_t est_time_show(elevator_t *e, char *page)
 }
 
 #define SHOW_FUNCTION(__FUNC, __VAR)                           \
-static ssize_t __FUNC(elevator_t *e, char *page)               \
+static ssize_t __FUNC(struct elevator_queue *e, char *page)    \
 {                                                              \
        struct as_data *ad = e->elevator_data;                  \
        return as_var_show(jiffies_to_msecs((__VAR)), (page));  \
@@ -1440,7 +1440,7 @@ SHOW_FUNCTION(as_write_batch_expire_show, ad->batch_expire[REQ_ASYNC]);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX)                                \
-static ssize_t __FUNC(elevator_t *e, const char *page, size_t count)   \
+static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count)        \
 {                                                                      \
        struct as_data *ad = e->elevator_data;                          \
        int ret = as_var_store(__PTR, (page), count);                   \
index 6e72d661ae425daa62f8b7999acc8f825e2a12e9..8eba4e43bb0c505c9c0e846ddd33caf0f15bfdd7 100644 (file)
@@ -24,8 +24,8 @@
 int blk_queue_ordered(struct request_queue *q, unsigned ordered,
                      prepare_flush_fn *prepare_flush_fn)
 {
-       if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) &&
-           prepare_flush_fn == NULL) {
+       if (!prepare_flush_fn && (ordered & (QUEUE_ORDERED_DO_PREFLUSH |
+                                            QUEUE_ORDERED_DO_POSTFLUSH))) {
                printk(KERN_ERR "%s: prepare_flush_fn required\n", __func__);
                return -EINVAL;
        }
@@ -88,7 +88,7 @@ unsigned blk_ordered_req_seq(struct request *rq)
                return QUEUE_ORDSEQ_DONE;
 }
 
-void blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
+bool blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
 {
        struct request *rq;
 
@@ -99,7 +99,7 @@ void blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
        q->ordseq |= seq;
 
        if (blk_ordered_cur_seq(q) != QUEUE_ORDSEQ_DONE)
-               return;
+               return false;
 
        /*
         * Okay, sequence complete.
@@ -109,6 +109,8 @@ void blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
 
        if (__blk_end_request(rq, q->orderr, blk_rq_bytes(rq)))
                BUG();
+
+       return true;
 }
 
 static void pre_flush_end_io(struct request *rq, int error)
@@ -134,7 +136,7 @@ static void queue_flush(struct request_queue *q, unsigned which)
        struct request *rq;
        rq_end_io_fn *end_io;
 
-       if (which == QUEUE_ORDERED_PREFLUSH) {
+       if (which == QUEUE_ORDERED_DO_PREFLUSH) {
                rq = &q->pre_flush_rq;
                end_io = pre_flush_end_io;
        } else {
@@ -151,80 +153,110 @@ static void queue_flush(struct request_queue *q, unsigned which)
        elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
 }
 
-static inline struct request *start_ordered(struct request_queue *q,
-                                           struct request *rq)
+static inline bool start_ordered(struct request_queue *q, struct request **rqp)
 {
+       struct request *rq = *rqp;
+       unsigned skip = 0;
+
        q->orderr = 0;
        q->ordered = q->next_ordered;
        q->ordseq |= QUEUE_ORDSEQ_STARTED;
 
        /*
-        * Prep proxy barrier request.
+        * For an empty barrier, there's no actual BAR request, which
+        * in turn makes POSTFLUSH unnecessary.  Mask them off.
         */
+       if (!rq->hard_nr_sectors) {
+               q->ordered &= ~(QUEUE_ORDERED_DO_BAR |
+                               QUEUE_ORDERED_DO_POSTFLUSH);
+               /*
+                * Empty barrier on a write-through device w/ ordered
+                * tag has no command to issue and without any command
+                * to issue, ordering by tag can't be used.  Drain
+                * instead.
+                */
+               if ((q->ordered & QUEUE_ORDERED_BY_TAG) &&
+                   !(q->ordered & QUEUE_ORDERED_DO_PREFLUSH)) {
+                       q->ordered &= ~QUEUE_ORDERED_BY_TAG;
+                       q->ordered |= QUEUE_ORDERED_BY_DRAIN;
+               }
+       }
+
+       /* stash away the original request */
        elv_dequeue_request(q, rq);
        q->orig_bar_rq = rq;
-       rq = &q->bar_rq;
-       blk_rq_init(q, rq);
-       if (bio_data_dir(q->orig_bar_rq->bio) == WRITE)
-               rq->cmd_flags |= REQ_RW;
-       if (q->ordered & QUEUE_ORDERED_FUA)
-               rq->cmd_flags |= REQ_FUA;
-       init_request_from_bio(rq, q->orig_bar_rq->bio);
-       rq->end_io = bar_end_io;
+       rq = NULL;
 
        /*
         * Queue ordered sequence.  As we stack them at the head, we
         * need to queue in reverse order.  Note that we rely on that
         * no fs request uses ELEVATOR_INSERT_FRONT and thus no fs
-        * request gets inbetween ordered sequence. If this request is
-        * an empty barrier, we don't need to do a postflush ever since
-        * there will be no data written between the pre and post flush.
-        * Hence a single flush will suffice.
+        * request gets inbetween ordered sequence.
         */
-       if ((q->ordered & QUEUE_ORDERED_POSTFLUSH) && !blk_empty_barrier(rq))
-               queue_flush(q, QUEUE_ORDERED_POSTFLUSH);
-       else
-               q->ordseq |= QUEUE_ORDSEQ_POSTFLUSH;
+       if (q->ordered & QUEUE_ORDERED_DO_POSTFLUSH) {
+               queue_flush(q, QUEUE_ORDERED_DO_POSTFLUSH);
+               rq = &q->post_flush_rq;
+       } else
+               skip |= QUEUE_ORDSEQ_POSTFLUSH;
 
-       elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
+       if (q->ordered & QUEUE_ORDERED_DO_BAR) {
+               rq = &q->bar_rq;
+
+               /* initialize proxy request and queue it */
+               blk_rq_init(q, rq);
+               if (bio_data_dir(q->orig_bar_rq->bio) == WRITE)
+                       rq->cmd_flags |= REQ_RW;
+               if (q->ordered & QUEUE_ORDERED_DO_FUA)
+                       rq->cmd_flags |= REQ_FUA;
+               init_request_from_bio(rq, q->orig_bar_rq->bio);
+               rq->end_io = bar_end_io;
 
-       if (q->ordered & QUEUE_ORDERED_PREFLUSH) {
-               queue_flush(q, QUEUE_ORDERED_PREFLUSH);
+               elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
+       } else
+               skip |= QUEUE_ORDSEQ_BAR;
+
+       if (q->ordered & QUEUE_ORDERED_DO_PREFLUSH) {
+               queue_flush(q, QUEUE_ORDERED_DO_PREFLUSH);
                rq = &q->pre_flush_rq;
        } else
-               q->ordseq |= QUEUE_ORDSEQ_PREFLUSH;
+               skip |= QUEUE_ORDSEQ_PREFLUSH;
 
-       if ((q->ordered & QUEUE_ORDERED_TAG) || q->in_flight == 0)
-               q->ordseq |= QUEUE_ORDSEQ_DRAIN;
-       else
+       if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && q->in_flight)
                rq = NULL;
+       else
+               skip |= QUEUE_ORDSEQ_DRAIN;
+
+       *rqp = rq;
 
-       return rq;
+       /*
+        * Complete skipped sequences.  If whole sequence is complete,
+        * return false to tell elevator that this request is gone.
+        */
+       return !blk_ordered_complete_seq(q, skip, 0);
 }
 
-int blk_do_ordered(struct request_queue *q, struct request **rqp)
+bool blk_do_ordered(struct request_queue *q, struct request **rqp)
 {
        struct request *rq = *rqp;
        const int is_barrier = blk_fs_request(rq) && blk_barrier_rq(rq);
 
        if (!q->ordseq) {
                if (!is_barrier)
-                       return 1;
+                       return true;
 
-               if (q->next_ordered != QUEUE_ORDERED_NONE) {
-                       *rqp = start_ordered(q, rq);
-                       return 1;
-               } else {
+               if (q->next_ordered != QUEUE_ORDERED_NONE)
+                       return start_ordered(q, rqp);
+               else {
                        /*
-                        * This can happen when the queue switches to
-                        * ORDERED_NONE while this request is on it.
+                        * Queue ordering not supported.  Terminate
+                        * with prejudice.
                         */
                        elv_dequeue_request(q, rq);
                        if (__blk_end_request(rq, -EOPNOTSUPP,
                                              blk_rq_bytes(rq)))
                                BUG();
                        *rqp = NULL;
-                       return 0;
+                       return false;
                }
        }
 
@@ -235,9 +267,9 @@ int blk_do_ordered(struct request_queue *q, struct request **rqp)
        /* Special requests are not subject to ordering rules. */
        if (!blk_fs_request(rq) &&
            rq != &q->pre_flush_rq && rq != &q->post_flush_rq)
-               return 1;
+               return true;
 
-       if (q->ordered & QUEUE_ORDERED_TAG) {
+       if (q->ordered & QUEUE_ORDERED_BY_TAG) {
                /* Ordered by tag.  Blocking the next barrier is enough. */
                if (is_barrier && rq != &q->bar_rq)
                        *rqp = NULL;
@@ -248,7 +280,7 @@ int blk_do_ordered(struct request_queue *q, struct request **rqp)
                        *rqp = NULL;
        }
 
-       return 1;
+       return true;
 }
 
 static void bio_end_empty_barrier(struct bio *bio, int err)
index 561e8a1b43a4a526e405905c69cf8f0e15a4df27..a824e49c0d0ac0567ad8294f6289544fa40553b6 100644 (file)
@@ -153,6 +153,9 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
                        nbytes = bio->bi_size;
                }
 
+               if (unlikely(rq->cmd_flags & REQ_QUIET))
+                       set_bit(BIO_QUIET, &bio->bi_flags);
+
                bio->bi_size -= nbytes;
                bio->bi_sector += (nbytes >> 9);
 
@@ -265,8 +268,7 @@ void __generic_unplug_device(struct request_queue *q)
 {
        if (unlikely(blk_queue_stopped(q)))
                return;
-
-       if (!blk_remove_plug(q))
+       if (!blk_remove_plug(q) && !blk_queue_nonrot(q))
                return;
 
        q->request_fn(q);
@@ -404,7 +406,8 @@ EXPORT_SYMBOL(blk_stop_queue);
 void blk_sync_queue(struct request_queue *q)
 {
        del_timer_sync(&q->unplug_timer);
-       kblockd_flush_work(&q->unplug_work);
+       del_timer_sync(&q->timeout);
+       cancel_work_sync(&q->unplug_work);
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
@@ -1135,7 +1138,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)
 static int __make_request(struct request_queue *q, struct bio *bio)
 {
        struct request *req;
-       int el_ret, nr_sectors, barrier, discard, err;
+       int el_ret, nr_sectors;
        const unsigned short prio = bio_prio(bio);
        const int sync = bio_sync(bio);
        int rw_flags;
@@ -1149,22 +1152,9 @@ static int __make_request(struct request_queue *q, struct bio *bio)
         */
        blk_queue_bounce(q, &bio);
 
-       barrier = bio_barrier(bio);
-       if (unlikely(barrier) && bio_has_data(bio) &&
-           (q->next_ordered == QUEUE_ORDERED_NONE)) {
-               err = -EOPNOTSUPP;
-               goto end_io;
-       }
-
-       discard = bio_discard(bio);
-       if (unlikely(discard) && !q->prepare_discard_fn) {
-               err = -EOPNOTSUPP;
-               goto end_io;
-       }
-
        spin_lock_irq(q->queue_lock);
 
-       if (unlikely(barrier) || elv_queue_empty(q))
+       if (unlikely(bio_barrier(bio)) || elv_queue_empty(q))
                goto get_rq;
 
        el_ret = elv_merge(q, &req, bio);
@@ -1250,18 +1240,14 @@ get_rq:
        if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags) ||
            bio_flagged(bio, BIO_CPU_AFFINE))
                req->cpu = blk_cpu_to_group(smp_processor_id());
-       if (elv_queue_empty(q))
+       if (!blk_queue_nonrot(q) && elv_queue_empty(q))
                blk_plug_device(q);
        add_request(q, req);
 out:
-       if (sync)
+       if (sync || blk_queue_nonrot(q))
                __generic_unplug_device(q);
        spin_unlock_irq(q->queue_lock);
        return 0;
-
-end_io:
-       bio_endio(bio, err);
-       return 0;
 }
 
 /*
@@ -1414,15 +1400,13 @@ static inline void __generic_make_request(struct bio *bio)
                char b[BDEVNAME_SIZE];
 
                q = bdev_get_queue(bio->bi_bdev);
-               if (!q) {
+               if (unlikely(!q)) {
                        printk(KERN_ERR
                               "generic_make_request: Trying to access "
                                "nonexistent block-device %s (%Lu)\n",
                                bdevname(bio->bi_bdev, b),
                                (long long) bio->bi_sector);
-end_io:
-                       bio_endio(bio, err);
-                       break;
+                       goto end_io;
                }
 
                if (unlikely(nr_sectors > q->max_hw_sectors)) {
@@ -1459,14 +1443,19 @@ end_io:
 
                if (bio_check_eod(bio, nr_sectors))
                        goto end_io;
-               if ((bio_empty_barrier(bio) && !q->prepare_flush_fn) ||
-                   (bio_discard(bio) && !q->prepare_discard_fn)) {
+
+               if (bio_discard(bio) && !q->prepare_discard_fn) {
                        err = -EOPNOTSUPP;
                        goto end_io;
                }
 
                ret = q->make_request_fn(q, bio);
        } while (ret);
+
+       return;
+
+end_io:
+       bio_endio(bio, err);
 }
 
 /*
@@ -1716,14 +1705,6 @@ static int __end_that_request_first(struct request *req, int error,
        while ((bio = req->bio) != NULL) {
                int nbytes;
 
-               /*
-                * For an empty barrier request, the low level driver must
-                * store a potential error location in ->sector. We pass
-                * that back up in ->bi_sector.
-                */
-               if (blk_empty_barrier(req))
-                       bio->bi_sector = req->sector;
-
                if (nr_bytes >= bio->bi_size) {
                        req->bio = bio->bi_next;
                        nbytes = bio->bi_size;
@@ -2143,12 +2124,6 @@ int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-void kblockd_flush_work(struct work_struct *work)
-{
-       cancel_work_sync(work);
-}
-EXPORT_SYMBOL(kblockd_flush_work);
-
 int __init blk_dev_init(void)
 {
        kblockd_workqueue = create_workqueue("kblockd");
index afa55e14e27896837cb026ce706438520ea848aa..59fd05d9f1d5d8022d1b16a5263d6ae087aadb21 100644 (file)
@@ -319,9 +319,9 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
        t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
        t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask);
 
-       t->max_phys_segments = min(t->max_phys_segments, b->max_phys_segments);
-       t->max_hw_segments = min(t->max_hw_segments, b->max_hw_segments);
-       t->max_segment_size = min(t->max_segment_size, b->max_segment_size);
+       t->max_phys_segments = min_not_zero(t->max_phys_segments, b->max_phys_segments);
+       t->max_hw_segments = min_not_zero(t->max_hw_segments, b->max_hw_segments);
+       t->max_segment_size = min_not_zero(t->max_segment_size, b->max_segment_size);
        t->hardsect_size = max(t->hardsect_size, b->hardsect_size);
        if (!t->queue_lock)
                WARN_ON_ONCE(1);
index e660d26ca656f060ca0c5a61952681c7b7d55e66..ce0efc6b26dc54cfabf225d4a78265ef401a9a24 100644 (file)
@@ -161,7 +161,7 @@ void blk_complete_request(struct request *req)
 }
 EXPORT_SYMBOL(blk_complete_request);
 
-__init int blk_softirq_init(void)
+static __init int blk_softirq_init(void)
 {
        int i;
 
index 21e275d7eed9444ab876834db2345eb78f4ae183..a29cb788e408e720b0b8023fca95a9f3d26a3e8c 100644 (file)
@@ -88,9 +88,7 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count)
        unsigned long ra_kb;
        ssize_t ret = queue_var_store(&ra_kb, page, count);
 
-       spin_lock_irq(q->queue_lock);
        q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
-       spin_unlock_irq(q->queue_lock);
 
        return ret;
 }
@@ -117,10 +115,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
 
        if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb)
                return -EINVAL;
-       /*
-        * Take the queue lock to update the readahead and max_sectors
-        * values synchronously:
-        */
+
        spin_lock_irq(q->queue_lock);
        q->max_sectors = max_sectors_kb << 1;
        spin_unlock_irq(q->queue_lock);
index c0d419e84ce7f8518e1246e3ec61b07f5c81efe8..3c518e3303ae34113516924f9d73a58b94a1e75c 100644 (file)
@@ -158,7 +158,6 @@ fail:
 /**
  * blk_init_tags - initialize the tag info for an external tag map
  * @depth:     the maximum queue depth supported
- * @tags: the tag to use
  **/
 struct blk_queue_tag *blk_init_tags(int depth)
 {
index 69185ea9fae26d4f643b6e70e07a3cd2e2265100..a09535377a94c0b84a59118533f5e4ddeaa1076d 100644 (file)
@@ -73,11 +73,7 @@ ssize_t part_timeout_store(struct device *dev, struct device_attribute *attr,
  */
 void blk_delete_timer(struct request *req)
 {
-       struct request_queue *q = req->q;
-
        list_del_init(&req->timeout_list);
-       if (list_empty(&q->timeout_list))
-               del_timer(&q->timeout);
 }
 
 static void blk_rq_timed_out(struct request *req)
@@ -111,7 +107,7 @@ static void blk_rq_timed_out(struct request *req)
 void blk_rq_timed_out_timer(unsigned long data)
 {
        struct request_queue *q = (struct request_queue *) data;
-       unsigned long flags, uninitialized_var(next), next_set = 0;
+       unsigned long flags, next = 0;
        struct request *rq, *tmp;
 
        spin_lock_irqsave(q->queue_lock, flags);
@@ -126,15 +122,18 @@ void blk_rq_timed_out_timer(unsigned long data)
                        if (blk_mark_rq_complete(rq))
                                continue;
                        blk_rq_timed_out(rq);
+               } else {
+                       if (!next || time_after(next, rq->deadline))
+                               next = rq->deadline;
                }
-               if (!next_set) {
-                       next = rq->deadline;
-                       next_set = 1;
-               } else if (time_after(next, rq->deadline))
-                       next = rq->deadline;
        }
 
-       if (next_set && !list_empty(&q->timeout_list))
+       /*
+        * next can never be 0 here with the list non-empty, since we always
+        * bump ->deadline to 1 so we can detect if the timer was ever added
+        * or not. See comment in blk_add_timer()
+        */
+       if (next)
                mod_timer(&q->timeout, round_jiffies_up(next));
 
        spin_unlock_irqrestore(q->queue_lock, flags);
index 6a062eebbd15301320e7491b5dd45d17f2204a3c..e8525fa72823a0c88adfd386e84e7b3e5db33af7 100644 (file)
@@ -1136,12 +1136,8 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
                if (cfq_class_idle(cfqq))
                        max_dispatch = 1;
 
-               if (cfqq->dispatched >= max_dispatch) {
-                       if (cfqd->busy_queues > 1)
-                               break;
-                       if (cfqq->dispatched >= 4 * max_dispatch)
-                               break;
-               }
+               if (cfqq->dispatched >= max_dispatch && cfqd->busy_queues > 1)
+                       break;
 
                if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
                        break;
@@ -1318,7 +1314,15 @@ static void cfq_exit_single_io_context(struct io_context *ioc,
                unsigned long flags;
 
                spin_lock_irqsave(q->queue_lock, flags);
-               __cfq_exit_single_io_context(cfqd, cic);
+
+               /*
+                * Ensure we get a fresh copy of the ->key to prevent
+                * race between exiting task and queue
+                */
+               smp_read_barrier_depends();
+               if (cic->key)
+                       __cfq_exit_single_io_context(cfqd, cic);
+
                spin_unlock_irqrestore(q->queue_lock, flags);
        }
 }
@@ -2160,7 +2164,7 @@ out_cont:
 static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
 {
        del_timer_sync(&cfqd->idle_slice_timer);
-       kblockd_flush_work(&cfqd->unplug_work);
+       cancel_work_sync(&cfqd->unplug_work);
 }
 
 static void cfq_put_async_queues(struct cfq_data *cfqd)
@@ -2178,7 +2182,7 @@ static void cfq_put_async_queues(struct cfq_data *cfqd)
                cfq_put_queue(cfqd->async_idle_cfqq);
 }
 
-static void cfq_exit_queue(elevator_t *e)
+static void cfq_exit_queue(struct elevator_queue *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
        struct request_queue *q = cfqd->queue;
@@ -2288,7 +2292,7 @@ cfq_var_store(unsigned int *var, const char *page, size_t count)
 }
 
 #define SHOW_FUNCTION(__FUNC, __VAR, __CONV)                           \
-static ssize_t __FUNC(elevator_t *e, char *page)                       \
+static ssize_t __FUNC(struct elevator_queue *e, char *page)            \
 {                                                                      \
        struct cfq_data *cfqd = e->elevator_data;                       \
        unsigned int __data = __VAR;                                    \
@@ -2308,7 +2312,7 @@ SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
-static ssize_t __FUNC(elevator_t *e, const char *page, size_t count)   \
+static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count)        \
 {                                                                      \
        struct cfq_data *cfqd = e->elevator_data;                       \
        unsigned int __data;                                            \
index 67eb93cff699ba2a4dc9231f73c0d4d46d9fc443..f87615dea46bbd9dfcdf0789f170c2b9b8512f6a 100644 (file)
@@ -774,9 +774,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                bdi = blk_get_backing_dev_info(bdev);
                if (bdi == NULL)
                        return -ENOTTY;
-               lock_kernel();
                bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
-               unlock_kernel();
                return 0;
        case BLKGETSIZE:
                size = bdev->bd_inode->i_size;
index fd311179f44c771f5c4ca49c2d67b3812fe47eb9..c4d991d4adef0e7fd6e0d432941b88771d7c6530 100644 (file)
@@ -334,7 +334,7 @@ static int deadline_queue_empty(struct request_queue *q)
                && list_empty(&dd->fifo_list[READ]);
 }
 
-static void deadline_exit_queue(elevator_t *e)
+static void deadline_exit_queue(struct elevator_queue *e)
 {
        struct deadline_data *dd = e->elevator_data;
 
@@ -387,7 +387,7 @@ deadline_var_store(int *var, const char *page, size_t count)
 }
 
 #define SHOW_FUNCTION(__FUNC, __VAR, __CONV)                           \
-static ssize_t __FUNC(elevator_t *e, char *page)                       \
+static ssize_t __FUNC(struct elevator_queue *e, char *page)            \
 {                                                                      \
        struct deadline_data *dd = e->elevator_data;                    \
        int __data = __VAR;                                             \
@@ -403,7 +403,7 @@ SHOW_FUNCTION(deadline_fifo_batch_show, dd->fifo_batch, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
-static ssize_t __FUNC(elevator_t *e, const char *page, size_t count)   \
+static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count)        \
 {                                                                      \
        struct deadline_data *dd = e->elevator_data;                    \
        int __data;                                                     \
index 86836dd179c05476078719869a0481777e999bc1..98259eda0ef66d4051cc5da958c0191f353b8158 100644 (file)
@@ -65,7 +65,7 @@ DEFINE_TRACE(block_rq_issue);
 static int elv_iosched_allow_merge(struct request *rq, struct bio *bio)
 {
        struct request_queue *q = rq->q;
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_allow_merge_fn)
                return e->ops->elevator_allow_merge_fn(q, rq, bio);
@@ -208,13 +208,13 @@ __setup("elevator=", elevator_setup);
 
 static struct kobj_type elv_ktype;
 
-static elevator_t *elevator_alloc(struct request_queue *q,
+static struct elevator_queue *elevator_alloc(struct request_queue *q,
                                  struct elevator_type *e)
 {
-       elevator_t *eq;
+       struct elevator_queue *eq;
        int i;
 
-       eq = kmalloc_node(sizeof(elevator_t), GFP_KERNEL | __GFP_ZERO, q->node);
+       eq = kmalloc_node(sizeof(*eq), GFP_KERNEL | __GFP_ZERO, q->node);
        if (unlikely(!eq))
                goto err;
 
@@ -240,8 +240,9 @@ err:
 
 static void elevator_release(struct kobject *kobj)
 {
-       elevator_t *e = container_of(kobj, elevator_t, kobj);
+       struct elevator_queue *e;
 
+       e = container_of(kobj, struct elevator_queue, kobj);
        elevator_put(e->elevator_type);
        kfree(e->hash);
        kfree(e);
@@ -297,7 +298,7 @@ int elevator_init(struct request_queue *q, char *name)
 }
 EXPORT_SYMBOL(elevator_init);
 
-void elevator_exit(elevator_t *e)
+void elevator_exit(struct elevator_queue *e)
 {
        mutex_lock(&e->sysfs_lock);
        if (e->ops->elevator_exit_fn)
@@ -311,7 +312,7 @@ EXPORT_SYMBOL(elevator_exit);
 
 static void elv_activate_rq(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_activate_req_fn)
                e->ops->elevator_activate_req_fn(q, rq);
@@ -319,7 +320,7 @@ static void elv_activate_rq(struct request_queue *q, struct request *rq)
 
 static void elv_deactivate_rq(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_deactivate_req_fn)
                e->ops->elevator_deactivate_req_fn(q, rq);
@@ -338,7 +339,7 @@ static void elv_rqhash_del(struct request_queue *q, struct request *rq)
 
 static void elv_rqhash_add(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        BUG_ON(ELV_ON_HASH(rq));
        hlist_add_head(&rq->hash, &e->hash[ELV_HASH_FN(rq_hash_key(rq))]);
@@ -352,7 +353,7 @@ static void elv_rqhash_reposition(struct request_queue *q, struct request *rq)
 
 static struct request *elv_rqhash_find(struct request_queue *q, sector_t offset)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
        struct hlist_head *hash_list = &e->hash[ELV_HASH_FN(offset)];
        struct hlist_node *entry, *next;
        struct request *rq;
@@ -494,7 +495,7 @@ EXPORT_SYMBOL(elv_dispatch_add_tail);
 
 int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
        struct request *__rq;
        int ret;
 
@@ -529,7 +530,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
 
 void elv_merged_request(struct request_queue *q, struct request *rq, int type)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_merged_fn)
                e->ops->elevator_merged_fn(q, rq, type);
@@ -543,7 +544,7 @@ void elv_merged_request(struct request_queue *q, struct request *rq, int type)
 void elv_merge_requests(struct request_queue *q, struct request *rq,
                             struct request *next)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_merge_req_fn)
                e->ops->elevator_merge_req_fn(q, rq, next);
@@ -755,14 +756,6 @@ struct request *elv_next_request(struct request_queue *q)
        int ret;
 
        while ((rq = __elv_next_request(q)) != NULL) {
-               /*
-                * Kill the empty barrier place holder, the driver must
-                * not ever see it.
-                */
-               if (blk_empty_barrier(rq)) {
-                       __blk_end_request(rq, 0, blk_rq_bytes(rq));
-                       continue;
-               }
                if (!(rq->cmd_flags & REQ_STARTED)) {
                        /*
                         * This is the first time the device driver
@@ -854,7 +847,7 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq)
 
 int elv_queue_empty(struct request_queue *q)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (!list_empty(&q->queue_head))
                return 0;
@@ -868,7 +861,7 @@ EXPORT_SYMBOL(elv_queue_empty);
 
 struct request *elv_latter_request(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_latter_req_fn)
                return e->ops->elevator_latter_req_fn(q, rq);
@@ -877,7 +870,7 @@ struct request *elv_latter_request(struct request_queue *q, struct request *rq)
 
 struct request *elv_former_request(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_former_req_fn)
                return e->ops->elevator_former_req_fn(q, rq);
@@ -886,7 +879,7 @@ struct request *elv_former_request(struct request_queue *q, struct request *rq)
 
 int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_set_req_fn)
                return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
@@ -897,7 +890,7 @@ int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
 
 void elv_put_request(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_put_req_fn)
                e->ops->elevator_put_req_fn(rq);
@@ -905,7 +898,7 @@ void elv_put_request(struct request_queue *q, struct request *rq)
 
 int elv_may_queue(struct request_queue *q, int rw)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        if (e->ops->elevator_may_queue_fn)
                return e->ops->elevator_may_queue_fn(q, rw);
@@ -928,7 +921,7 @@ EXPORT_SYMBOL(elv_abort_queue);
 
 void elv_completed_request(struct request_queue *q, struct request *rq)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
 
        /*
         * request is released from the driver, io must be done
@@ -944,10 +937,14 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
         * drained for flush sequence.
         */
        if (unlikely(q->ordseq)) {
-               struct request *first_rq = list_entry_rq(q->queue_head.next);
-               if (q->in_flight == 0 &&
+               struct request *next = NULL;
+
+               if (!list_empty(&q->queue_head))
+                       next = list_entry_rq(q->queue_head.next);
+
+               if (!q->in_flight &&
                    blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN &&
-                   blk_ordered_req_seq(first_rq) > QUEUE_ORDSEQ_DRAIN) {
+                   (!next || blk_ordered_req_seq(next) > QUEUE_ORDSEQ_DRAIN)) {
                        blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0);
                        blk_start_queueing(q);
                }
@@ -959,13 +956,14 @@ void elv_completed_request(struct request_queue *q, struct request *rq)
 static ssize_t
 elv_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
 {
-       elevator_t *e = container_of(kobj, elevator_t, kobj);
        struct elv_fs_entry *entry = to_elv(attr);
+       struct elevator_queue *e;
        ssize_t error;
 
        if (!entry->show)
                return -EIO;
 
+       e = container_of(kobj, struct elevator_queue, kobj);
        mutex_lock(&e->sysfs_lock);
        error = e->ops ? entry->show(e, page) : -ENOENT;
        mutex_unlock(&e->sysfs_lock);
@@ -976,13 +974,14 @@ static ssize_t
 elv_attr_store(struct kobject *kobj, struct attribute *attr,
               const char *page, size_t length)
 {
-       elevator_t *e = container_of(kobj, elevator_t, kobj);
        struct elv_fs_entry *entry = to_elv(attr);
+       struct elevator_queue *e;
        ssize_t error;
 
        if (!entry->store)
                return -EIO;
 
+       e = container_of(kobj, struct elevator_queue, kobj);
        mutex_lock(&e->sysfs_lock);
        error = e->ops ? entry->store(e, page, length) : -ENOENT;
        mutex_unlock(&e->sysfs_lock);
@@ -1001,7 +1000,7 @@ static struct kobj_type elv_ktype = {
 
 int elv_register_queue(struct request_queue *q)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
        int error;
 
        error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
@@ -1019,7 +1018,7 @@ int elv_register_queue(struct request_queue *q)
        return error;
 }
 
-static void __elv_unregister_queue(elevator_t *e)
+static void __elv_unregister_queue(struct elevator_queue *e)
 {
        kobject_uevent(&e->kobj, KOBJ_REMOVE);
        kobject_del(&e->kobj);
@@ -1082,7 +1081,7 @@ EXPORT_SYMBOL_GPL(elv_unregister);
  */
 static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 {
-       elevator_t *old_elevator, *e;
+       struct elevator_queue *old_elevator, *e;
        void *data;
 
        /*
@@ -1188,7 +1187,7 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 
 ssize_t elv_iosched_show(struct request_queue *q, char *name)
 {
-       elevator_t *e = q->elevator;
+       struct elevator_queue *e = q->elevator;
        struct elevator_type *elv = e->elevator_type;
        struct elevator_type *__e;
        int len = 0;
index 2f7feda61e35fc3cfd8dc74264300baeeaa56826..d84a7df1e2a094e663f7e1683bb941f1c3562e2d 100644 (file)
@@ -181,6 +181,12 @@ void disk_part_iter_exit(struct disk_part_iter *piter)
 }
 EXPORT_SYMBOL_GPL(disk_part_iter_exit);
 
+static inline int sector_in_part(struct hd_struct *part, sector_t sector)
+{
+       return part->start_sect <= sector &&
+               sector < part->start_sect + part->nr_sects;
+}
+
 /**
  * disk_map_sector_rcu - map sector to partition
  * @disk: gendisk of interest
@@ -199,16 +205,22 @@ EXPORT_SYMBOL_GPL(disk_part_iter_exit);
 struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
 {
        struct disk_part_tbl *ptbl;
+       struct hd_struct *part;
        int i;
 
        ptbl = rcu_dereference(disk->part_tbl);
 
+       part = rcu_dereference(ptbl->last_lookup);
+       if (part && sector_in_part(part, sector))
+               return part;
+
        for (i = 1; i < ptbl->len; i++) {
-               struct hd_struct *part = rcu_dereference(ptbl->part[i]);
+               part = rcu_dereference(ptbl->part[i]);
 
-               if (part && part->start_sect <= sector &&
-                   sector < part->start_sect + part->nr_sects)
+               if (part && sector_in_part(part, sector)) {
+                       rcu_assign_pointer(ptbl->last_lookup, part);
                        return part;
+               }
        }
        return &disk->part0;
 }
@@ -888,8 +900,11 @@ static void disk_replace_part_tbl(struct gendisk *disk,
        struct disk_part_tbl *old_ptbl = disk->part_tbl;
 
        rcu_assign_pointer(disk->part_tbl, new_ptbl);
-       if (old_ptbl)
+
+       if (old_ptbl) {
+               rcu_assign_pointer(old_ptbl->last_lookup, NULL);
                call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb);
+       }
 }
 
 /**
index d03985b04d6768bd0966c3c75f27b6a1336ede1b..0f22e629b13c8e93bf46401c0913605b5d2cbfba 100644 (file)
@@ -323,9 +323,7 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                bdi = blk_get_backing_dev_info(bdev);
                if (bdi == NULL)
                        return -ENOTTY;
-               lock_kernel();
                bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
-               unlock_kernel();
                return 0;
        case BLKBSZSET:
                /* set the logical block size */
index c23e029696508dde4161e1359acd882a6dc8a6de..3a0d369d08c7488f8f475091ef3ee6b5dfe46211 100644 (file)
@@ -76,7 +76,7 @@ static void *noop_init_queue(struct request_queue *q)
        return nd;
 }
 
-static void noop_exit_queue(elevator_t *e)
+static void noop_exit_queue(struct elevator_queue *e)
 {
        struct noop_data *nd = e->elevator_data;
 
index d0bb92cbefb9d698fc4756ec9041aeb2f5794005..ee9c67d7e1bea2015bc5d8a86287d001e33f20d1 100644 (file)
@@ -60,7 +60,7 @@ static int scsi_get_bus(struct request_queue *q, int __user *p)
 
 static int sg_get_timeout(struct request_queue *q)
 {
-       return q->sg_timeout / (HZ / USER_HZ);
+       return jiffies_to_clock_t(q->sg_timeout);
 }
 
 static int sg_set_timeout(struct request_queue *q, int __user *p)
@@ -68,7 +68,7 @@ static int sg_set_timeout(struct request_queue *q, int __user *p)
        int timeout, err = get_user(timeout, p);
 
        if (!err)
-               q->sg_timeout = timeout * (HZ / USER_HZ);
+               q->sg_timeout = clock_t_to_jiffies(timeout);
 
        return err;
 }
index a67b8e7c712dce78b371a5b5d0d1b39c33cb9e47..656448c7fef9df9965091d0d41c75d5db5778086 100644 (file)
@@ -1119,14 +1119,14 @@ static void ahci_start_port(struct ata_port *ap)
 
        /* turn on LEDs */
        if (ap->flags & ATA_FLAG_EM) {
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        emp = &pp->em_priv[link->pmp];
                        ahci_transmit_led_message(ap, emp->led_state, 4);
                }
        }
 
        if (ap->flags & ATA_FLAG_SW_ACTIVITY)
-               ata_port_for_each_link(link, ap)
+               ata_for_each_link(link, ap, EDGE)
                        ahci_init_sw_activity(link);
 
 }
@@ -1361,7 +1361,7 @@ static ssize_t ahci_led_show(struct ata_port *ap, char *buf)
        struct ahci_em_priv *emp;
        int rc = 0;
 
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                emp = &pp->em_priv[link->pmp];
                rc += sprintf(buf, "%lx\n", emp->led_state);
        }
@@ -1941,7 +1941,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        u32 serror;
 
        /* determine active link */
-       ata_port_for_each_link(link, ap)
+       ata_for_each_link(link, ap, EDGE)
                if (ata_link_active(link))
                        break;
        if (!link)
index 5c33767e66de8e25493fe37343c5fe433c2971b7..dc48a6398abe145432939e742718852fb7b24adb 100644 (file)
@@ -57,10 +57,7 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
        if (pdev->vendor == PCI_VENDOR_ID_CENATEK)
                dma_enabled = 0xFF;
 
-       ata_link_for_each_dev(dev, link) {
-               if (!ata_dev_enabled(dev))
-                       continue;
-
+       ata_for_each_dev(dev, link, ENABLED) {
                /* We don't really care */
                dev->pio_mode = XFER_PIO_0;
                dev->dma_mode = XFER_MW_DMA_0;
index c11936e13dd3ccd39952b35b242e42dd5e0d1078..5fdf1678d0ccc716c4fc73ec5d8b97328cdb5253 100644 (file)
@@ -1072,20 +1072,13 @@ static int piix_broken_suspend(void)
         * matching is necessary because dmi_system_id.matches is
         * limited to four entries.
         */
-       if (dmi_get_system_info(DMI_SYS_VENDOR) &&
-           dmi_get_system_info(DMI_PRODUCT_NAME) &&
-           dmi_get_system_info(DMI_PRODUCT_VERSION) &&
-           dmi_get_system_info(DMI_PRODUCT_SERIAL) &&
-           dmi_get_system_info(DMI_BOARD_VENDOR) &&
-           dmi_get_system_info(DMI_BOARD_NAME) &&
-           dmi_get_system_info(DMI_BOARD_VERSION) &&
-           !strcmp(dmi_get_system_info(DMI_SYS_VENDOR), "TOSHIBA") &&
-           !strcmp(dmi_get_system_info(DMI_PRODUCT_NAME), "000000") &&
-           !strcmp(dmi_get_system_info(DMI_PRODUCT_VERSION), "000000") &&
-           !strcmp(dmi_get_system_info(DMI_PRODUCT_SERIAL), "000000") &&
-           !strcmp(dmi_get_system_info(DMI_BOARD_VENDOR), "TOSHIBA") &&
-           !strcmp(dmi_get_system_info(DMI_BOARD_NAME), "Portable PC") &&
-           !strcmp(dmi_get_system_info(DMI_BOARD_VERSION), "Version A0"))
+       if (dmi_match(DMI_SYS_VENDOR, "TOSHIBA") &&
+           dmi_match(DMI_PRODUCT_NAME, "000000") &&
+           dmi_match(DMI_PRODUCT_VERSION, "000000") &&
+           dmi_match(DMI_PRODUCT_SERIAL, "000000") &&
+           dmi_match(DMI_BOARD_VENDOR, "TOSHIBA") &&
+           dmi_match(DMI_BOARD_NAME, "Portable PC") &&
+           dmi_match(DMI_BOARD_VERSION, "Version A0"))
                return 1;
 
        return 0;
index c012307d0ba6a726f7a0c9b30eac55f698da5b0b..ef02e488d468880a6af3dc624fbf854685dc730e 100644 (file)
@@ -89,7 +89,7 @@ void ata_acpi_associate_sata_port(struct ata_port *ap)
 
                ap->link.device->acpi_handle = NULL;
 
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
 
                        link->device->acpi_handle =
@@ -129,8 +129,8 @@ static void ata_acpi_detach_device(struct ata_port *ap, struct ata_device *dev)
                struct ata_link *tlink;
                struct ata_device *tdev;
 
-               ata_port_for_each_link(tlink, ap)
-                       ata_link_for_each_dev(tdev, tlink)
+               ata_for_each_link(tlink, ap, EDGE)
+                       ata_for_each_dev(tdev, tlink, ALL)
                                tdev->flags |= ATA_DFLAG_DETACH;
        }
 
@@ -588,12 +588,9 @@ int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm)
 {
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, &ap->link) {
+       ata_for_each_dev(dev, &ap->link, ENABLED) {
                unsigned long xfer_mask, udma_mask;
 
-               if (!ata_dev_enabled(dev))
-                       continue;
-
                xfer_mask = ata_acpi_gtm_xfermask(dev, gtm);
                ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask);
 
@@ -893,7 +890,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
                 * use values set by _STM.  Cache _GTF result and
                 * schedule _GTF.
                 */
-               ata_link_for_each_dev(dev, &ap->link) {
+               ata_for_each_dev(dev, &ap->link, ALL) {
                        ata_acpi_clear_gtf(dev);
                        if (ata_dev_enabled(dev) &&
                            ata_dev_get_GTF(dev, NULL) >= 0)
@@ -904,7 +901,7 @@ void ata_acpi_on_resume(struct ata_port *ap)
                 * there's no reason to evaluate IDE _GTF early
                 * without _STM.  Clear cache and schedule _GTF.
                 */
-               ata_link_for_each_dev(dev, &ap->link) {
+               ata_for_each_dev(dev, &ap->link, ALL) {
                        ata_acpi_clear_gtf(dev);
                        if (ata_dev_enabled(dev))
                                dev->flags |= ATA_DFLAG_ACPI_PENDING;
@@ -932,8 +929,8 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
        if (state.event == PM_EVENT_ON)
                acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0);
 
-       ata_link_for_each_dev(dev, &ap->link) {
-               if (dev->acpi_handle && ata_dev_enabled(dev))
+       ata_for_each_dev(dev, &ap->link, ENABLED) {
+               if (dev->acpi_handle)
                        acpi_bus_set_power(dev->acpi_handle,
                                state.event == PM_EVENT_ON ?
                                        ACPI_STATE_D0 : ACPI_STATE_D3);
index bc6695e3c8482927e5b6de7ae4017c9884bea4a8..fecca4223f8ee92adfe4e4824ef6114def00baa2 100644 (file)
@@ -163,42 +163,118 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
 
-/*
- * Iterator helpers.  Don't use directly.
+/**
+ *     ata_link_next - link iteration helper
+ *     @link: the previous link, NULL to start
+ *     @ap: ATA port containing links to iterate
+ *     @mode: iteration mode, one of ATA_LITER_*
+ *
+ *     LOCKING:
+ *     Host lock or EH context.
  *
- * LOCKING:
- * Host lock or EH context.
+ *     RETURNS:
+ *     Pointer to the next link.
  */
-struct ata_link *__ata_port_next_link(struct ata_port *ap,
-                                     struct ata_link *link, bool dev_only)
+struct ata_link *ata_link_next(struct ata_link *link, struct ata_port *ap,
+                              enum ata_link_iter_mode mode)
 {
+       BUG_ON(mode != ATA_LITER_EDGE &&
+              mode != ATA_LITER_PMP_FIRST && mode != ATA_LITER_HOST_FIRST);
+
        /* NULL link indicates start of iteration */
-       if (!link) {
-               if (dev_only && sata_pmp_attached(ap))
-                       return ap->pmp_link;
-               return &ap->link;
-       }
+       if (!link)
+               switch (mode) {
+               case ATA_LITER_EDGE:
+               case ATA_LITER_PMP_FIRST:
+                       if (sata_pmp_attached(ap))
+                               return ap->pmp_link;
+                       /* fall through */
+               case ATA_LITER_HOST_FIRST:
+                       return &ap->link;
+               }
 
-       /* we just iterated over the host master link, what's next? */
-       if (link == &ap->link) {
-               if (!sata_pmp_attached(ap)) {
-                       if (unlikely(ap->slave_link) && !dev_only)
+       /* we just iterated over the host link, what's next? */
+       if (link == &ap->link)
+               switch (mode) {
+               case ATA_LITER_HOST_FIRST:
+                       if (sata_pmp_attached(ap))
+                               return ap->pmp_link;
+                       /* fall through */
+               case ATA_LITER_PMP_FIRST:
+                       if (unlikely(ap->slave_link))
                                return ap->slave_link;
+                       /* fall through */
+               case ATA_LITER_EDGE:
                        return NULL;
                }
-               return ap->pmp_link;
-       }
 
        /* slave_link excludes PMP */
        if (unlikely(link == ap->slave_link))
                return NULL;
 
-       /* iterate to the next PMP link */
+       /* we were over a PMP link */
        if (++link < ap->pmp_link + ap->nr_pmp_links)
                return link;
+
+       if (mode == ATA_LITER_PMP_FIRST)
+               return &ap->link;
+
        return NULL;
 }
 
+/**
+ *     ata_dev_next - device iteration helper
+ *     @dev: the previous device, NULL to start
+ *     @link: ATA link containing devices to iterate
+ *     @mode: iteration mode, one of ATA_DITER_*
+ *
+ *     LOCKING:
+ *     Host lock or EH context.
+ *
+ *     RETURNS:
+ *     Pointer to the next device.
+ */
+struct ata_device *ata_dev_next(struct ata_device *dev, struct ata_link *link,
+                               enum ata_dev_iter_mode mode)
+{
+       BUG_ON(mode != ATA_DITER_ENABLED && mode != ATA_DITER_ENABLED_REVERSE &&
+              mode != ATA_DITER_ALL && mode != ATA_DITER_ALL_REVERSE);
+
+       /* NULL dev indicates start of iteration */
+       if (!dev)
+               switch (mode) {
+               case ATA_DITER_ENABLED:
+               case ATA_DITER_ALL:
+                       dev = link->device;
+                       goto check;
+               case ATA_DITER_ENABLED_REVERSE:
+               case ATA_DITER_ALL_REVERSE:
+                       dev = link->device + ata_link_max_devices(link) - 1;
+                       goto check;
+               }
+
+ next:
+       /* move to the next one */
+       switch (mode) {
+       case ATA_DITER_ENABLED:
+       case ATA_DITER_ALL:
+               if (++dev < link->device + ata_link_max_devices(link))
+                       goto check;
+               return NULL;
+       case ATA_DITER_ENABLED_REVERSE:
+       case ATA_DITER_ALL_REVERSE:
+               if (--dev >= link->device)
+                       goto check;
+               return NULL;
+       }
+
+ check:
+       if ((mode == ATA_DITER_ENABLED || mode == ATA_DITER_ENABLED_REVERSE) &&
+           !ata_dev_enabled(dev))
+               goto next;
+       return dev;
+}
+
 /**
  *     ata_dev_phys_link - find physical link for a device
  *     @dev: ATA device to look up physical link for
@@ -1107,8 +1183,8 @@ static void ata_lpm_enable(struct ata_host *host)
 
        for (i = 0; i < host->n_ports; i++) {
                ap = host->ports[i];
-               ata_port_for_each_link(link, ap) {
-                       ata_link_for_each_dev(dev, link)
+               ata_for_each_link(link, ap, EDGE) {
+                       ata_for_each_dev(dev, link, ALL)
                                ata_dev_disable_pm(dev);
                }
        }
@@ -2594,11 +2670,11 @@ int ata_bus_probe(struct ata_port *ap)
 
        ata_port_probe(ap);
 
-       ata_link_for_each_dev(dev, &ap->link)
+       ata_for_each_dev(dev, &ap->link, ALL)
                tries[dev->devno] = ATA_PROBE_MAX_TRIES;
 
  retry:
-       ata_link_for_each_dev(dev, &ap->link) {
+       ata_for_each_dev(dev, &ap->link, ALL) {
                /* If we issue an SRST then an ATA drive (not ATAPI)
                 * may change configuration and be in PIO0 timing. If
                 * we do a hard reset (or are coming from power on)
@@ -2620,7 +2696,7 @@ int ata_bus_probe(struct ata_port *ap)
        /* reset and determine device classes */
        ap->ops->phy_reset(ap);
 
-       ata_link_for_each_dev(dev, &ap->link) {
+       ata_for_each_dev(dev, &ap->link, ALL) {
                if (!(ap->flags & ATA_FLAG_DISABLED) &&
                    dev->class != ATA_DEV_UNKNOWN)
                        classes[dev->devno] = dev->class;
@@ -2636,7 +2712,7 @@ int ata_bus_probe(struct ata_port *ap)
           specific sequence bass-ackwards so that PDIAG- is released by
           the slave device */
 
-       ata_link_for_each_dev_reverse(dev, &ap->link) {
+       ata_for_each_dev(dev, &ap->link, ALL_REVERSE) {
                if (tries[dev->devno])
                        dev->class = classes[dev->devno];
 
@@ -2653,24 +2729,19 @@ int ata_bus_probe(struct ata_port *ap)
        if (ap->ops->cable_detect)
                ap->cbl = ap->ops->cable_detect(ap);
 
-       /* We may have SATA bridge glue hiding here irrespective of the
-          reported cable types and sensed types */
-       ata_link_for_each_dev(dev, &ap->link) {
-               if (!ata_dev_enabled(dev))
-                       continue;
-               /* SATA drives indicate we have a bridge. We don't know which
-                  end of the link the bridge is which is a problem */
+       /* We may have SATA bridge glue hiding here irrespective of
+        * the reported cable types and sensed types.  When SATA
+        * drives indicate we have a bridge, we don't know which end
+        * of the link the bridge is which is a problem.
+        */
+       ata_for_each_dev(dev, &ap->link, ENABLED)
                if (ata_id_is_sata(dev->id))
                        ap->cbl = ATA_CBL_SATA;
-       }
 
        /* After the identify sequence we can now set up the devices. We do
           this in the normal order so that the user doesn't get confused */
 
-       ata_link_for_each_dev(dev, &ap->link) {
-               if (!ata_dev_enabled(dev))
-                       continue;
-
+       ata_for_each_dev(dev, &ap->link, ENABLED) {
                ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
                rc = ata_dev_configure(dev);
                ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
@@ -2683,9 +2754,8 @@ int ata_bus_probe(struct ata_port *ap)
        if (rc)
                goto fail;
 
-       ata_link_for_each_dev(dev, &ap->link)
-               if (ata_dev_enabled(dev))
-                       return 0;
+       ata_for_each_dev(dev, &ap->link, ENABLED)
+               return 0;
 
        /* no device present, disable port */
        ata_port_disable(ap);
@@ -3331,13 +3401,10 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        int rc = 0, used_dma = 0, found = 0;
 
        /* step 1: calculate xfer_mask */
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ENABLED) {
                unsigned long pio_mask, dma_mask;
                unsigned int mode_mask;
 
-               if (!ata_dev_enabled(dev))
-                       continue;
-
                mode_mask = ATA_DMA_MASK_ATA;
                if (dev->class == ATA_DEV_ATAPI)
                        mode_mask = ATA_DMA_MASK_ATAPI;
@@ -3366,10 +3433,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
                goto out;
 
        /* step 2: always set host PIO timings */
-       ata_link_for_each_dev(dev, link) {
-               if (!ata_dev_enabled(dev))
-                       continue;
-
+       ata_for_each_dev(dev, link, ENABLED) {
                if (dev->pio_mode == 0xff) {
                        ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
                        rc = -EINVAL;
@@ -3383,8 +3447,8 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        }
 
        /* step 3: set host DMA timings */
-       ata_link_for_each_dev(dev, link) {
-               if (!ata_dev_enabled(dev) || !ata_dma_enabled(dev))
+       ata_for_each_dev(dev, link, ENABLED) {
+               if (!ata_dma_enabled(dev))
                        continue;
 
                dev->xfer_mode = dev->dma_mode;
@@ -3394,11 +3458,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        }
 
        /* step 4: update devices' xfer mode */
-       ata_link_for_each_dev(dev, link) {
-               /* don't update suspended devices' xfer mode */
-               if (!ata_dev_enabled(dev))
-                       continue;
-
+       ata_for_each_dev(dev, link, ENABLED) {
                rc = ata_dev_set_mode(dev);
                if (rc)
                        goto out;
@@ -4048,6 +4108,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Maxtor 7V300F0",     "VA111630",     ATA_HORKAGE_NONCQ },
        { "ST380817AS",         "3.42",         ATA_HORKAGE_NONCQ },
        { "ST3160023AS",        "3.42",         ATA_HORKAGE_NONCQ },
+       { "OCZ CORE_SSD",       "02.10104",     ATA_HORKAGE_NONCQ },
 
        /* Seagate NCQ + FLUSH CACHE firmware bug */
        { "ST31500341AS",       "SD15",         ATA_HORKAGE_NONCQ |
@@ -4263,9 +4324,9 @@ static int cable_is_40wire(struct ata_port *ap)
         * - if you have a non detect capable drive you don't want it
         *   to colour the choice
         */
-       ata_port_for_each_link(link, ap) {
-               ata_link_for_each_dev(dev, link) {
-                       if (ata_dev_enabled(dev) && !ata_is_40wire(dev))
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, link, ENABLED) {
+                       if (!ata_is_40wire(dev))
                                return 0;
                }
        }
@@ -4672,7 +4733,6 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
 /**
  *     ata_qc_new_init - Request an available ATA command, and initialize it
  *     @dev: Device from whom we request an available command structure
- *     @tag: command tag
  *
  *     LOCKING:
  *     None.
@@ -5218,7 +5278,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
                }
 
                ap->pflags |= ATA_PFLAG_PM_PENDING;
-               __ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, HOST_FIRST) {
                        link->eh_info.action |= action;
                        link->eh_info.flags |= ehi_flags;
                }
@@ -6047,8 +6107,6 @@ int ata_host_activate(struct ata_host *host, int irq,
 static void ata_port_detach(struct ata_port *ap)
 {
        unsigned long flags;
-       struct ata_link *link;
-       struct ata_device *dev;
 
        if (!ap->ops->error_handler)
                goto skip_eh;
@@ -6056,28 +6114,15 @@ static void ata_port_detach(struct ata_port *ap)
        /* tell EH we're leaving & flush EH */
        spin_lock_irqsave(ap->lock, flags);
        ap->pflags |= ATA_PFLAG_UNLOADING;
+       ata_port_schedule_eh(ap);
        spin_unlock_irqrestore(ap->lock, flags);
 
+       /* wait till EH commits suicide */
        ata_port_wait_eh(ap);
 
-       /* EH is now guaranteed to see UNLOADING - EH context belongs
-        * to us.  Restore SControl and disable all existing devices.
-        */
-       __ata_port_for_each_link(link, ap) {
-               sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
-               ata_link_for_each_dev(dev, link)
-                       ata_dev_disable(dev);
-       }
+       /* it better be dead now */
+       WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
 
-       /* Final freeze & EH.  All in-flight commands are aborted.  EH
-        * will be skipped and retrials will be terminated with bad
-        * target.
-        */
-       spin_lock_irqsave(ap->lock, flags);
-       ata_port_freeze(ap);    /* won't be thawed */
-       spin_unlock_irqrestore(ap->lock, flags);
-
-       ata_port_wait_eh(ap);
        cancel_rearming_delayed_work(&ap->hotplug_task);
 
  skip_eh:
@@ -6528,7 +6573,8 @@ EXPORT_SYMBOL_GPL(ata_base_port_ops);
 EXPORT_SYMBOL_GPL(sata_port_ops);
 EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 EXPORT_SYMBOL_GPL(ata_dummy_port_info);
-EXPORT_SYMBOL_GPL(__ata_port_next_link);
+EXPORT_SYMBOL_GPL(ata_link_next);
+EXPORT_SYMBOL_GPL(ata_dev_next);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_host_init);
 EXPORT_SYMBOL_GPL(ata_host_alloc);
index 32da9a93ce44ae221caa63b753c225c81b257f5d..8147a838637094cc16d0217fe8c8ac135edc9c0a 100644 (file)
@@ -422,7 +422,7 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
 
        if (!dev) {
                ehi->action &= ~action;
-               ata_link_for_each_dev(tdev, link)
+               ata_for_each_dev(tdev, link, ALL)
                        ehi->dev_action[tdev->devno] &= ~action;
        } else {
                /* doesn't make sense for port-wide EH actions */
@@ -430,7 +430,7 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
 
                /* break ehi->action into ehi->dev_action */
                if (ehi->action & action) {
-                       ata_link_for_each_dev(tdev, link)
+                       ata_for_each_dev(tdev, link, ALL)
                                ehi->dev_action[tdev->devno] |=
                                        ehi->action & action;
                        ehi->action &= ~action;
@@ -491,6 +491,31 @@ enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
        return ret;
 }
 
+static void ata_eh_unload(struct ata_port *ap)
+{
+       struct ata_link *link;
+       struct ata_device *dev;
+       unsigned long flags;
+
+       /* Restore SControl IPM and SPD for the next driver and
+        * disable attached devices.
+        */
+       ata_for_each_link(link, ap, PMP_FIRST) {
+               sata_scr_write(link, SCR_CONTROL, link->saved_scontrol & 0xff0);
+               ata_for_each_dev(dev, link, ALL)
+                       ata_dev_disable(dev);
+       }
+
+       /* freeze and set UNLOADED */
+       spin_lock_irqsave(ap->lock, flags);
+
+       ata_port_freeze(ap);                    /* won't be thawed */
+       ap->pflags &= ~ATA_PFLAG_EH_PENDING;    /* clear pending from freeze */
+       ap->pflags |= ATA_PFLAG_UNLOADED;
+
+       spin_unlock_irqrestore(ap->lock, flags);
+}
+
 /**
  *     ata_scsi_error - SCSI layer error handler callback
  *     @host: SCSI host on which error occurred
@@ -592,7 +617,7 @@ void ata_scsi_error(struct Scsi_Host *host)
                /* fetch & clear EH info */
                spin_lock_irqsave(ap->lock, flags);
 
-               __ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, HOST_FIRST) {
                        struct ata_eh_context *ehc = &link->eh_context;
                        struct ata_device *dev;
 
@@ -600,12 +625,9 @@ void ata_scsi_error(struct Scsi_Host *host)
                        link->eh_context.i = link->eh_info;
                        memset(&link->eh_info, 0, sizeof(link->eh_info));
 
-                       ata_link_for_each_dev(dev, link) {
+                       ata_for_each_dev(dev, link, ENABLED) {
                                int devno = dev->devno;
 
-                               if (!ata_dev_enabled(dev))
-                                       continue;
-
                                ehc->saved_xfer_mode[devno] = dev->xfer_mode;
                                if (ata_ncq_enabled(dev))
                                        ehc->saved_ncq_enabled |= 1 << devno;
@@ -621,8 +643,13 @@ void ata_scsi_error(struct Scsi_Host *host)
                /* invoke EH, skip if unloading or suspended */
                if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
                        ap->ops->error_handler(ap);
-               else
+               else {
+                       /* if unloading, commence suicide */
+                       if ((ap->pflags & ATA_PFLAG_UNLOADING) &&
+                           !(ap->pflags & ATA_PFLAG_UNLOADED))
+                               ata_eh_unload(ap);
                        ata_eh_finish(ap);
+               }
 
                /* process port suspend request */
                ata_eh_handle_port_suspend(ap);
@@ -644,7 +671,7 @@ void ata_scsi_error(struct Scsi_Host *host)
                }
 
                /* this run is complete, make sure EH info is clear */
-               __ata_port_for_each_link(link, ap)
+               ata_for_each_link(link, ap, HOST_FIRST)
                        memset(&link->eh_info, 0, sizeof(link->eh_info));
 
                /* Clear host_eh_scheduled while holding ap->lock such
@@ -1025,7 +1052,7 @@ int sata_async_notification(struct ata_port *ap)
                struct ata_link *link;
 
                /* check and notify ATAPI AN */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        if (!(sntf & (1 << link->pmp)))
                                continue;
 
@@ -2005,7 +2032,7 @@ void ata_eh_autopsy(struct ata_port *ap)
 {
        struct ata_link *link;
 
-       ata_port_for_each_link(link, ap)
+       ata_for_each_link(link, ap, EDGE)
                ata_eh_link_autopsy(link);
 
        /* Handle the frigging slave link.  Autopsy is done similarly
@@ -2219,7 +2246,7 @@ void ata_eh_report(struct ata_port *ap)
 {
        struct ata_link *link;
 
-       __ata_port_for_each_link(link, ap)
+       ata_for_each_link(link, ap, HOST_FIRST)
                ata_eh_link_report(link);
 }
 
@@ -2230,7 +2257,7 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
        struct ata_device *dev;
 
        if (clear_classes)
-               ata_link_for_each_dev(dev, link)
+               ata_for_each_dev(dev, link, ALL)
                        classes[dev->devno] = ATA_DEV_UNKNOWN;
 
        return reset(link, classes, deadline);
@@ -2294,7 +2321,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
 
        ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
 
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                /* If we issue an SRST then an ATA drive (not ATAPI)
                 * may change configuration and be in PIO0 timing. If
                 * we do a hard reset (or are coming from power on)
@@ -2355,7 +2382,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
                                                "port disabled. ignoring.\n");
                                ehc->i.action &= ~ATA_EH_RESET;
 
-                               ata_link_for_each_dev(dev, link)
+                               ata_for_each_dev(dev, link, ALL)
                                        classes[dev->devno] = ATA_DEV_NONE;
 
                                rc = 0;
@@ -2369,7 +2396,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
                 * bang classes and return.
                 */
                if (reset && !(ehc->i.action & ATA_EH_RESET)) {
-                       ata_link_for_each_dev(dev, link)
+                       ata_for_each_dev(dev, link, ALL)
                                classes[dev->devno] = ATA_DEV_NONE;
                        rc = 0;
                        goto out;
@@ -2454,7 +2481,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
        /*
         * Post-reset processing
         */
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                /* After the reset, the device state is PIO 0 and the
                 * controller state is undefined.  Reset also wakes up
                 * drives from sleeping mode.
@@ -2510,7 +2537,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
         * can be reliably detected and retried.
         */
        nr_unknown = 0;
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
                if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
                        classes[dev->devno] = ATA_DEV_NONE;
@@ -2619,8 +2646,8 @@ static inline void ata_eh_pull_park_action(struct ata_port *ap)
 
        spin_lock_irqsave(ap->lock, flags);
        INIT_COMPLETION(ap->park_req_pending);
-       ata_port_for_each_link(link, ap) {
-               ata_link_for_each_dev(dev, link) {
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, link, ALL) {
                        struct ata_eh_info *ehi = &link->eh_info;
 
                        link->eh_context.i.dev_action[dev->devno] |=
@@ -2675,7 +2702,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
         * be done backwards such that PDIAG- is released by the slave
         * device before the master device is identified.
         */
-       ata_link_for_each_dev_reverse(dev, link) {
+       ata_for_each_dev(dev, link, ALL_REVERSE) {
                unsigned int action = ata_eh_dev_action(dev);
                unsigned int readid_flags = 0;
 
@@ -2744,7 +2771,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
        /* Configure new devices forward such that user doesn't see
         * device detection messages backwards.
         */
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                if (!(new_mask & (1 << dev->devno)) ||
                    dev->class == ATA_DEV_PMP)
                        continue;
@@ -2793,10 +2820,7 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
        int rc;
 
        /* if data transfer is verified, clear DUBIOUS_XFER on ering top */
-       ata_link_for_each_dev(dev, link) {
-               if (!ata_dev_enabled(dev))
-                       continue;
-
+       ata_for_each_dev(dev, link, ENABLED) {
                if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) {
                        struct ata_ering_entry *ent;
 
@@ -2813,14 +2837,11 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
                rc = ata_do_set_mode(link, r_failed_dev);
 
        /* if transfer mode has changed, set DUBIOUS_XFER on device */
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ENABLED) {
                struct ata_eh_context *ehc = &link->eh_context;
                u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno];
                u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno));
 
-               if (!ata_dev_enabled(dev))
-                       continue;
-
                if (dev->xfer_mode != saved_xfer_mode ||
                    ata_ncq_enabled(dev) != saved_ncq)
                        dev->flags |= ATA_DFLAG_DUBIOUS_XFER;
@@ -2881,9 +2902,8 @@ static int ata_link_nr_enabled(struct ata_link *link)
        struct ata_device *dev;
        int cnt = 0;
 
-       ata_link_for_each_dev(dev, link)
-               if (ata_dev_enabled(dev))
-                       cnt++;
+       ata_for_each_dev(dev, link, ENABLED)
+               cnt++;
        return cnt;
 }
 
@@ -2892,7 +2912,7 @@ static int ata_link_nr_vacant(struct ata_link *link)
        struct ata_device *dev;
        int cnt = 0;
 
-       ata_link_for_each_dev(dev, link)
+       ata_for_each_dev(dev, link, ALL)
                if (dev->class == ATA_DEV_UNKNOWN)
                        cnt++;
        return cnt;
@@ -2918,7 +2938,7 @@ static int ata_eh_skip_recovery(struct ata_link *link)
                return 0;
 
        /* skip if class codes for all vacant slots are ATA_DEV_NONE */
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                if (dev->class == ATA_DEV_UNKNOWN &&
                    ehc->classes[dev->devno] != ATA_DEV_NONE)
                        return 0;
@@ -3026,7 +3046,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        DPRINTK("ENTER\n");
 
        /* prep for recovery */
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                struct ata_eh_context *ehc = &link->eh_context;
 
                /* re-enable link? */
@@ -3038,7 +3058,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                        ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
                }
 
-               ata_link_for_each_dev(dev, link) {
+               ata_for_each_dev(dev, link, ALL) {
                        if (link->flags & ATA_LFLAG_NO_RETRY)
                                ehc->tries[dev->devno] = 1;
                        else
@@ -3068,19 +3088,19 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                goto out;
 
        /* prep for EH */
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                struct ata_eh_context *ehc = &link->eh_context;
 
                /* skip EH if possible. */
                if (ata_eh_skip_recovery(link))
                        ehc->i.action = 0;
 
-               ata_link_for_each_dev(dev, link)
+               ata_for_each_dev(dev, link, ALL)
                        ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
        }
 
        /* reset */
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                struct ata_eh_context *ehc = &link->eh_context;
 
                if (!(ehc->i.action & ATA_EH_RESET))
@@ -3105,8 +3125,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                ata_eh_pull_park_action(ap);
 
                deadline = jiffies;
-               ata_port_for_each_link(link, ap) {
-                       ata_link_for_each_dev(dev, link) {
+               ata_for_each_link(link, ap, EDGE) {
+                       ata_for_each_dev(dev, link, ALL) {
                                struct ata_eh_context *ehc = &link->eh_context;
                                unsigned long tmp;
 
@@ -3134,8 +3154,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                deadline = wait_for_completion_timeout(&ap->park_req_pending,
                                                       deadline - now);
        } while (deadline);
-       ata_port_for_each_link(link, ap) {
-               ata_link_for_each_dev(dev, link) {
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, link, ALL) {
                        if (!(link->eh_context.unloaded_mask &
                              (1 << dev->devno)))
                                continue;
@@ -3146,7 +3166,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        }
 
        /* the rest */
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                struct ata_eh_context *ehc = &link->eh_context;
 
                /* revalidate existing devices and attach new ones */
@@ -3172,7 +3192,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                 * disrupting the current users of the device.
                 */
                if (ehc->i.flags & ATA_EHI_DID_RESET) {
-                       ata_link_for_each_dev(dev, link) {
+                       ata_for_each_dev(dev, link, ALL) {
                                if (dev->class != ATA_DEV_ATAPI)
                                        continue;
                                rc = atapi_eh_clear_ua(dev);
@@ -3183,7 +3203,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 
                /* configure link power saving */
                if (ehc->i.action & ATA_EH_LPM)
-                       ata_link_for_each_dev(dev, link)
+                       ata_for_each_dev(dev, link, ALL)
                                ata_dev_enable_pm(dev, ap->pm_policy);
 
                /* this link is okay now */
@@ -3288,7 +3308,7 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
        rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
                            NULL);
        if (rc) {
-               ata_link_for_each_dev(dev, &ap->link)
+               ata_for_each_dev(dev, &ap->link, ALL)
                        ata_dev_disable(dev);
        }
 
index b65db309c181f02f76431a4d7b3e24d5e63b3388..98ca07a2db87e22a49895e8d1bfd48c332875f49 100644 (file)
@@ -321,7 +321,7 @@ static void sata_pmp_quirks(struct ata_port *ap)
 
        if (vendor == 0x1095 && devid == 0x3726) {
                /* sil3726 quirks */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        /* Class code report is unreliable and SRST
                         * times out under certain configurations.
                         */
@@ -336,7 +336,7 @@ static void sata_pmp_quirks(struct ata_port *ap)
                }
        } else if (vendor == 0x1095 && devid == 0x4723) {
                /* sil4723 quirks */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        /* class code report is unreliable */
                        if (link->pmp < 2)
                                link->flags |= ATA_LFLAG_ASSUME_ATA;
@@ -348,7 +348,7 @@ static void sata_pmp_quirks(struct ata_port *ap)
                }
        } else if (vendor == 0x1095 && devid == 0x4726) {
                /* sil4726 quirks */
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        /* Class code report is unreliable and SRST
                         * times out under certain configurations.
                         * Config device can be at port 0 or 5 and
@@ -450,7 +450,7 @@ int sata_pmp_attach(struct ata_device *dev)
        if (ap->ops->pmp_attach)
                ap->ops->pmp_attach(ap);
 
-       ata_port_for_each_link(tlink, ap)
+       ata_for_each_link(tlink, ap, EDGE)
                sata_link_init_spd(tlink);
 
        ata_acpi_associate_sata_port(ap);
@@ -487,7 +487,7 @@ static void sata_pmp_detach(struct ata_device *dev)
        if (ap->ops->pmp_detach)
                ap->ops->pmp_detach(ap);
 
-       ata_port_for_each_link(tlink, ap)
+       ata_for_each_link(tlink, ap, EDGE)
                ata_eh_detach_dev(tlink->device);
 
        spin_lock_irqsave(ap->lock, flags);
@@ -700,7 +700,7 @@ static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
                }
 
                /* PMP is reset, SErrors cannot be trusted, scan all */
-               ata_port_for_each_link(tlink, ap) {
+               ata_for_each_link(tlink, ap, EDGE) {
                        struct ata_eh_context *ehc = &tlink->eh_context;
 
                        ehc->i.probe_mask |= ATA_ALL_DEVICES;
@@ -768,7 +768,7 @@ static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
 
        spin_lock_irqsave(ap->lock, flags);
 
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                if (!(link->flags & ATA_LFLAG_DISABLED))
                        continue;
 
@@ -852,7 +852,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        int cnt, rc;
 
        pmp_tries = ATA_EH_PMP_TRIES;
-       ata_port_for_each_link(link, ap)
+       ata_for_each_link(link, ap, EDGE)
                link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
 
  retry:
@@ -861,7 +861,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
                rc = ata_eh_recover(ap, ops->prereset, ops->softreset,
                                    ops->hardreset, ops->postreset, NULL);
                if (rc) {
-                       ata_link_for_each_dev(dev, &ap->link)
+                       ata_for_each_dev(dev, &ap->link, ALL)
                                ata_dev_disable(dev);
                        return rc;
                }
@@ -870,7 +870,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
                        return 0;
 
                /* new PMP online */
-               ata_port_for_each_link(link, ap)
+               ata_for_each_link(link, ap, EDGE)
                        link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
 
                /* fall through */
@@ -942,7 +942,7 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        }
 
        cnt = 0;
-       ata_port_for_each_link(link, ap) {
+       ata_for_each_link(link, ap, EDGE) {
                if (!(gscr_error & (1 << link->pmp)))
                        continue;
 
index b88e443027c43aef121245899350c644bd1f447e..4040d8b532165b791fef71902b44a5905e21303a 100644 (file)
@@ -3229,12 +3229,12 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
                return;
 
  repeat:
-       ata_port_for_each_link(link, ap) {
-               ata_link_for_each_dev(dev, link) {
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, link, ENABLED) {
                        struct scsi_device *sdev;
                        int channel = 0, id = 0;
 
-                       if (!ata_dev_enabled(dev) || dev->sdev)
+                       if (dev->sdev)
                                continue;
 
                        if (ata_is_host_link(link))
@@ -3255,9 +3255,9 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
         * failure occurred, scan would have failed silently.  Check
         * whether all devices are attached.
         */
-       ata_port_for_each_link(link, ap) {
-               ata_link_for_each_dev(dev, link) {
-                       if (ata_dev_enabled(dev) && !dev->sdev)
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, link, ENABLED) {
+                       if (!dev->sdev)
                                goto exit_loop;
                }
        }
@@ -3381,7 +3381,7 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)
        struct ata_port *ap = link->ap;
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                unsigned long flags;
 
                if (!(dev->flags & ATA_DFLAG_DETACHED))
@@ -3496,7 +3496,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
        if (devno == SCAN_WILD_CARD) {
                struct ata_link *link;
 
-               ata_port_for_each_link(link, ap) {
+               ata_for_each_link(link, ap, EDGE) {
                        struct ata_eh_info *ehi = &link->eh_info;
                        ehi->probe_mask |= ATA_ALL_DEVICES;
                        ehi->action |= ATA_EH_RESET;
@@ -3544,11 +3544,11 @@ void ata_scsi_dev_rescan(struct work_struct *work)
 
        spin_lock_irqsave(ap->lock, flags);
 
-       ata_port_for_each_link(link, ap) {
-               ata_link_for_each_dev(dev, link) {
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, link, ENABLED) {
                        struct scsi_device *sdev = dev->sdev;
 
-                       if (!ata_dev_enabled(dev) || !sdev)
+                       if (!sdev)
                                continue;
                        if (scsi_device_get(sdev))
                                continue;
index 1266924c11f97f7771f4ee99d232df8fbf59aae7..1050fed96b2bfdc1f1e948e86a874eb03d6c9165 100644 (file)
@@ -356,7 +356,6 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     bfin_set_dmamode - Initialize host controller PATA DMA timings
  *     @ap: Port whose timings we are configuring
  *     @adev: um
- *     @udma: udma mode, 0 - 6
  *
  *     Set UDMA mode for device.
  *
index 860ede526282d5dc1939c132f0cb44429345443d..f828a29d77567e27ff539845e3e51745344007dd 100644 (file)
@@ -465,24 +465,22 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus
 {
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
-                       /* We don't really care */
-                       dev->pio_mode = XFER_PIO_0;
-                       dev->dma_mode = XFER_MW_DMA_0;
-                       /* We do need the right mode information for DMA or PIO
-                          and this comes from the current configuration flags */
-                       if (ata_id_has_dma(dev->id)) {
-                               ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
-                               dev->xfer_mode = XFER_MW_DMA_0;
-                               dev->xfer_shift = ATA_SHIFT_MWDMA;
-                               dev->flags &= ~ATA_DFLAG_PIO;
-                       } else {
-                               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
-                               dev->xfer_mode = XFER_PIO_0;
-                               dev->xfer_shift = ATA_SHIFT_PIO;
-                               dev->flags |= ATA_DFLAG_PIO;
-                       }
+       ata_for_each_dev(dev, link, ENABLED) {
+               /* We don't really care */
+               dev->pio_mode = XFER_PIO_0;
+               dev->dma_mode = XFER_MW_DMA_0;
+               /* We do need the right mode information for DMA or PIO
+                  and this comes from the current configuration flags */
+               if (ata_id_has_dma(dev->id)) {
+                       ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
+                       dev->xfer_mode = XFER_MW_DMA_0;
+                       dev->xfer_shift = ATA_SHIFT_MWDMA;
+                       dev->flags &= ~ATA_DFLAG_PIO;
+               } else {
+                       ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+                       dev->xfer_mode = XFER_PIO_0;
+                       dev->xfer_shift = ATA_SHIFT_PIO;
+                       dev->flags |= ATA_DFLAG_PIO;
                }
        }
        return 0;
index 2014253f6c8842981b6d6b2f34ca8a52144ccbe4..b173c157ab007ac7dc5070f13e4d9d96ed8ade4c 100644 (file)
@@ -30,14 +30,12 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
 {
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
-                       ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
-                       dev->pio_mode = XFER_PIO_0;
-                       dev->xfer_mode = XFER_PIO_0;
-                       dev->xfer_shift = ATA_SHIFT_PIO;
-                       dev->flags |= ATA_DFLAG_PIO;
-               }
+       ata_for_each_dev(dev, link, ENABLED) {
+               ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
+               dev->pio_mode = XFER_PIO_0;
+               dev->xfer_mode = XFER_PIO_0;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               dev->flags |= ATA_DFLAG_PIO;
        }
        return 0;
 }
index 930c2208640b950740f53f89cbd25799eebda645..6c1d778b63a9cd58a06dc4772fcfc15f8350d428 100644 (file)
@@ -194,15 +194,12 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
 {
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
-                       ata_dev_printk(dev, KERN_INFO,
-                                               "configured for PIO\n");
-                       dev->pio_mode = XFER_PIO_0;
-                       dev->xfer_mode = XFER_PIO_0;
-                       dev->xfer_shift = ATA_SHIFT_PIO;
-                       dev->flags |= ATA_DFLAG_PIO;
-               }
+       ata_for_each_dev(dev, link, ENABLED) {
+               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+               dev->pio_mode = XFER_PIO_0;
+               dev->xfer_mode = XFER_PIO_0;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               dev->flags |= ATA_DFLAG_PIO;
        }
        return 0;
 }
@@ -641,7 +638,6 @@ static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     qdi6580dp_set_piomode           -       PIO setup for dual channel
  *     @ap: Port
  *     @adev: Device
- *     @irq: interrupt line
  *
  *     In dual channel mode the 6580 has one clock per channel and we have
  *     to software clockswitch in qc_issue.
@@ -1028,7 +1024,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)
        /* Nothing found means we drop the port as its probably not there */
 
        ret = -ENODEV;
-       ata_link_for_each_dev(dev, &ap->link) {
+       ata_for_each_dev(dev, &ap->link, ALL) {
                if (!ata_dev_absent(dev)) {
                        legacy_host[probe->slot] = host;
                        ld->platform_dev = pdev;
index c0dbc46a348e4bcad76cbbb6ae607573b6d4ed79..2c1a91c40c1ae2eb65e3d3cdb47e555ac38b5184 100644 (file)
@@ -116,7 +116,6 @@ static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
  *     oldpiix_set_dmamode - Initialize host controller PATA DMA timings
  *     @ap: Port whose timings we are configuring
  *     @adev: Device to program
- *     @isich: True if the device is an ICH and has IOCFG registers
  *
  *     Set MWDMA mode for device, in host controller PCI config space.
  *
index 0e1c2c1134d34b10dfc50d85d27c3136c948245a..e94efccaa4827b1ce466ce3ccea0c846ff885f82 100644 (file)
@@ -281,7 +281,6 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long
  *     pdc2027x_set_piomode - Initialize host controller PATA PIO timings
  *     @ap: Port to configure
  *     @adev: um
- *     @pio: PIO mode, 0 - 4
  *
  *     Set PIO mode for device.
  *
@@ -326,7 +325,6 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
  *     pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings
  *     @ap: Port to configure
  *     @adev: um
- *     @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6
  *
  *     Set UDMA mode for device.
  *
@@ -406,23 +404,20 @@ static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed
        if (rc < 0)
                return rc;
 
-       ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
+       ata_for_each_dev(dev, link, ENABLED) {
+               pdc2027x_set_piomode(ap, dev);
 
-                       pdc2027x_set_piomode(ap, dev);
+               /*
+                * Enable prefetch if the device support PIO only.
+                */
+               if (dev->xfer_shift == ATA_SHIFT_PIO) {
+                       u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
+                       ctcr1 |= (1 << 25);
+                       iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
 
-                       /*
-                        * Enable prefetch if the device support PIO only.
-                        */
-                       if (dev->xfer_shift == ATA_SHIFT_PIO) {
-                               u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
-                               ctcr1 |= (1 << 25);
-                               iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
-
-                               PDPRINTK("Turn on prefetch\n");
-                       } else {
-                               pdc2027x_set_dmamode(ap, dev);
-                       }
+                       PDPRINTK("Turn on prefetch\n");
+               } else {
+                       pdc2027x_set_dmamode(ap, dev);
                }
        }
        return 0;
index 77e4e3b17f5479b7ee4a2306513f4e8aa5d3a18f..6afa07a37648ef7aac343f1d7bdb7e5d5de57161 100644 (file)
@@ -34,14 +34,12 @@ static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unu
 {
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
-                       /* We don't really care */
-                       dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
-                       dev->xfer_shift = ATA_SHIFT_PIO;
-                       dev->flags |= ATA_DFLAG_PIO;
-                       ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
-               }
+       ata_for_each_dev(dev, link, ENABLED) {
+               /* We don't really care */
+               dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               dev->flags |= ATA_DFLAG_PIO;
+               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
        }
        return 0;
 }
index 0b0aa452de147b834afbabc1248c082dd84099a9..695d44ae52c69673f7662f747ecf8d12b35a83e5 100644 (file)
@@ -81,7 +81,6 @@ static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev)
  *     radisys_set_dmamode - Initialize host controller PATA DMA timings
  *     @ap: Port whose timings we are configuring
  *     @adev: Device to program
- *     @isich: True if the device is an ICH and has IOCFG registers
  *
  *     Set MWDMA mode for device, in host controller PCI config space.
  *
index 7dfd1f3f6f3a21b31e738c4254a2aa5413890610..46d6bc1bf1e92afc990479c37525f4e91f197904 100644 (file)
@@ -38,15 +38,13 @@ static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
 {
        struct ata_device *dev;
 
-       ata_link_for_each_dev(dev, link) {
-               if (ata_dev_enabled(dev)) {
-                       /* We don't really care */
-                       dev->pio_mode = XFER_PIO_0;
-                       dev->xfer_mode = XFER_PIO_0;
-                       dev->xfer_shift = ATA_SHIFT_PIO;
-                       dev->flags |= ATA_DFLAG_PIO;
-                       ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
-               }
+       ata_for_each_dev(dev, link, ENABLED) {
+               /* We don't really care */
+               dev->pio_mode = XFER_PIO_0;
+               dev->xfer_mode = XFER_PIO_0;
+               dev->xfer_shift = ATA_SHIFT_PIO;
+               dev->flags |= ATA_DFLAG_PIO;
+               ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
        }
        return 0;
 }
index cf3707e516a2e2f4ca67c5f77276b2747c229579..d447f1cb46ec2ee47dd4d80c037b9157338acbd6 100644 (file)
@@ -210,7 +210,6 @@ static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev)
  *     scc_set_dmamode - Initialize host controller PATA DMA timings
  *     @ap: Port whose timings we are configuring
  *     @adev: um
- *     @udma: udma mode, 0 - 6
  *
  *     Set UDMA mode for device.
  *
index 72e41c9f969b3241c1c64622f3b232fdbf0ea642..8d2fd9dd40c7eba21f0c8820a91ceb01222f7411 100644 (file)
@@ -138,7 +138,6 @@ static struct sv_cable_table cable_detect[] = {
 /**
  *     serverworks_cable_detect        -       cable detection
  *     @ap: ATA port
- *     @deadline: deadline jiffies for the operation
  *
  *     Perform cable detection according to the device and subvendor
  *     identifications
index e4be55e047f61c3608bb9a0ae02027555475eb2c..27ceb42a774b4bc7499373189570c5a345e490cd 100644 (file)
@@ -112,7 +112,6 @@ static int sis_133_cable_detect(struct ata_port *ap)
 /**
  *     sis_66_cable_detect     -       check for 40/80 pin
  *     @ap: Port
- *     @deadline: deadline jiffies for the operation
  *
  *     Perform cable detection on the UDMA66, UDMA100 and early UDMA133
  *     SiS IDE controllers.
index 2b24ae58b52ee557e9d028e06e83de405a121a40..86918634a4c56e1ae7fa066006c5e56fc32ac123 100644 (file)
@@ -1836,7 +1836,6 @@ static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
 /**
  *      mv_err_intr - Handle error interrupts on the port
  *      @ap: ATA channel to manipulate
- *      @qc: affected command (non-NCQ), or NULL
  *
  *      Most cases require a full reset of the chip's state machine,
  *      which also performs a COMRESET.
index 031d7b7dee34bc09998c9d9cfa4d65891d47aa86..564c142b03b043ec9faf0c930b5ded6af1dc8b1d 100644 (file)
@@ -46,7 +46,9 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_sil"
-#define DRV_VERSION    "2.3"
+#define DRV_VERSION    "2.4"
+
+#define SIL_DMA_BOUNDARY       0x7fffffffUL
 
 enum {
        SIL_MMIO_BAR            = 5,
@@ -118,6 +120,10 @@ static void sil_dev_config(struct ata_device *dev);
 static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
 static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
 static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
+static void sil_qc_prep(struct ata_queued_cmd *qc);
+static void sil_bmdma_setup(struct ata_queued_cmd *qc);
+static void sil_bmdma_start(struct ata_queued_cmd *qc);
+static void sil_bmdma_stop(struct ata_queued_cmd *qc);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
 
@@ -167,13 +173,22 @@ static struct pci_driver sil_pci_driver = {
 };
 
 static struct scsi_host_template sil_sht = {
-       ATA_BMDMA_SHT(DRV_NAME),
+       ATA_BASE_SHT(DRV_NAME),
+       /** These controllers support Large Block Transfer which allows
+           transfer chunks up to 2GB and which cross 64KB boundaries,
+           therefore the DMA limits are more relaxed than standard ATA SFF. */
+       .dma_boundary           = SIL_DMA_BOUNDARY,
+       .sg_tablesize           = ATA_MAX_PRD
 };
 
 static struct ata_port_operations sil_ops = {
        .inherits               = &ata_bmdma_port_ops,
        .dev_config             = sil_dev_config,
        .set_mode               = sil_set_mode,
+       .bmdma_setup            = sil_bmdma_setup,
+       .bmdma_start            = sil_bmdma_start,
+       .bmdma_stop             = sil_bmdma_stop,
+       .qc_prep                = sil_qc_prep,
        .freeze                 = sil_freeze,
        .thaw                   = sil_thaw,
        .scr_read               = sil_scr_read,
@@ -249,6 +264,83 @@ module_param(slow_down, int, 0444);
 MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
 
 
+static void sil_bmdma_stop(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
+       void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2;
+
+       /* clear start/stop bit - can safely always write 0 */
+       iowrite8(0, bmdma2);
+
+       /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+       ata_sff_dma_pause(ap);
+}
+
+static void sil_bmdma_setup(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+       void __iomem *bmdma = ap->ioaddr.bmdma_addr;
+
+       /* load PRD table addr. */
+       iowrite32(ap->prd_dma, bmdma + ATA_DMA_TABLE_OFS);
+
+       /* issue r/w command */
+       ap->ops->sff_exec_command(ap, &qc->tf);
+}
+
+static void sil_bmdma_start(struct ata_queued_cmd *qc)
+{
+       unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+       struct ata_port *ap = qc->ap;
+       void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
+       void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2;
+       u8 dmactl = ATA_DMA_START;
+
+       /* set transfer direction, start host DMA transaction
+          Note: For Large Block Transfer to work, the DMA must be started
+          using the bmdma2 register. */
+       if (!rw)
+               dmactl |= ATA_DMA_WR;
+       iowrite8(dmactl, bmdma2);
+}
+
+/* The way God intended PCI IDE scatter/gather lists to look and behave... */
+static void sil_fill_sg(struct ata_queued_cmd *qc)
+{
+       struct scatterlist *sg;
+       struct ata_port *ap = qc->ap;
+       struct ata_prd *prd, *last_prd = NULL;
+       unsigned int si;
+
+       prd = &ap->prd[0];
+       for_each_sg(qc->sg, sg, qc->n_elem, si) {
+               /* Note h/w doesn't support 64-bit, so we unconditionally
+                * truncate dma_addr_t to u32.
+                */
+               u32 addr = (u32) sg_dma_address(sg);
+               u32 sg_len = sg_dma_len(sg);
+
+               prd->addr = cpu_to_le32(addr);
+               prd->flags_len = cpu_to_le32(sg_len);
+               VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, sg_len);
+
+               last_prd = prd;
+               prd++;
+       }
+
+       if (likely(last_prd))
+               last_prd->flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static void sil_qc_prep(struct ata_queued_cmd *qc)
+{
+       if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+               return;
+
+       sil_fill_sg(qc);
+}
+
 static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
 {
        u8 cache_line = 0;
@@ -278,7 +370,7 @@ static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
        if (rc)
                return rc;
 
-       ata_link_for_each_dev(dev, link) {
+       ata_for_each_dev(dev, link, ALL) {
                if (!ata_dev_enabled(dev))
                        dev_mode[dev->devno] = 0;       /* PIO0/1/2 */
                else if (dev->flags & ATA_DFLAG_PIO)
index 9f7c543cc04b265344b0e37443c4349147e88574..01e69383d9c07ece3df6e56d23b4d3b2bf687475 100644 (file)
@@ -164,7 +164,7 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int cciss_revalidate(struct gendisk *disk);
 static int rebuild_lun_table(ctlr_info_t *h, int first_time);
-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+static int deregister_disk(ctlr_info_t *h, int drv_index,
                           int clear_all);
 
 static void cciss_read_capacity(int ctlr, int logvol, int withirq,
@@ -215,31 +215,17 @@ static struct block_device_operations cciss_fops = {
 /*
  * Enqueuing and dequeuing functions for cmdlists.
  */
-static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
+static inline void addQ(struct hlist_head *list, CommandList_struct *c)
 {
-       if (*Qptr == NULL) {
-               *Qptr = c;
-               c->next = c->prev = c;
-       } else {
-               c->prev = (*Qptr)->prev;
-               c->next = (*Qptr);
-               (*Qptr)->prev->next = c;
-               (*Qptr)->prev = c;
-       }
+       hlist_add_head(&c->list, list);
 }
 
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
-                                         CommandList_struct *c)
+static inline void removeQ(CommandList_struct *c)
 {
-       if (c && c->next != c) {
-               if (*Qptr == c)
-                       *Qptr = c->next;
-               c->prev->next = c->next;
-               c->next->prev = c->prev;
-       } else {
-               *Qptr = NULL;
-       }
-       return c;
+       if (WARN_ON(hlist_unhashed(&c->list)))
+               return;
+
+       hlist_del_init(&c->list);
 }
 
 #include "cciss_scsi.c"                /* For SCSI tape support */
@@ -506,6 +492,7 @@ static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
                c->cmdindex = i;
        }
 
+       INIT_HLIST_NODE(&c->list);
        c->busaddr = (__u32) cmd_dma_handle;
        temp64.val = (__u64) err_dma_handle;
        c->ErrDesc.Addr.lower = temp64.val32.lower;
@@ -1492,8 +1479,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
                 * which keeps the interrupt handler from starting
                 * the queue.
                 */
-               ret = deregister_disk(h->gendisk[drv_index],
-                                     &h->drv[drv_index], 0);
+               ret = deregister_disk(h, drv_index, 0);
                h->drv[drv_index].busy_configuring = 0;
        }
 
@@ -1711,8 +1697,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
                        spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
                        h->drv[i].busy_configuring = 1;
                        spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
-                       return_code = deregister_disk(h->gendisk[i],
-                               &h->drv[i], 1);
+                       return_code = deregister_disk(h, i, 1);
                        h->drv[i].busy_configuring = 0;
                }
        }
@@ -1782,15 +1767,19 @@ mem_msg:
  *             the highest_lun should be left unchanged and the LunID
  *             should not be cleared.
 */
-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+static int deregister_disk(ctlr_info_t *h, int drv_index,
                           int clear_all)
 {
        int i;
-       ctlr_info_t *h = get_host(disk);
+       struct gendisk *disk;
+       drive_info_struct *drv;
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
 
+       drv = &h->drv[drv_index];
+       disk = h->gendisk[drv_index];
+
        /* make sure logical volume is NOT is use */
        if (clear_all || (h->gendisk[0] == disk)) {
                if (drv->usage_count > 1)
@@ -2548,7 +2537,8 @@ static void start_io(ctlr_info_t *h)
 {
        CommandList_struct *c;
 
-       while ((c = h->reqQ) != NULL) {
+       while (!hlist_empty(&h->reqQ)) {
+               c = hlist_entry(h->reqQ.first, CommandList_struct, list);
                /* can't do anything if fifo is full */
                if ((h->access.fifo_full(h))) {
                        printk(KERN_WARNING "cciss: fifo full\n");
@@ -2556,14 +2546,14 @@ static void start_io(ctlr_info_t *h)
                }
 
                /* Get the first entry from the Request Q */
-               removeQ(&(h->reqQ), c);
+               removeQ(c);
                h->Qdepth--;
 
                /* Tell the controller execute command */
                h->access.submit_command(h, c);
 
                /* Put job onto the completed Q */
-               addQ(&(h->cmpQ), c);
+               addQ(&h->cmpQ, c);
        }
 }
 
@@ -2576,7 +2566,7 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
        memset(c->err_info, 0, sizeof(ErrorInfo_struct));
 
        /* add it to software queue and then send it to the controller */
-       addQ(&(h->reqQ), c);
+       addQ(&h->reqQ, c);
        h->Qdepth++;
        if (h->Qdepth > h->maxQsinceinit)
                h->maxQsinceinit = h->Qdepth;
@@ -2897,7 +2887,7 @@ static void do_cciss_request(struct request_queue *q)
 
        spin_lock_irq(q->queue_lock);
 
-       addQ(&(h->reqQ), c);
+       addQ(&h->reqQ, c);
        h->Qdepth++;
        if (h->Qdepth > h->maxQsinceinit)
                h->maxQsinceinit = h->Qdepth;
@@ -2985,16 +2975,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
                                a = c->busaddr;
 
                        } else {
+                               struct hlist_node *tmp;
+
                                a &= ~3;
-                               if ((c = h->cmpQ) == NULL) {
-                                       printk(KERN_WARNING
-                                              "cciss: Completion of %08x ignored\n",
-                                              a1);
-                                       continue;
-                               }
-                               while (c->busaddr != a) {
-                                       c = c->next;
-                                       if (c == h->cmpQ)
+                               c = NULL;
+                               hlist_for_each_entry(c, tmp, &h->cmpQ, list) {
+                                       if (c->busaddr == a)
                                                break;
                                }
                        }
@@ -3002,8 +2988,8 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
                         * If we've found the command, take it off the
                         * completion Q and free it
                         */
-                       if (c->busaddr == a) {
-                               removeQ(&h->cmpQ, c);
+                       if (c && c->busaddr == a) {
+                               removeQ(c);
                                if (c->cmd_type == CMD_RWREQ) {
                                        complete_command(h, c, 0);
                                } else if (c->cmd_type == CMD_IOCTL_PEND) {
@@ -3423,6 +3409,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                return -1;
 
        hba[i]->busy_initializing = 1;
+       INIT_HLIST_HEAD(&hba[i]->cmpQ);
+       INIT_HLIST_HEAD(&hba[i]->reqQ);
 
        if (cciss_pci_init(hba[i], pdev) != 0)
                goto clean1;
@@ -3730,15 +3718,17 @@ static void fail_all_cmds(unsigned long ctlr)
        pci_disable_device(h->pdev);    /* Make sure it is really dead. */
 
        /* move everything off the request queue onto the completed queue */
-       while ((c = h->reqQ) != NULL) {
-               removeQ(&(h->reqQ), c);
+       while (!hlist_empty(&h->reqQ)) {
+               c = hlist_entry(h->reqQ.first, CommandList_struct, list);
+               removeQ(c);
                h->Qdepth--;
-               addQ(&(h->cmpQ), c);
+               addQ(&h->cmpQ, c);
        }
 
        /* Now, fail everything on the completed queue with a HW error */
-       while ((c = h->cmpQ) != NULL) {
-               removeQ(&h->cmpQ, c);
+       while (!hlist_empty(&h->cmpQ)) {
+               c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
+               removeQ(c);
                c->err_info->CommandStatus = CMD_HARDWARE_ERR;
                if (c->cmd_type == CMD_RWREQ) {
                        complete_command(h, c, 0);
index 24a7efa993ab5d1dd655c68c60e57b41a6f5ebdc..15e2b84734e3ad68df867b26a47b98ea9e982326 100644 (file)
@@ -89,8 +89,8 @@ struct ctlr_info
        struct access_method access;
 
        /* queue and queue Info */ 
-       CommandList_struct *reqQ;
-       CommandList_struct  *cmpQ;
+       struct hlist_head reqQ;
+       struct hlist_head cmpQ;
        unsigned int Qdepth;
        unsigned int maxQsinceinit;
        unsigned int maxSG;
index 43bf5593b59bf6ed1da79abbbba46a0fea499d44..24e22dea1a99e2ee2d8ec297b0dd69b624acff15 100644 (file)
@@ -265,8 +265,7 @@ typedef struct _CommandList_struct {
   int                     ctlr;
   int                     cmd_type; 
   long                    cmdindex;
-  struct _CommandList_struct *prev;
-  struct _CommandList_struct *next;
+  struct hlist_node list;
   struct request *        rq;
   struct completion *waiting;
   int   retry_count;
index fb06ed6592121fe8dbdfa79da727f2a6eac921f5..edbaac6c05739ab183e69f94c1dc230acea27176 100644 (file)
@@ -623,6 +623,18 @@ static int loop_switch(struct loop_device *lo, struct file *file)
        return 0;
 }
 
+/*
+ * Helper to flush the IOs in loop, but keeping loop thread running
+ */
+static int loop_flush(struct loop_device *lo)
+{
+       /* loop not yet configured, no running thread, nothing to flush */
+       if (!lo->lo_thread)
+               return 0;
+
+       return loop_switch(lo, NULL);
+}
+
 /*
  * Do the actual switch; called from the BIO completion routine
  */
@@ -630,14 +642,20 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
 {
        struct file *file = p->file;
        struct file *old_file = lo->lo_backing_file;
-       struct address_space *mapping = file->f_mapping;
+       struct address_space *mapping;
+
+       /* if no new file, only flush of queued bios requested */
+       if (!file)
+               goto out;
 
+       mapping = file->f_mapping;
        mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
        lo->lo_backing_file = file;
        lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
                mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
        lo->old_gfp_mask = mapping_gfp_mask(mapping);
        mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+out:
        complete(&p->wait);
 }
 
@@ -901,6 +919,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
 
        kthread_stop(lo->lo_thread);
 
+       lo->lo_queue->unplug_fn = NULL;
        lo->lo_backing_file = NULL;
 
        loop_release_xfer(lo);
@@ -1345,11 +1364,25 @@ static int lo_release(struct gendisk *disk, fmode_t mode)
        struct loop_device *lo = disk->private_data;
 
        mutex_lock(&lo->lo_ctl_mutex);
-       --lo->lo_refcnt;
 
-       if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt)
+       if (--lo->lo_refcnt)
+               goto out;
+
+       if (lo->lo_flags & LO_FLAGS_AUTOCLEAR) {
+               /*
+                * In autoclear mode, stop the loop thread
+                * and remove configuration after last close.
+                */
                loop_clr_fd(lo, NULL);
+       } else {
+               /*
+                * Otherwise keep thread (if running) and config,
+                * but flush possible ongoing bios in thread.
+                */
+               loop_flush(lo);
+       }
 
+out:
        mutex_unlock(&lo->lo_ctl_mutex);
 
        return 0;
index d3a91cacee8c6aff410bc9a8567ce89cb1ae477f..7bcc1d8bc96724add86213f7f85ec01ed48a8314 100644 (file)
@@ -722,7 +722,6 @@ static int __init nbd_init(void)
 
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
-               elevator_t *old_e;
                if (!disk)
                        goto out;
                nbd_dev[i].disk = disk;
@@ -736,11 +735,10 @@ static int __init nbd_init(void)
                        put_disk(disk);
                        goto out;
                }
-               old_e = disk->queue->elevator;
-               if (elevator_init(disk->queue, "deadline") == 0 ||
-                       elevator_init(disk->queue, "noop") == 0) {
-                               elevator_exit(old_e);
-               }
+               /*
+                * Tell the block layer that we are not a rotational device
+                */
+               queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue);
        }
 
        if (register_blkdev(NBD_MAJOR, "nbd")) {
index 85d79a02d48726c150e6f8f1b17889f84bc8cc8d..5d34764c8a8726d5103e6e723eaae6ab28a6a422 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/virtio_blk.h>
 #include <linux/scatterlist.h>
 
-#define VIRTIO_MAX_SG  (3+MAX_PHYS_SEGMENTS)
 #define PART_BITS 4
 
 static int major, index;
@@ -26,8 +25,11 @@ struct virtio_blk
 
        mempool_t *pool;
 
+       /* What host tells us, plus 2 for header & tailer. */
+       unsigned int sg_elems;
+
        /* Scatterlist: can be too big for stack. */
-       struct scatterlist sg[VIRTIO_MAX_SG];
+       struct scatterlist sg[/*sg_elems*/];
 };
 
 struct virtblk_req
@@ -97,8 +99,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        if (blk_barrier_rq(vbr->req))
                vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
 
-       /* This init could be done at vblk creation time */
-       sg_init_table(vblk->sg, VIRTIO_MAX_SG);
        sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
        num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
        sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
@@ -130,7 +130,7 @@ static void do_virtblk_request(struct request_queue *q)
 
        while ((req = elv_next_request(q)) != NULL) {
                vblk = req->rq_disk->private_data;
-               BUG_ON(req->nr_phys_segments > ARRAY_SIZE(vblk->sg));
+               BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
 
                /* If this request fails, stop queue and wait for something to
                   finish to restart it. */
@@ -196,12 +196,22 @@ static int virtblk_probe(struct virtio_device *vdev)
        int err;
        u64 cap;
        u32 v;
-       u32 blk_size;
+       u32 blk_size, sg_elems;
 
        if (index_to_minor(index) >= 1 << MINORBITS)
                return -ENOSPC;
 
-       vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
+       /* We need to know how many segments before we allocate. */
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
+                               offsetof(struct virtio_blk_config, seg_max),
+                               &sg_elems);
+       if (err)
+               sg_elems = 1;
+
+       /* We need an extra sg elements at head and tail. */
+       sg_elems += 2;
+       vdev->priv = vblk = kmalloc(sizeof(*vblk) +
+                                   sizeof(vblk->sg[0]) * sg_elems, GFP_KERNEL);
        if (!vblk) {
                err = -ENOMEM;
                goto out;
@@ -210,6 +220,8 @@ static int virtblk_probe(struct virtio_device *vdev)
        INIT_LIST_HEAD(&vblk->reqs);
        spin_lock_init(&vblk->lock);
        vblk->vdev = vdev;
+       vblk->sg_elems = sg_elems;
+       sg_init_table(vblk->sg, vblk->sg_elems);
 
        /* We expect one virtqueue, for output. */
        vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
@@ -237,6 +249,8 @@ static int virtblk_probe(struct virtio_device *vdev)
                goto out_put_disk;
        }
 
+       queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);
+
        if (index < 26) {
                sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
        } else if (index < (26 + 1) * 26) {
@@ -277,6 +291,13 @@ static int virtblk_probe(struct virtio_device *vdev)
        }
        set_capacity(vblk->disk, cap);
 
+       /* We can handle whatever the host told us to handle. */
+       blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
+       blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
+
+       /* No real sector limit. */
+       blk_queue_max_sectors(vblk->disk->queue, -1U);
+
        /* Host can optionally specify maximum segment size and number of
         * segments. */
        err = virtio_config_val(vdev, VIRTIO_BLK_F_SIZE_MAX,
@@ -284,12 +305,8 @@ static int virtblk_probe(struct virtio_device *vdev)
                                &v);
        if (!err)
                blk_queue_max_segment_size(vblk->disk->queue, v);
-
-       err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
-                               offsetof(struct virtio_blk_config, seg_max),
-                               &v);
-       if (!err)
-               blk_queue_max_hw_segments(vblk->disk->queue, v);
+       else
+               blk_queue_max_segment_size(vblk->disk->queue, -1U);
 
        /* Host can optionally specify the block size of the device */
        err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
index 2d19f0cc47f272c5ae4f96ee97ea34a1bce5a407..918ef725de41c849f3f78b7e30f80d7709e01a39 100644 (file)
@@ -338,18 +338,12 @@ wait:
 static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 {
        struct request_queue *rq;
-       elevator_t *old_e;
 
        rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
        if (rq == NULL)
                return -1;
 
-       old_e = rq->elevator;
-       if (IS_ERR_VALUE(elevator_init(rq, "noop")))
-               printk(KERN_WARNING
-                       "blkfront: Switch elevator failed, use default\n");
-       else
-               elevator_exit(old_e);
+       queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);
 
        /* Hard sector size and max sectors impersonate the equiv. hardware. */
        blk_queue_hardsect_size(rq, sector_size);
index 7d2e91cccb13e99068a4499bc469ef9bc032c67b..cceace61ef286622b93af85fb5c45d134c289eae 100644 (file)
@@ -1712,29 +1712,30 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        return 0;
 }
 
-static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
+static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s,
+                               struct packet_command *cgc)
 {
        unsigned char buf[21], *base;
        struct dvd_layer *layer;
-       struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
        int ret, layer_num = s->physical.layer_num;
 
        if (layer_num >= DVD_LAYERS)
                return -EINVAL;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-       cgc.cmd[6] = layer_num;
-       cgc.cmd[7] = s->type;
-       cgc.cmd[9] = cgc.buflen & 0xff;
+       init_cdrom_command(cgc, buf, sizeof(buf), CGC_DATA_READ);
+       cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
+       cgc->cmd[6] = layer_num;
+       cgc->cmd[7] = s->type;
+       cgc->cmd[9] = cgc->buflen & 0xff;
 
        /*
         * refrain from reporting errors on non-existing layers (mainly)
         */
-       cgc.quiet = 1;
+       cgc->quiet = 1;
 
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
+       ret = cdo->generic_packet(cdi, cgc);
+       if (ret)
                return ret;
 
        base = &buf[4];
@@ -1762,21 +1763,22 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        return 0;
 }
 
-static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
+static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s,
+                               struct packet_command *cgc)
 {
        int ret;
        u_char buf[8];
-       struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-       cgc.cmd[6] = s->copyright.layer_num;
-       cgc.cmd[7] = s->type;
-       cgc.cmd[8] = cgc.buflen >> 8;
-       cgc.cmd[9] = cgc.buflen & 0xff;
+       init_cdrom_command(cgc, buf, sizeof(buf), CGC_DATA_READ);
+       cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
+       cgc->cmd[6] = s->copyright.layer_num;
+       cgc->cmd[7] = s->type;
+       cgc->cmd[8] = cgc->buflen >> 8;
+       cgc->cmd[9] = cgc->buflen & 0xff;
 
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
+       ret = cdo->generic_packet(cdi, cgc);
+       if (ret)
                return ret;
 
        s->copyright.cpst = buf[4];
@@ -1785,79 +1787,89 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
        return 0;
 }
 
-static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
+static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s,
+                               struct packet_command *cgc)
 {
        int ret, size;
        u_char *buf;
-       struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
        size = sizeof(s->disckey.value) + 4;
 
-       if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
                return -ENOMEM;
 
-       init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-       cgc.cmd[7] = s->type;
-       cgc.cmd[8] = size >> 8;
-       cgc.cmd[9] = size & 0xff;
-       cgc.cmd[10] = s->disckey.agid << 6;
+       init_cdrom_command(cgc, buf, size, CGC_DATA_READ);
+       cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
+       cgc->cmd[7] = s->type;
+       cgc->cmd[8] = size >> 8;
+       cgc->cmd[9] = size & 0xff;
+       cgc->cmd[10] = s->disckey.agid << 6;
 
-       if (!(ret = cdo->generic_packet(cdi, &cgc)))
+       ret = cdo->generic_packet(cdi, cgc);
+       if (!ret)
                memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value));
 
        kfree(buf);
        return ret;
 }
 
-static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
+static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s,
+                       struct packet_command *cgc)
 {
-       int ret;
-       u_char buf[4 + 188];
-       struct packet_command cgc;
+       int ret, size = 4 + 188;
+       u_char *buf;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-       cgc.cmd[7] = s->type;
-       cgc.cmd[9] = cgc.buflen & 0xff;
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+       init_cdrom_command(cgc, buf, size, CGC_DATA_READ);
+       cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
+       cgc->cmd[7] = s->type;
+       cgc->cmd[9] = cgc->buflen & 0xff;
+
+       ret = cdo->generic_packet(cdi, cgc);
+       if (ret)
+               goto out;
 
        s->bca.len = buf[0] << 8 | buf[1];
        if (s->bca.len < 12 || s->bca.len > 188) {
                cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len);
-               return -EIO;
+               ret = -EIO;
+               goto out;
        }
        memcpy(s->bca.value, &buf[4], s->bca.len);
-
-       return 0;
+       ret = 0;
+out:
+       kfree(buf);
+       return ret;
 }
 
-static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
+static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
+                               struct packet_command *cgc)
 {
        int ret = 0, size;
        u_char *buf;
-       struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
        size = sizeof(s->manufact.value) + 4;
 
-       if ((buf = kmalloc(size, GFP_KERNEL)) == NULL)
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
                return -ENOMEM;
 
-       init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-       cgc.cmd[7] = s->type;
-       cgc.cmd[8] = size >> 8;
-       cgc.cmd[9] = size & 0xff;
+       init_cdrom_command(cgc, buf, size, CGC_DATA_READ);
+       cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE;
+       cgc->cmd[7] = s->type;
+       cgc->cmd[8] = size >> 8;
+       cgc->cmd[9] = size & 0xff;
 
-       if ((ret = cdo->generic_packet(cdi, &cgc))) {
-               kfree(buf);
-               return ret;
-       }
+       ret = cdo->generic_packet(cdi, cgc);
+       if (ret)
+               goto out;
 
        s->manufact.len = buf[0] << 8 | buf[1];
        if (s->manufact.len < 0 || s->manufact.len > 2048) {
@@ -1868,27 +1880,29 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
                memcpy(s->manufact.value, &buf[4], s->manufact.len);
        }
 
+out:
        kfree(buf);
        return ret;
 }
 
-static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s)
+static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s,
+                               struct packet_command *cgc)
 {
        switch (s->type) {
        case DVD_STRUCT_PHYSICAL:
-               return dvd_read_physical(cdi, s);
+               return dvd_read_physical(cdi, s, cgc);
 
        case DVD_STRUCT_COPYRIGHT:
-               return dvd_read_copyright(cdi, s);
+               return dvd_read_copyright(cdi, s, cgc);
 
        case DVD_STRUCT_DISCKEY:
-               return dvd_read_disckey(cdi, s);
+               return dvd_read_disckey(cdi, s, cgc);
 
        case DVD_STRUCT_BCA:
-               return dvd_read_bca(cdi, s);
+               return dvd_read_bca(cdi, s, cgc);
 
        case DVD_STRUCT_MANUFACT:
-               return dvd_read_manufact(cdi, s);
+               return dvd_read_manufact(cdi, s, cgc);
                
        default:
                cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n",
@@ -2787,271 +2801,360 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
        return cdo->generic_packet(cdi, &cgc);
 }
 
-static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-                    unsigned long arg)
-{              
-       struct cdrom_device_ops *cdo = cdi->ops;
-       struct packet_command cgc;
+static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
+                                       void __user *arg,
+                                       struct packet_command *cgc,
+                                       int cmd)
+{
        struct request_sense sense;
-       unsigned char buffer[32];
-       int ret = 0;
-
-       memset(&cgc, 0, sizeof(cgc));
+       struct cdrom_msf msf;
+       int blocksize = 0, format = 0, lba;
+       int ret;
 
-       /* build a unified command and queue it through
-          cdo->generic_packet() */
        switch (cmd) {
        case CDROMREADRAW:
+               blocksize = CD_FRAMESIZE_RAW;
+               break;
        case CDROMREADMODE1:
-       case CDROMREADMODE2: {
-               struct cdrom_msf msf;
-               int blocksize = 0, format = 0, lba;
-               
-               switch (cmd) {
-               case CDROMREADRAW:
-                       blocksize = CD_FRAMESIZE_RAW;
-                       break;
-               case CDROMREADMODE1:
-                       blocksize = CD_FRAMESIZE;
-                       format = 2;
-                       break;
-               case CDROMREADMODE2:
-                       blocksize = CD_FRAMESIZE_RAW0;
-                       break;
-               }
-               IOCTL_IN(arg, struct cdrom_msf, msf);
-               lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0);
-               /* FIXME: we need upper bound checking, too!! */
-               if (lba < 0)
-                       return -EINVAL;
-               cgc.buffer = kmalloc(blocksize, GFP_KERNEL);
-               if (cgc.buffer == NULL)
-                       return -ENOMEM;
-               memset(&sense, 0, sizeof(sense));
-               cgc.sense = &sense;
-               cgc.data_direction = CGC_DATA_READ;
-               ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);
-               if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) {
-                       /*
-                        * SCSI-II devices are not required to support
-                        * READ_CD, so let's try switching block size
-                        */
-                       /* FIXME: switch back again... */
-                       if ((ret = cdrom_switch_blocksize(cdi, blocksize))) {
-                               kfree(cgc.buffer);
-                               return ret;
-                       }
-                       cgc.sense = NULL;
-                       ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1);
-                       ret |= cdrom_switch_blocksize(cdi, blocksize);
-               }
-               if (!ret && copy_to_user((char __user *)arg, cgc.buffer, blocksize))
-                       ret = -EFAULT;
-               kfree(cgc.buffer);
+               blocksize = CD_FRAMESIZE;
+               format = 2;
+               break;
+       case CDROMREADMODE2:
+               blocksize = CD_FRAMESIZE_RAW0;
+               break;
+       }
+       IOCTL_IN(arg, struct cdrom_msf, msf);
+       lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0);
+       /* FIXME: we need upper bound checking, too!! */
+       if (lba < 0)
+               return -EINVAL;
+
+       cgc->buffer = kmalloc(blocksize, GFP_KERNEL);
+       if (cgc->buffer == NULL)
+               return -ENOMEM;
+
+       memset(&sense, 0, sizeof(sense));
+       cgc->sense = &sense;
+       cgc->data_direction = CGC_DATA_READ;
+       ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize);
+       if (ret && sense.sense_key == 0x05 &&
+                  sense.asc == 0x20 &&
+                  sense.ascq == 0x00) {
+               /*
+                * SCSI-II devices are not required to support
+                * READ_CD, so let's try switching block size
+                */
+               /* FIXME: switch back again... */
+               ret = cdrom_switch_blocksize(cdi, blocksize);
+               if (ret)
+                       goto out;
+               cgc->sense = NULL;
+               ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1);
+               ret |= cdrom_switch_blocksize(cdi, blocksize);
+       }
+       if (!ret && copy_to_user(arg, cgc->buffer, blocksize))
+               ret = -EFAULT;
+out:
+       kfree(cgc->buffer);
+       return ret;
+}
+
+static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
+                                       void __user *arg)
+{
+       struct cdrom_read_audio ra;
+       int lba;
+
+       IOCTL_IN(arg, struct cdrom_read_audio, ra);
+
+       if (ra.addr_format == CDROM_MSF)
+               lba = msf_to_lba(ra.addr.msf.minute,
+                                ra.addr.msf.second,
+                                ra.addr.msf.frame);
+       else if (ra.addr_format == CDROM_LBA)
+               lba = ra.addr.lba;
+       else
+               return -EINVAL;
+
+       /* FIXME: we need upper bound checking, too!! */
+       if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES)
+               return -EINVAL;
+
+       return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes);
+}
+
+static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,
+                                       void __user *arg)
+{
+       int ret;
+       struct cdrom_subchnl q;
+       u_char requested, back;
+       IOCTL_IN(arg, struct cdrom_subchnl, q);
+       requested = q.cdsc_format;
+       if (!((requested == CDROM_MSF) ||
+             (requested == CDROM_LBA)))
+               return -EINVAL;
+       q.cdsc_format = CDROM_MSF;
+       ret = cdrom_read_subchannel(cdi, &q, 0);
+       if (ret)
                return ret;
-               }
-       case CDROMREADAUDIO: {
-               struct cdrom_read_audio ra;
-               int lba;
-
-               IOCTL_IN(arg, struct cdrom_read_audio, ra);
-
-               if (ra.addr_format == CDROM_MSF)
-                       lba = msf_to_lba(ra.addr.msf.minute,
-                                        ra.addr.msf.second,
-                                        ra.addr.msf.frame);
-               else if (ra.addr_format == CDROM_LBA)
-                       lba = ra.addr.lba;
-               else
-                       return -EINVAL;
+       back = q.cdsc_format; /* local copy */
+       sanitize_format(&q.cdsc_absaddr, &back, requested);
+       sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
+       IOCTL_OUT(arg, struct cdrom_subchnl, q);
+       /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+       return 0;
+}
 
-               /* FIXME: we need upper bound checking, too!! */
-               if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES)
-                       return -EINVAL;
+static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
+                                       void __user *arg,
+                                       struct packet_command *cgc)
+{
+       struct cdrom_device_ops *cdo = cdi->ops;
+       struct cdrom_msf msf;
+       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+       IOCTL_IN(arg, struct cdrom_msf, msf);
+       cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+       cgc->cmd[3] = msf.cdmsf_min0;
+       cgc->cmd[4] = msf.cdmsf_sec0;
+       cgc->cmd[5] = msf.cdmsf_frame0;
+       cgc->cmd[6] = msf.cdmsf_min1;
+       cgc->cmd[7] = msf.cdmsf_sec1;
+       cgc->cmd[8] = msf.cdmsf_frame1;
+       cgc->data_direction = CGC_DATA_NONE;
+       return cdo->generic_packet(cdi, cgc);
+}
 
-               return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes);
-               }
-       case CDROMSUBCHNL: {
-               struct cdrom_subchnl q;
-               u_char requested, back;
-               IOCTL_IN(arg, struct cdrom_subchnl, q);
-               requested = q.cdsc_format;
-               if (!((requested == CDROM_MSF) ||
-                     (requested == CDROM_LBA)))
-                       return -EINVAL;
-               q.cdsc_format = CDROM_MSF;
-               if ((ret = cdrom_read_subchannel(cdi, &q, 0)))
-                       return ret;
-               back = q.cdsc_format; /* local copy */
-               sanitize_format(&q.cdsc_absaddr, &back, requested);
-               sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
-               IOCTL_OUT(arg, struct cdrom_subchnl, q);
-               /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 
-               return 0;
-               }
-       case CDROMPLAYMSF: {
-               struct cdrom_msf msf;
-               cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
-               IOCTL_IN(arg, struct cdrom_msf, msf);
-               cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
-               cgc.cmd[3] = msf.cdmsf_min0;
-               cgc.cmd[4] = msf.cdmsf_sec0;
-               cgc.cmd[5] = msf.cdmsf_frame0;
-               cgc.cmd[6] = msf.cdmsf_min1;
-               cgc.cmd[7] = msf.cdmsf_sec1;
-               cgc.cmd[8] = msf.cdmsf_frame1;
-               cgc.data_direction = CGC_DATA_NONE;
-               return cdo->generic_packet(cdi, &cgc);
-               }
-       case CDROMPLAYBLK: {
-               struct cdrom_blk blk;
-               cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
-               IOCTL_IN(arg, struct cdrom_blk, blk);
-               cgc.cmd[0] = GPCMD_PLAY_AUDIO_10;
-               cgc.cmd[2] = (blk.from >> 24) & 0xff;
-               cgc.cmd[3] = (blk.from >> 16) & 0xff;
-               cgc.cmd[4] = (blk.from >>  8) & 0xff;
-               cgc.cmd[5] = blk.from & 0xff;
-               cgc.cmd[7] = (blk.len >> 8) & 0xff;
-               cgc.cmd[8] = blk.len & 0xff;
-               cgc.data_direction = CGC_DATA_NONE;
-               return cdo->generic_packet(cdi, &cgc);
-               }
-       case CDROMVOLCTRL:
-       case CDROMVOLREAD: {
-               struct cdrom_volctrl volctrl;
-               char mask[sizeof(buffer)];
-               unsigned short offset;
+static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
+                                       void __user *arg,
+                                       struct packet_command *cgc)
+{
+       struct cdrom_device_ops *cdo = cdi->ops;
+       struct cdrom_blk blk;
+       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
+       IOCTL_IN(arg, struct cdrom_blk, blk);
+       cgc->cmd[0] = GPCMD_PLAY_AUDIO_10;
+       cgc->cmd[2] = (blk.from >> 24) & 0xff;
+       cgc->cmd[3] = (blk.from >> 16) & 0xff;
+       cgc->cmd[4] = (blk.from >>  8) & 0xff;
+       cgc->cmd[5] = blk.from & 0xff;
+       cgc->cmd[7] = (blk.len >> 8) & 0xff;
+       cgc->cmd[8] = blk.len & 0xff;
+       cgc->data_direction = CGC_DATA_NONE;
+       return cdo->generic_packet(cdi, cgc);
+}
+
+static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
+                                       void __user *arg,
+                                       struct packet_command *cgc,
+                                       unsigned int cmd)
+{
+       struct cdrom_volctrl volctrl;
+       unsigned char buffer[32];
+       char mask[sizeof(buffer)];
+       unsigned short offset;
+       int ret;
 
-               cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
+       cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
 
-               IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
+       IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
 
-               cgc.buffer = buffer;
-               cgc.buflen = 24;
-               if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0)))
-                   return ret;
+       cgc->buffer = buffer;
+       cgc->buflen = 24;
+       ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 0);
+       if (ret)
+               return ret;
                
-               /* originally the code depended on buffer[1] to determine
-                  how much data is available for transfer. buffer[1] is
-                  unfortunately ambigious and the only reliable way seem
-                  to be to simply skip over the block descriptor... */
-               offset = 8 + be16_to_cpu(*(__be16 *)(buffer+6));
-
-               if (offset + 16 > sizeof(buffer))
-                       return -E2BIG;
-
-               if (offset + 16 > cgc.buflen) {
-                       cgc.buflen = offset+16;
-                       ret = cdrom_mode_sense(cdi, &cgc,
-                                               GPMODE_AUDIO_CTL_PAGE, 0);
-                       if (ret)
-                               return ret;
-               }
+       /* originally the code depended on buffer[1] to determine
+          how much data is available for transfer. buffer[1] is
+          unfortunately ambigious and the only reliable way seem
+          to be to simply skip over the block descriptor... */
+       offset = 8 + be16_to_cpu(*(__be16 *)(buffer + 6));
+
+       if (offset + 16 > sizeof(buffer))
+               return -E2BIG;
+
+       if (offset + 16 > cgc->buflen) {
+               cgc->buflen = offset + 16;
+               ret = cdrom_mode_sense(cdi, cgc,
+                                       GPMODE_AUDIO_CTL_PAGE, 0);
+               if (ret)
+                       return ret;
+       }
 
-               /* sanity check */
-               if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE ||
-                               buffer[offset+1] < 14)
-                       return -EINVAL;
+       /* sanity check */
+       if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE ||
+                       buffer[offset + 1] < 14)
+               return -EINVAL;
 
-               /* now we have the current volume settings. if it was only
-                  a CDROMVOLREAD, return these values */
-               if (cmd == CDROMVOLREAD) {
-                       volctrl.channel0 = buffer[offset+9];
-                       volctrl.channel1 = buffer[offset+11];
-                       volctrl.channel2 = buffer[offset+13];
-                       volctrl.channel3 = buffer[offset+15];
-                       IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);
-                       return 0;
-               }
+       /* now we have the current volume settings. if it was only
+          a CDROMVOLREAD, return these values */
+       if (cmd == CDROMVOLREAD) {
+               volctrl.channel0 = buffer[offset+9];
+               volctrl.channel1 = buffer[offset+11];
+               volctrl.channel2 = buffer[offset+13];
+               volctrl.channel3 = buffer[offset+15];
+               IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);
+               return 0;
+       }
                
-               /* get the volume mask */
-               cgc.buffer = mask;
-               if ((ret = cdrom_mode_sense(cdi, &cgc, 
-                               GPMODE_AUDIO_CTL_PAGE, 1)))
-                       return ret;
+       /* get the volume mask */
+       cgc->buffer = mask;
+       ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 1);
+       if (ret)
+               return ret;
 
-               buffer[offset+9] = volctrl.channel0 & mask[offset+9];
-               buffer[offset+11] = volctrl.channel1 & mask[offset+11];
-               buffer[offset+13] = volctrl.channel2 & mask[offset+13];
-               buffer[offset+15] = volctrl.channel3 & mask[offset+15];
+       buffer[offset + 9]  = volctrl.channel0 & mask[offset + 9];
+       buffer[offset + 11] = volctrl.channel1 & mask[offset + 11];
+       buffer[offset + 13] = volctrl.channel2 & mask[offset + 13];
+       buffer[offset + 15] = volctrl.channel3 & mask[offset + 15];
 
-               /* set volume */
-               cgc.buffer = buffer + offset - 8;
-               memset(cgc.buffer, 0, 8);
-               return cdrom_mode_select(cdi, &cgc);
-               }
+       /* set volume */
+       cgc->buffer = buffer + offset - 8;
+       memset(cgc->buffer, 0, 8);
+       return cdrom_mode_select(cdi, cgc);
+}
 
-       case CDROMSTART:
-       case CDROMSTOP: {
-               cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); 
-               cgc.cmd[0] = GPCMD_START_STOP_UNIT;
-               cgc.cmd[1] = 1;
-               cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
-               cgc.data_direction = CGC_DATA_NONE;
-               return cdo->generic_packet(cdi, &cgc);
-               }
+static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
+                                       struct packet_command *cgc,
+                                       int cmd)
+{
+       struct cdrom_device_ops *cdo = cdi->ops;
+       cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
+       cgc->cmd[0] = GPCMD_START_STOP_UNIT;
+       cgc->cmd[1] = 1;
+       cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
+       cgc->data_direction = CGC_DATA_NONE;
+       return cdo->generic_packet(cdi, cgc);
+}
 
-       case CDROMPAUSE:
-       case CDROMRESUME: {
-               cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 
-               cgc.cmd[0] = GPCMD_PAUSE_RESUME;
-               cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
-               cgc.data_direction = CGC_DATA_NONE;
-               return cdo->generic_packet(cdi, &cgc);
-               }
+static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
+                                       struct packet_command *cgc,
+                                       int cmd)
+{
+       struct cdrom_device_ops *cdo = cdi->ops;
+       cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
+       cgc->cmd[0] = GPCMD_PAUSE_RESUME;
+       cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
+       cgc->data_direction = CGC_DATA_NONE;
+       return cdo->generic_packet(cdi, cgc);
+}
 
-       case DVD_READ_STRUCT: {
-               dvd_struct *s;
-               int size = sizeof(dvd_struct);
-               if (!CDROM_CAN(CDC_DVD))
-                       return -ENOSYS;
-               if ((s = kmalloc(size, GFP_KERNEL)) == NULL)
-                       return -ENOMEM;
-               cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); 
-               if (copy_from_user(s, (dvd_struct __user *)arg, size)) {
-                       kfree(s);
-                       return -EFAULT;
-               }
-               if ((ret = dvd_read_struct(cdi, s))) {
-                       kfree(s);
-                       return ret;
-               }
-               if (copy_to_user((dvd_struct __user *)arg, s, size))
-                       ret = -EFAULT;
+static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
+                                               void __user *arg,
+                                               struct packet_command *cgc)
+{
+       int ret;
+       dvd_struct *s;
+       int size = sizeof(dvd_struct);
+
+       if (!CDROM_CAN(CDC_DVD))
+               return -ENOSYS;
+
+       s = kmalloc(size, GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
+       if (copy_from_user(s, arg, size)) {
                kfree(s);
+               return -EFAULT;
+       }
+
+       ret = dvd_read_struct(cdi, s, cgc);
+       if (ret)
+               goto out;
+
+       if (copy_to_user(arg, s, size))
+               ret = -EFAULT;
+out:
+       kfree(s);
+       return ret;
+}
+
+static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi,
+                                       void __user *arg)
+{
+       int ret;
+       dvd_authinfo ai;
+       if (!CDROM_CAN(CDC_DVD))
+               return -ENOSYS;
+       cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n");
+       IOCTL_IN(arg, dvd_authinfo, ai);
+       ret = dvd_do_auth(cdi, &ai);
+       if (ret)
                return ret;
-               }
+       IOCTL_OUT(arg, dvd_authinfo, ai);
+       return 0;
+}
 
-       case DVD_AUTH: {
-               dvd_authinfo ai;
-               if (!CDROM_CAN(CDC_DVD))
-                       return -ENOSYS;
-               cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); 
-               IOCTL_IN(arg, dvd_authinfo, ai);
-               if ((ret = dvd_do_auth (cdi, &ai)))
-                       return ret;
-               IOCTL_OUT(arg, dvd_authinfo, ai);
-               return 0;
-               }
+static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi,
+                                               void __user *arg)
+{
+       int ret;
+       long next = 0;
+       cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
+       ret = cdrom_get_next_writable(cdi, &next);
+       if (ret)
+               return ret;
+       IOCTL_OUT(arg, long, next);
+       return 0;
+}
 
-       case CDROM_NEXT_WRITABLE: {
-               long next = 0;
-               cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); 
-               if ((ret = cdrom_get_next_writable(cdi, &next)))
-                       return ret;
-               IOCTL_OUT(arg, long, next);
-               return 0;
-               }
-       case CDROM_LAST_WRITTEN: {
-               long last = 0;
-               cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); 
-               if ((ret = cdrom_get_last_written(cdi, &last)))
-                       return ret;
-               IOCTL_OUT(arg, long, last);
-               return 0;
-               }
-       } /* switch */
+static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi,
+                                               void __user *arg)
+{
+       int ret;
+       long last = 0;
+       cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
+       ret = cdrom_get_last_written(cdi, &last);
+       if (ret)
+               return ret;
+       IOCTL_OUT(arg, long, last);
+       return 0;
+}
+
+static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+                    unsigned long arg)
+{
+       struct packet_command cgc;
+       void __user *userptr = (void __user *)arg;
+
+       memset(&cgc, 0, sizeof(cgc));
+
+       /* build a unified command and queue it through
+          cdo->generic_packet() */
+       switch (cmd) {
+       case CDROMREADRAW:
+       case CDROMREADMODE1:
+       case CDROMREADMODE2:
+               return mmc_ioctl_cdrom_read_data(cdi, userptr, &cgc, cmd);
+       case CDROMREADAUDIO:
+               return mmc_ioctl_cdrom_read_audio(cdi, userptr);
+       case CDROMSUBCHNL:
+               return mmc_ioctl_cdrom_subchannel(cdi, userptr);
+       case CDROMPLAYMSF:
+               return mmc_ioctl_cdrom_play_msf(cdi, userptr, &cgc);
+       case CDROMPLAYBLK:
+               return mmc_ioctl_cdrom_play_blk(cdi, userptr, &cgc);
+       case CDROMVOLCTRL:
+       case CDROMVOLREAD:
+               return mmc_ioctl_cdrom_volume(cdi, userptr, &cgc, cmd);
+       case CDROMSTART:
+       case CDROMSTOP:
+               return mmc_ioctl_cdrom_start_stop(cdi, &cgc, cmd);
+       case CDROMPAUSE:
+       case CDROMRESUME:
+               return mmc_ioctl_cdrom_pause_resume(cdi, &cgc, cmd);
+       case DVD_READ_STRUCT:
+               return mmc_ioctl_dvd_read_struct(cdi, userptr, &cgc);
+       case DVD_AUTH:
+               return mmc_ioctl_dvd_auth(cdi, userptr);
+       case CDROM_NEXT_WRITABLE:
+               return mmc_ioctl_cdrom_next_writable(cdi, userptr);
+       case CDROM_LAST_WRITTEN:
+               return mmc_ioctl_cdrom_last_written(cdi, userptr);
+       }
 
        return -ENOTTY;
 }
index 9cf6e9bb017e6dca0b537bb04b70e5c49dbf705b..c7714185f83103219de72565f34a3dadbb6e198d 100644 (file)
@@ -40,6 +40,8 @@
 #define PCI_DEVICE_ID_INTEL_Q45_IG          0x2E12
 #define PCI_DEVICE_ID_INTEL_G45_HB          0x2E20
 #define PCI_DEVICE_ID_INTEL_G45_IG          0x2E22
+#define PCI_DEVICE_ID_INTEL_G41_HB          0x2E30
+#define PCI_DEVICE_ID_INTEL_G41_IG          0x2E32
 
 /* cover 915 and 945 variants */
 #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
@@ -63,7 +65,8 @@
 #define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_E_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
                agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
-               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB)
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
+               agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB)
 
 extern int agp_memory_reserved;
 
@@ -1196,6 +1199,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
        case PCI_DEVICE_ID_INTEL_IGD_E_HB:
        case PCI_DEVICE_ID_INTEL_Q45_HB:
        case PCI_DEVICE_ID_INTEL_G45_HB:
+       case PCI_DEVICE_ID_INTEL_G41_HB:
                *gtt_offset = *gtt_size = MB(2);
                break;
        default:
@@ -2156,13 +2160,15 @@ static const struct intel_driver_description {
        { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
                NULL, &intel_g33_driver },
        { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
-           "Mobile Intel? GM45 Express", NULL, &intel_i965_driver },
+           "Mobile Intel® GM45 Express", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_IGD_E_HB, PCI_DEVICE_ID_INTEL_IGD_E_IG, 0,
            "Intel Integrated Graphics Device", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0,
            "Q45/Q43", NULL, &intel_i965_driver },
        { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
            "G45/G43", NULL, &intel_i965_driver },
+       { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
+           "G41", NULL, &intel_i965_driver },
        { 0, 0, 0, NULL, NULL, NULL }
 };
 
@@ -2360,6 +2366,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_IGD_E_HB),
        ID(PCI_DEVICE_ID_INTEL_Q45_HB),
        ID(PCI_DEVICE_ID_INTEL_G45_HB),
+       ID(PCI_DEVICE_ID_INTEL_G41_HB),
        { }
 };
 
index 74e9cd81b5b253b8139d9fbc6ceea59afeb77c27..61f0146e215dd30ff3203b65e2ca75960928d39b 100644 (file)
@@ -43,52 +43,51 @@ static const char *fan_state[] = { "off", "on", "on (hardwired)" };
  *  chance that the WaveArtist driver could touch these bits to
  *  enable or disable the speaker.
  */
-extern spinlock_t gpio_lock;
 extern unsigned int system_rev;
 
 static inline void netwinder_ds1620_set_clk(int clk)
 {
-       gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0);
+       nw_gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0);
 }
 
 static inline void netwinder_ds1620_set_data(int dat)
 {
-       gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0);
+       nw_gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0);
 }
 
 static inline int netwinder_ds1620_get_data(void)
 {
-       return gpio_read() & GPIO_DATA;
+       return nw_gpio_read() & GPIO_DATA;
 }
 
 static inline void netwinder_ds1620_set_data_dir(int dir)
 {
-       gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0);
+       nw_gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0);
 }
 
 static inline void netwinder_ds1620_reset(void)
 {
-       cpld_modify(CPLD_DS_ENABLE, 0);
-       cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE);
+       nw_cpld_modify(CPLD_DS_ENABLE, 0);
+       nw_cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE);
 }
 
 static inline void netwinder_lock(unsigned long *flags)
 {
-       spin_lock_irqsave(&gpio_lock, *flags);
+       spin_lock_irqsave(&nw_gpio_lock, *flags);
 }
 
 static inline void netwinder_unlock(unsigned long *flags)
 {
-       spin_unlock_irqrestore(&gpio_lock, *flags);
+       spin_unlock_irqrestore(&nw_gpio_lock, *flags);
 }
 
 static inline void netwinder_set_fan(int i)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&gpio_lock, flags);
-       gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0);
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
 }
 
 static inline int netwinder_get_fan(void)
@@ -96,7 +95,7 @@ static inline int netwinder_get_fan(void)
        if ((system_rev & 0xf000) == 0x4000)
                return FAN_ALWAYS_ON;
 
-       return (gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF;
+       return (nw_gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF;
 }
 
 /*
index 53fdc7ff387051507ade9def9a75eb67ff1bfd13..32b8bbf5003e17678a996e50ccb2c9b38d018886 100644 (file)
@@ -46,7 +46,7 @@
 /*
  * The High Precision Event Timer driver.
  * This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/hardwaredesign/hpetspec.htm
+ * http://www.intel.com/hardwaredesign/hpetspec_1.pdf
  */
 #define        HPET_USER_FREQ  (64)
 #define        HPET_DRIFT      (500)
index fb57f67bb427fb86e23e9b6c723ba3fcae467ea9..0587b66d6fc7070225e7f493517cc30cac11cfdc 100644 (file)
@@ -695,6 +695,7 @@ void hvc_resize(struct hvc_struct *hp, struct winsize ws)
        hp->ws = ws;
        schedule_work(&hp->tty_resize);
 }
+EXPORT_SYMBOL_GPL(hvc_resize);
 
 /*
  * This kthread is either polling or interrupt driven.  This is determined by
index 006be92ee3f3f9cf36ba5682c7819623aabef0f2..8c7df5ba088f5e05fee54e507602463b15cddbf7 100644 (file)
@@ -58,8 +58,6 @@ static volatile unsigned char *FLASH_BASE;
 static int gbFlashSize = KFLASH_SIZE;
 static DEFINE_MUTEX(nwflash_mutex);
 
-extern spinlock_t gpio_lock;
-
 static int get_flash_id(void)
 {
        volatile unsigned int c1, c2;
@@ -616,9 +614,9 @@ static void kick_open(void)
         * we want to write a bit pattern XXX1 to Xilinx to enable
         * the write gate, which will be open for about the next 2ms.
         */
-       spin_lock_irqsave(&gpio_lock, flags);
-       cpld_modify(1, 1);
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
 
        /*
         * let the ISA bus to catch on...
index 675076f5fca881d0ab3752b44c8356766dac1c3a..d26891bfcd4154effba426421322ed053acb9d9b 100644 (file)
@@ -558,23 +558,9 @@ struct timer_rand_state {
        unsigned dont_count_entropy:1;
 };
 
-static struct timer_rand_state *irq_timer_state[NR_IRQS];
-
-static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
-{
-       if (irq >= nr_irqs)
-               return NULL;
-
-       return irq_timer_state[irq];
-}
-
-static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
-{
-       if (irq >= nr_irqs)
-               return;
-
-       irq_timer_state[irq] = state;
-}
+#ifndef CONFIG_SPARSE_IRQ
+struct timer_rand_state *irq_timer_state[NR_IRQS];
+#endif
 
 static struct timer_rand_state input_timer_state;
 
@@ -933,8 +919,10 @@ void rand_initialize_irq(int irq)
 {
        struct timer_rand_state *state;
 
+#ifndef CONFIG_SPARSE_IRQ
        if (irq >= nr_irqs)
                return;
+#endif
 
        state = get_timer_rand_state(irq);
 
index 3fb0d2c88ba5fd3252bf7d773c8ecdaafc9de395..ff6f5a4b58fb5acd25622ad4fdd1b1a9c45b15f0 100644 (file)
@@ -137,13 +137,34 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
        return hvc_instantiate(0, 0, &virtio_cons);
 }
 
+/*
+ * virtio console configuration. This supports:
+ * - console resize
+ */
+static void virtcons_apply_config(struct virtio_device *dev)
+{
+       struct winsize ws;
+
+       if (virtio_has_feature(dev, VIRTIO_CONSOLE_F_SIZE)) {
+               dev->config->get(dev,
+                                offsetof(struct virtio_console_config, cols),
+                                &ws.ws_col, sizeof(u16));
+               dev->config->get(dev,
+                                offsetof(struct virtio_console_config, rows),
+                                &ws.ws_row, sizeof(u16));
+               hvc_resize(hvc, ws);
+       }
+}
+
 /*
  * we support only one console, the hvc struct is a global var
- * There is no need to do anything
+ * We set the configuration at this point, since we now have a tty
  */
 static int notifier_add_vio(struct hvc_struct *hp, int data)
 {
        hp->irq_requested = 1;
+       virtcons_apply_config(vdev);
+
        return 0;
 }
 
@@ -234,11 +255,18 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+static unsigned int features[] = {
+       VIRTIO_CONSOLE_F_SIZE,
+};
+
 static struct virtio_driver virtio_console = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
        .probe =        virtcons_probe,
+       .config_changed = virtcons_apply_config,
 };
 
 static int __init init(void)
index c20171078d1d6f475f04a23fc0be9e63101d5d76..e1129fad96dd2c75a20cc283dc6e53045b3a553d 100644 (file)
@@ -57,11 +57,6 @@ u32 acpi_pm_read_verified(void)
        return v2;
 }
 
-static cycle_t acpi_pm_read_slow(void)
-{
-       return (cycle_t)acpi_pm_read_verified();
-}
-
 static cycle_t acpi_pm_read(void)
 {
        return (cycle_t)read_pmtmr();
@@ -88,6 +83,11 @@ static int __init acpi_pm_good_setup(char *__str)
 }
 __setup("acpi_pm_good", acpi_pm_good_setup);
 
+static cycle_t acpi_pm_read_slow(void)
+{
+       return (cycle_t)acpi_pm_read_verified();
+}
+
 static inline void acpi_pm_need_workaround(void)
 {
        clocksource_acpi_pm.read = acpi_pm_read_slow;
index 4a597d8c2f708ae4bb0e52a7c16a4fe0a0891092..78b989d202a35e3d0c46b05b9267c762c5e7b6cc 100644 (file)
@@ -582,3 +582,19 @@ int dmi_walk(void (*decode)(const struct dmi_header *))
        return 0;
 }
 EXPORT_SYMBOL_GPL(dmi_walk);
+
+/**
+ * dmi_match - compare a string to the dmi field (if exists)
+ *
+ * Returns true if the requested field equals to the str (including NULL).
+ */
+bool dmi_match(enum dmi_field f, const char *str)
+{
+       const char *info = dmi_get_system_info(f);
+
+       if (info == NULL || str == NULL)
+               return info == str;
+
+       return !strcmp(info, str);
+}
+EXPORT_SYMBOL_GPL(dmi_match);
index a8b33c2ec8d2fa951a4b81509cf944eb0e4759af..5130b72d593c5726e34263ad0d63eb248b1265f6 100644 (file)
@@ -7,6 +7,8 @@
 menuconfig DRM
        tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
        depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
+       select I2C
+       select I2C_ALGOBIT
        help
          Kernel-level support for the Direct Rendering Infrastructure (DRI)
          introduced in XFree86 4.0. If you say Y here, you need to select
@@ -65,6 +67,10 @@ config DRM_I830
          will load the correct one.
 
 config DRM_I915
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       depends on FB
        tristate "i915 driver"
        help
          Choose this option if you have a system that has Intel 830M, 845G,
@@ -76,6 +82,17 @@ config DRM_I915
 
 endchoice
 
+config DRM_I915_KMS
+       bool "Enable modesetting on intel by default"
+       depends on DRM_I915
+       help
+       Choose this option if you want kernel modesetting enabled by default,
+       and you have a new enough userspace to support this. Running old
+       userspaces with this enabled will cause pain.  Note that this causes
+       the driver to bind to PCI devices, which precludes loading things
+       like intelfb.
+
+
 config DRM_MGA
        tristate "Matrox g200/g400"
        depends on DRM
index 74da99495e21d8cbce22853d5e943d2b5e37e647..30022c4a5c12a0be54aef5cfb7b0fddd7abd06df 100644 (file)
@@ -9,7 +9,8 @@ drm-y       :=  drm_auth.o drm_bufs.o drm_cache.o \
                drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
                drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
                drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
-               drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
+               drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
+               drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
index a73462723d2d517d2c7af88cb46880b9024ee354..ca7a9ef5007b3c383f05f6e8969dfb37c1368408 100644 (file)
  * the one with matching magic number, while holding the drm_device::struct_mutex
  * lock.
  */
-static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic)
+static struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic)
 {
        struct drm_file *retval = NULL;
        struct drm_magic_entry *pt;
        struct drm_hash_item *hash;
+       struct drm_device *dev = master->minor->dev;
 
        mutex_lock(&dev->struct_mutex);
-       if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+       if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
                pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
                retval = pt->priv;
        }
@@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic
  * associated the magic number hash key in drm_device::magiclist, while holding
  * the drm_device::struct_mutex lock.
  */
-static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
+static int drm_add_magic(struct drm_master *master, struct drm_file *priv,
                         drm_magic_t magic)
 {
        struct drm_magic_entry *entry;
-
+       struct drm_device *dev = master->minor->dev;
        DRM_DEBUG("%d\n", magic);
 
        entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
@@ -83,11 +84,10 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
                return -ENOMEM;
        memset(entry, 0, sizeof(*entry));
        entry->priv = priv;
-
        entry->hash_item.key = (unsigned long)magic;
        mutex_lock(&dev->struct_mutex);
-       drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
-       list_add_tail(&entry->head, &dev->magicfree);
+       drm_ht_insert_item(&master->magiclist, &entry->hash_item);
+       list_add_tail(&entry->head, &master->magicfree);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -102,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
  * Searches and unlinks the entry in drm_device::magiclist with the magic
  * number hash key, while holding the drm_device::struct_mutex lock.
  */
-static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic)
+static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
 {
        struct drm_magic_entry *pt;
        struct drm_hash_item *hash;
+       struct drm_device *dev = master->minor->dev;
 
        DRM_DEBUG("%d\n", magic);
 
        mutex_lock(&dev->struct_mutex);
-       if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+       if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
                mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
        pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
-       drm_ht_remove_item(&dev->magiclist, hash);
+       drm_ht_remove_item(&master->magiclist, hash);
        list_del(&pt->head);
        mutex_unlock(&dev->struct_mutex);
 
@@ -153,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
                                ++sequence;     /* reserve 0 */
                        auth->magic = sequence++;
                        spin_unlock(&lock);
-               } while (drm_find_file(dev, auth->magic));
+               } while (drm_find_file(file_priv->master, auth->magic));
                file_priv->magic = auth->magic;
-               drm_add_magic(dev, file_priv, auth->magic);
+               drm_add_magic(file_priv->master, file_priv, auth->magic);
        }
 
        DRM_DEBUG("%u\n", auth->magic);
@@ -181,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data,
        struct drm_file *file;
 
        DRM_DEBUG("%u\n", auth->magic);
-       if ((file = drm_find_file(dev, auth->magic))) {
+       if ((file = drm_find_file(file_priv->master, auth->magic))) {
                file->authenticated = 1;
-               drm_remove_magic(dev, auth->magic);
+               drm_remove_magic(file_priv->master, auth->magic);
                return 0;
        }
        return -EINVAL;
index bde64b84166e1d783a2c5a8ece1816c483e76f0b..72c667f9bee1aadbc4067687d05aca0849be751b 100644 (file)
@@ -54,9 +54,9 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
 {
        struct drm_map_list *entry;
        list_for_each_entry(entry, &dev->maplist, head) {
-               if (entry->map && map->type == entry->map->type &&
+               if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
                    ((entry->map->offset == map->offset) ||
-                    (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
+                    ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
                        return entry;
                }
        }
@@ -210,12 +210,12 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                map->offset = (unsigned long)map->handle;
                if (map->flags & _DRM_CONTAINS_LOCK) {
                        /* Prevent a 2nd X Server from creating a 2nd lock */
-                       if (dev->lock.hw_lock != NULL) {
+                       if (dev->primary->master->lock.hw_lock != NULL) {
                                vfree(map->handle);
                                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                                return -EBUSY;
                        }
-                       dev->sigdata.lock = dev->lock.hw_lock = map->handle;    /* Pointer to lock */
+                       dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle;   /* Pointer to lock */
                }
                break;
        case _DRM_AGP: {
@@ -261,6 +261,9 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
                }
                DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
 
+               break;
+       case _DRM_GEM:
+               DRM_ERROR("tried to rmmap GEM object\n");
                break;
        }
        case _DRM_SCATTER_GATHER:
@@ -319,6 +322,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
        list->user_token = list->hash.key << PAGE_SHIFT;
        mutex_unlock(&dev->struct_mutex);
 
+       list->master = dev->primary->master;
        *maplist = list;
        return 0;
        }
@@ -345,7 +349,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
        struct drm_map_list *maplist;
        int err;
 
-       if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP))
+       if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM))
                return -EPERM;
 
        err = drm_addmap_core(dev, map->offset, map->size, map->type,
@@ -380,10 +384,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
        struct drm_map_list *r_list = NULL, *list_t;
        drm_dma_handle_t dmah;
        int found = 0;
+       struct drm_master *master;
 
        /* Find the list entry for the map and remove it */
        list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
                if (r_list->map == map) {
+                       master = r_list->master;
                        list_del(&r_list->head);
                        drm_ht_remove_key(&dev->map_hash,
                                          r_list->user_token >> PAGE_SHIFT);
@@ -409,6 +415,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
                break;
        case _DRM_SHM:
                vfree(map->handle);
+               if (master) {
+                       if (dev->sigdata.lock == master->lock.hw_lock)
+                               dev->sigdata.lock = NULL;
+                       master->lock.hw_lock = NULL;   /* SHM removed */
+                       master->lock.file_priv = NULL;
+                       wake_up_interruptible(&master->lock.lock_queue);
+               }
                break;
        case _DRM_AGP:
        case _DRM_SCATTER_GATHER:
@@ -419,11 +432,15 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
                dmah.size = map->size;
                __drm_pci_free(dev, &dmah);
                break;
+       case _DRM_GEM:
+               DRM_ERROR("tried to rmmap GEM object\n");
+               break;
        }
        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
 
        return 0;
 }
+EXPORT_SYMBOL(drm_rmmap_locked);
 
 int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
 {
index d505f695421fbeff447435c450a2882e40133227..809ec0f034524506ef0b4cef13e4d60b89fa10d3 100644 (file)
@@ -256,12 +256,13 @@ static int drm_context_switch(struct drm_device * dev, int old, int new)
  * hardware lock is held, clears the drm_device::context_flag and wakes up
  * drm_device::context_wait.
  */
-static int drm_context_switch_complete(struct drm_device * dev, int new)
+static int drm_context_switch_complete(struct drm_device *dev,
+                                      struct drm_file *file_priv, int new)
 {
        dev->last_context = new;        /* PRE/POST: This is the _only_ writer. */
        dev->last_switch = jiffies;
 
-       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+       if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
                DRM_ERROR("Lock isn't held after context switch\n");
        }
 
@@ -420,7 +421,7 @@ int drm_newctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        DRM_DEBUG("%d\n", ctx->handle);
-       drm_context_switch_complete(dev, ctx->handle);
+       drm_context_switch_complete(dev, file_priv, ctx->handle);
 
        return 0;
 }
@@ -442,9 +443,6 @@ int drm_rmctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        DRM_DEBUG("%d\n", ctx->handle);
-       if (ctx->handle == DRM_KERNEL_CONTEXT + 1) {
-               file_priv->remove_auth_on_close = 1;
-       }
        if (ctx->handle != DRM_KERNEL_CONTEXT) {
                if (dev->driver->context_dtor)
                        dev->driver->context_dtor(dev, ctx->handle);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
new file mode 100644 (file)
index 0000000..53c8725
--- /dev/null
@@ -0,0 +1,2446 @@
+/*
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2008 Red Hat Inc.
+ *
+ * DRM core CRTC related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ *      Keith Packard
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+#include <linux/list.h>
+#include "drm.h"
+#include "drmP.h"
+#include "drm_crtc.h"
+
+struct drm_prop_enum_list {
+       int type;
+       char *name;
+};
+
+/* Avoid boilerplate.  I'm tired of typing. */
+#define DRM_ENUM_NAME_FN(fnname, list)                         \
+       char *fnname(int val)                                   \
+       {                                                       \
+               int i;                                          \
+               for (i = 0; i < ARRAY_SIZE(list); i++) {        \
+                       if (list[i].type == val)                \
+                               return list[i].name;            \
+               }                                               \
+               return "(unknown)";                             \
+       }
+
+/*
+ * Global properties
+ */
+static struct drm_prop_enum_list drm_dpms_enum_list[] =
+{      { DRM_MODE_DPMS_ON, "On" },
+       { DRM_MODE_DPMS_STANDBY, "Standby" },
+       { DRM_MODE_DPMS_SUSPEND, "Suspend" },
+       { DRM_MODE_DPMS_OFF, "Off" }
+};
+
+DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
+
+/*
+ * Optional properties
+ */
+static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
+{
+       { DRM_MODE_SCALE_NON_GPU, "Non-GPU" },
+       { DRM_MODE_SCALE_FULLSCREEN, "Fullscreen" },
+       { DRM_MODE_SCALE_NO_SCALE, "No scale" },
+       { DRM_MODE_SCALE_ASPECT, "Aspect" },
+};
+
+static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
+{
+       { DRM_MODE_DITHERING_OFF, "Off" },
+       { DRM_MODE_DITHERING_ON, "On" },
+};
+
+/*
+ * Non-global properties, but "required" for certain connectors.
+ */
+static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
+       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
+};
+
+DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
+
+static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_DVID,      "DVI-D"     }, /* DVI-I  */
+       { DRM_MODE_SUBCONNECTOR_DVIA,      "DVI-A"     }, /* DVI-I  */
+};
+
+DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
+                drm_dvi_i_subconnector_enum_list)
+
+static struct drm_prop_enum_list drm_tv_select_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+};
+
+DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
+
+static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
+{
+       { DRM_MODE_SUBCONNECTOR_Unknown,   "Unknown"   }, /* DVI-I and TV-out */
+       { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_SVIDEO,    "SVIDEO"    }, /* TV-out */
+       { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */
+};
+
+DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
+                drm_tv_subconnector_enum_list)
+
+struct drm_conn_prop_enum_list {
+       int type;
+       char *name;
+       int count;
+};
+
+/*
+ * Connector and encoder types.
+ */
+static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
+{      { DRM_MODE_CONNECTOR_Unknown, "Unknown", 0 },
+       { DRM_MODE_CONNECTOR_VGA, "VGA", 0 },
+       { DRM_MODE_CONNECTOR_DVII, "DVI-I", 0 },
+       { DRM_MODE_CONNECTOR_DVID, "DVI-D", 0 },
+       { DRM_MODE_CONNECTOR_DVIA, "DVI-A", 0 },
+       { DRM_MODE_CONNECTOR_Composite, "Composite", 0 },
+       { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
+       { DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
+       { DRM_MODE_CONNECTOR_Component, "Component", 0 },
+       { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 },
+       { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 },
+       { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 },
+       { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 },
+};
+
+static struct drm_prop_enum_list drm_encoder_enum_list[] =
+{      { DRM_MODE_ENCODER_NONE, "None" },
+       { DRM_MODE_ENCODER_DAC, "DAC" },
+       { DRM_MODE_ENCODER_TMDS, "TMDS" },
+       { DRM_MODE_ENCODER_LVDS, "LVDS" },
+       { DRM_MODE_ENCODER_TVDAC, "TV" },
+};
+
+char *drm_get_encoder_name(struct drm_encoder *encoder)
+{
+       static char buf[32];
+
+       snprintf(buf, 32, "%s-%d",
+                drm_encoder_enum_list[encoder->encoder_type].name,
+                encoder->base.id);
+       return buf;
+}
+
+char *drm_get_connector_name(struct drm_connector *connector)
+{
+       static char buf[32];
+
+       snprintf(buf, 32, "%s-%d",
+                drm_connector_enum_list[connector->connector_type].name,
+                connector->connector_type_id);
+       return buf;
+}
+EXPORT_SYMBOL(drm_get_connector_name);
+
+char *drm_get_connector_status_name(enum drm_connector_status status)
+{
+       if (status == connector_status_connected)
+               return "connected";
+       else if (status == connector_status_disconnected)
+               return "disconnected";
+       else
+               return "unknown";
+}
+
+/**
+ * drm_mode_object_get - allocate a new identifier
+ * @dev: DRM device
+ * @ptr: object pointer, used to generate unique ID
+ * @type: object type
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Create a unique identifier based on @ptr in @dev's identifier space.  Used
+ * for tracking modes, CRTCs and connectors.
+ *
+ * RETURNS:
+ * New unique (relative to other objects in @dev) integer identifier for the
+ * object.
+ */
+static int drm_mode_object_get(struct drm_device *dev,
+                              struct drm_mode_object *obj, uint32_t obj_type)
+{
+       int new_id = 0;
+       int ret;
+
+       WARN(!mutex_is_locked(&dev->mode_config.mutex),
+            "%s called w/o mode_config lock\n", __FUNCTION__);
+again:
+       if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
+               DRM_ERROR("Ran out memory getting a mode number\n");
+               return -EINVAL;
+       }
+
+       ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id);
+       if (ret == -EAGAIN)
+               goto again;
+
+       obj->id = new_id;
+       obj->type = obj_type;
+       return 0;
+}
+
+/**
+ * drm_mode_object_put - free an identifer
+ * @dev: DRM device
+ * @id: ID to free
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Free @id from @dev's unique identifier pool.
+ */
+static void drm_mode_object_put(struct drm_device *dev,
+                               struct drm_mode_object *object)
+{
+       idr_remove(&dev->mode_config.crtc_idr, object->id);
+}
+
+void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type)
+{
+       struct drm_mode_object *obj;
+
+       obj = idr_find(&dev->mode_config.crtc_idr, id);
+       if (!obj || (obj->type != type) || (obj->id != id))
+               return NULL;
+
+       return obj;
+}
+EXPORT_SYMBOL(drm_mode_object_find);
+
+/**
+ * drm_crtc_from_fb - find the CRTC structure associated with an fb
+ * @dev: DRM device
+ * @fb: framebuffer in question
+ *
+ * LOCKING:
+ * Caller must hold mode_config lock.
+ *
+ * Find CRTC in the mode_config structure that matches @fb.
+ *
+ * RETURNS:
+ * Pointer to the CRTC or NULL if it wasn't found.
+ */
+struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev,
+                                 struct drm_framebuffer *fb)
+{
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (crtc->fb == fb)
+                       return crtc;
+       }
+       return NULL;
+}
+
+/**
+ * drm_framebuffer_init - initialize a framebuffer
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Allocates an ID for the framebuffer's parent mode object, sets its mode
+ * functions & device file and adds it to the master fd list.
+ *
+ * RETURNS:
+ * Zero on success, error code on falure.
+ */
+int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
+                        const struct drm_framebuffer_funcs *funcs)
+{
+       int ret;
+
+       ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
+       if (ret) {
+               return ret;
+       }
+
+       fb->dev = dev;
+       fb->funcs = funcs;
+       dev->mode_config.num_fb++;
+       list_add(&fb->head, &dev->mode_config.fb_list);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_framebuffer_init);
+
+/**
+ * drm_framebuffer_cleanup - remove a framebuffer object
+ * @fb: framebuffer to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Scans all the CRTCs in @dev's mode_config.  If they're using @fb, removes
+ * it, setting it to NULL.
+ */
+void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
+{
+       struct drm_device *dev = fb->dev;
+       struct drm_crtc *crtc;
+
+       /* remove from any CRTC */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (crtc->fb == fb)
+                       crtc->fb = NULL;
+       }
+
+       drm_mode_object_put(dev, &fb->base);
+       list_del(&fb->head);
+       dev->mode_config.num_fb--;
+}
+EXPORT_SYMBOL(drm_framebuffer_cleanup);
+
+/**
+ * drm_crtc_init - Initialise a new CRTC object
+ * @dev: DRM device
+ * @crtc: CRTC object to init
+ * @funcs: callbacks for the new CRTC
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Inits a new object created as base part of an driver crtc object.
+ */
+void drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                  const struct drm_crtc_funcs *funcs)
+{
+       crtc->dev = dev;
+       crtc->funcs = funcs;
+
+       mutex_lock(&dev->mode_config.mutex);
+       drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
+
+       list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
+       dev->mode_config.num_crtc++;
+       mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_crtc_init);
+
+/**
+ * drm_crtc_cleanup - Cleans up the core crtc usage.
+ * @crtc: CRTC to cleanup
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Cleanup @crtc. Removes from drm modesetting space
+ * does NOT free object, caller does that.
+ */
+void drm_crtc_cleanup(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+
+       if (crtc->gamma_store) {
+               kfree(crtc->gamma_store);
+               crtc->gamma_store = NULL;
+       }
+
+       drm_mode_object_put(dev, &crtc->base);
+       list_del(&crtc->head);
+       dev->mode_config.num_crtc--;
+}
+EXPORT_SYMBOL(drm_crtc_cleanup);
+
+/**
+ * drm_mode_probed_add - add a mode to a connector's probed mode list
+ * @connector: connector the new mode
+ * @mode: mode data
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Add @mode to @connector's mode list for later use.
+ */
+void drm_mode_probed_add(struct drm_connector *connector,
+                        struct drm_display_mode *mode)
+{
+       list_add(&mode->head, &connector->probed_modes);
+}
+EXPORT_SYMBOL(drm_mode_probed_add);
+
+/**
+ * drm_mode_remove - remove and free a mode
+ * @connector: connector list to modify
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Remove @mode from @connector's mode list, then free it.
+ */
+void drm_mode_remove(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
+{
+       list_del(&mode->head);
+       kfree(mode);
+}
+EXPORT_SYMBOL(drm_mode_remove);
+
+/**
+ * drm_connector_init - Init a preallocated connector
+ * @dev: DRM device
+ * @connector: the connector to init
+ * @funcs: callbacks for this connector
+ * @name: user visible name of the connector
+ *
+ * LOCKING:
+ * Caller must hold @dev's mode_config lock.
+ *
+ * Initialises a preallocated connector. Connectors should be
+ * subclassed as part of driver connector objects.
+ */
+void drm_connector_init(struct drm_device *dev,
+                    struct drm_connector *connector,
+                    const struct drm_connector_funcs *funcs,
+                    int connector_type)
+{
+       mutex_lock(&dev->mode_config.mutex);
+
+       connector->dev = dev;
+       connector->funcs = funcs;
+       drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
+       connector->connector_type = connector_type;
+       connector->connector_type_id =
+               ++drm_connector_enum_list[connector_type].count; /* TODO */
+       INIT_LIST_HEAD(&connector->user_modes);
+       INIT_LIST_HEAD(&connector->probed_modes);
+       INIT_LIST_HEAD(&connector->modes);
+       connector->edid_blob_ptr = NULL;
+
+       list_add_tail(&connector->head, &dev->mode_config.connector_list);
+       dev->mode_config.num_connector++;
+
+       drm_connector_attach_property(connector,
+                                     dev->mode_config.edid_property, 0);
+
+       drm_connector_attach_property(connector,
+                                     dev->mode_config.dpms_property, 0);
+
+       mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_connector_init);
+
+/**
+ * drm_connector_cleanup - cleans up an initialised connector
+ * @connector: connector to cleanup
+ *
+ * LOCKING:
+ * Caller must hold @dev's mode_config lock.
+ *
+ * Cleans up the connector but doesn't free the object.
+ */
+void drm_connector_cleanup(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode, *t;
+
+       list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
+               drm_mode_remove(connector, mode);
+
+       list_for_each_entry_safe(mode, t, &connector->modes, head)
+               drm_mode_remove(connector, mode);
+
+       list_for_each_entry_safe(mode, t, &connector->user_modes, head)
+               drm_mode_remove(connector, mode);
+
+       mutex_lock(&dev->mode_config.mutex);
+       drm_mode_object_put(dev, &connector->base);
+       list_del(&connector->head);
+       mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_connector_cleanup);
+
+void drm_encoder_init(struct drm_device *dev,
+                     struct drm_encoder *encoder,
+                     const struct drm_encoder_funcs *funcs,
+                     int encoder_type)
+{
+       mutex_lock(&dev->mode_config.mutex);
+
+       encoder->dev = dev;
+
+       drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
+       encoder->encoder_type = encoder_type;
+       encoder->funcs = funcs;
+
+       list_add_tail(&encoder->head, &dev->mode_config.encoder_list);
+       dev->mode_config.num_encoder++;
+
+       mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_encoder_init);
+
+void drm_encoder_cleanup(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       mutex_lock(&dev->mode_config.mutex);
+       drm_mode_object_put(dev, &encoder->base);
+       list_del(&encoder->head);
+       mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_encoder_cleanup);
+
+/**
+ * drm_mode_create - create a new display mode
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Create a new drm_display_mode, give it an ID, and return it.
+ *
+ * RETURNS:
+ * Pointer to new mode on success, NULL on error.
+ */
+struct drm_display_mode *drm_mode_create(struct drm_device *dev)
+{
+       struct drm_display_mode *nmode;
+
+       nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+       if (!nmode)
+               return NULL;
+
+       drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE);
+       return nmode;
+}
+EXPORT_SYMBOL(drm_mode_create);
+
+/**
+ * drm_mode_destroy - remove a mode
+ * @dev: DRM device
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Free @mode's unique identifier, then free it.
+ */
+void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       drm_mode_object_put(dev, &mode->base);
+
+       kfree(mode);
+}
+EXPORT_SYMBOL(drm_mode_destroy);
+
+static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
+{
+       struct drm_property *edid;
+       struct drm_property *dpms;
+       int i;
+
+       /*
+        * Standard properties (apply to all connectors)
+        */
+       edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+                                  DRM_MODE_PROP_IMMUTABLE,
+                                  "EDID", 0);
+       dev->mode_config.edid_property = edid;
+
+       dpms = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                  "DPMS", ARRAY_SIZE(drm_dpms_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++)
+               drm_property_add_enum(dpms, i, drm_dpms_enum_list[i].type,
+                                     drm_dpms_enum_list[i].name);
+       dev->mode_config.dpms_property = dpms;
+
+       return 0;
+}
+
+/**
+ * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
+ * @dev: DRM device
+ *
+ * Called by a driver the first time a DVI-I connector is made.
+ */
+int drm_mode_create_dvi_i_properties(struct drm_device *dev)
+{
+       struct drm_property *dvi_i_selector;
+       struct drm_property *dvi_i_subconnector;
+       int i;
+
+       if (dev->mode_config.dvi_i_select_subconnector_property)
+               return 0;
+
+       dvi_i_selector =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                   "select subconnector",
+                                   ARRAY_SIZE(drm_dvi_i_select_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_dvi_i_select_enum_list); i++)
+               drm_property_add_enum(dvi_i_selector, i,
+                                     drm_dvi_i_select_enum_list[i].type,
+                                     drm_dvi_i_select_enum_list[i].name);
+       dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector;
+
+       dvi_i_subconnector =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM |
+                                   DRM_MODE_PROP_IMMUTABLE,
+                                   "subconnector",
+                                   ARRAY_SIZE(drm_dvi_i_subconnector_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_dvi_i_subconnector_enum_list); i++)
+               drm_property_add_enum(dvi_i_subconnector, i,
+                                     drm_dvi_i_subconnector_enum_list[i].type,
+                                     drm_dvi_i_subconnector_enum_list[i].name);
+       dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_dvi_i_properties);
+
+/**
+ * drm_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @num_modes: number of different TV formats (modes) supported
+ * @modes: array of pointers to strings containing name of each format
+ *
+ * Called by a driver's TV initialization routine, this function creates
+ * the TV specific connector properties for a given device.  Caller is
+ * responsible for allocating a list of format names and passing them to
+ * this routine.
+ */
+int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes,
+                                 char *modes[])
+{
+       struct drm_property *tv_selector;
+       struct drm_property *tv_subconnector;
+       int i;
+
+       if (dev->mode_config.tv_select_subconnector_property)
+               return 0;
+
+       /*
+        * Basic connector properties
+        */
+       tv_selector = drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                         "select subconnector",
+                                         ARRAY_SIZE(drm_tv_select_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_tv_select_enum_list); i++)
+               drm_property_add_enum(tv_selector, i,
+                                     drm_tv_select_enum_list[i].type,
+                                     drm_tv_select_enum_list[i].name);
+       dev->mode_config.tv_select_subconnector_property = tv_selector;
+
+       tv_subconnector =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM |
+                                   DRM_MODE_PROP_IMMUTABLE, "subconnector",
+                                   ARRAY_SIZE(drm_tv_subconnector_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_tv_subconnector_enum_list); i++)
+               drm_property_add_enum(tv_subconnector, i,
+                                     drm_tv_subconnector_enum_list[i].type,
+                                     drm_tv_subconnector_enum_list[i].name);
+       dev->mode_config.tv_subconnector_property = tv_subconnector;
+
+       /*
+        * Other, TV specific properties: margins & TV modes.
+        */
+       dev->mode_config.tv_left_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "left margin", 2);
+       dev->mode_config.tv_left_margin_property->values[0] = 0;
+       dev->mode_config.tv_left_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_right_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "right margin", 2);
+       dev->mode_config.tv_right_margin_property->values[0] = 0;
+       dev->mode_config.tv_right_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_top_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "top margin", 2);
+       dev->mode_config.tv_top_margin_property->values[0] = 0;
+       dev->mode_config.tv_top_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_bottom_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE,
+                                   "bottom margin", 2);
+       dev->mode_config.tv_bottom_margin_property->values[0] = 0;
+       dev->mode_config.tv_bottom_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_mode_property =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM,
+                                   "mode", num_modes);
+       for (i = 0; i < num_modes; i++)
+               drm_property_add_enum(dev->mode_config.tv_mode_property, i,
+                                     i, modes[i]);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_tv_properties);
+
+/**
+ * drm_mode_create_scaling_mode_property - create scaling mode property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ */
+int drm_mode_create_scaling_mode_property(struct drm_device *dev)
+{
+       struct drm_property *scaling_mode;
+       int i;
+
+       if (dev->mode_config.scaling_mode_property)
+               return 0;
+
+       scaling_mode =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM, "scaling mode",
+                                   ARRAY_SIZE(drm_scaling_mode_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_scaling_mode_enum_list); i++)
+               drm_property_add_enum(scaling_mode, i,
+                                     drm_scaling_mode_enum_list[i].type,
+                                     drm_scaling_mode_enum_list[i].name);
+
+       dev->mode_config.scaling_mode_property = scaling_mode;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_scaling_mode_property);
+
+/**
+ * drm_mode_create_dithering_property - create dithering property
+ * @dev: DRM device
+ *
+ * Called by a driver the first time it's needed, must be attached to desired
+ * connectors.
+ */
+int drm_mode_create_dithering_property(struct drm_device *dev)
+{
+       struct drm_property *dithering_mode;
+       int i;
+
+       if (dev->mode_config.dithering_mode_property)
+               return 0;
+
+       dithering_mode =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM, "dithering",
+                                   ARRAY_SIZE(drm_dithering_mode_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_dithering_mode_enum_list); i++)
+               drm_property_add_enum(dithering_mode, i,
+                                     drm_dithering_mode_enum_list[i].type,
+                                     drm_dithering_mode_enum_list[i].name);
+       dev->mode_config.dithering_mode_property = dithering_mode;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_create_dithering_property);
+
+/**
+ * drm_mode_config_init - initialize DRM mode_configuration structure
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * None, should happen single threaded at init time.
+ *
+ * Initialize @dev's mode_config structure, used for tracking the graphics
+ * configuration of @dev.
+ */
+void drm_mode_config_init(struct drm_device *dev)
+{
+       mutex_init(&dev->mode_config.mutex);
+       INIT_LIST_HEAD(&dev->mode_config.fb_list);
+       INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list);
+       INIT_LIST_HEAD(&dev->mode_config.crtc_list);
+       INIT_LIST_HEAD(&dev->mode_config.connector_list);
+       INIT_LIST_HEAD(&dev->mode_config.encoder_list);
+       INIT_LIST_HEAD(&dev->mode_config.property_list);
+       INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
+       idr_init(&dev->mode_config.crtc_idr);
+
+       mutex_lock(&dev->mode_config.mutex);
+       drm_mode_create_standard_connector_properties(dev);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       /* Just to be sure */
+       dev->mode_config.num_fb = 0;
+       dev->mode_config.num_connector = 0;
+       dev->mode_config.num_crtc = 0;
+       dev->mode_config.num_encoder = 0;
+}
+EXPORT_SYMBOL(drm_mode_config_init);
+
+int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group)
+{
+       uint32_t total_objects = 0;
+
+       total_objects += dev->mode_config.num_crtc;
+       total_objects += dev->mode_config.num_connector;
+       total_objects += dev->mode_config.num_encoder;
+
+       if (total_objects == 0)
+               return -EINVAL;
+
+       group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
+       if (!group->id_list)
+               return -ENOMEM;
+
+       group->num_crtcs = 0;
+       group->num_connectors = 0;
+       group->num_encoders = 0;
+       return 0;
+}
+
+int drm_mode_group_init_legacy_group(struct drm_device *dev,
+                                    struct drm_mode_group *group)
+{
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       int ret;
+
+       if ((ret = drm_mode_group_init(dev, group)))
+               return ret;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               group->id_list[group->num_crtcs++] = crtc->base.id;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               group->id_list[group->num_crtcs + group->num_encoders++] =
+               encoder->base.id;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               group->id_list[group->num_crtcs + group->num_encoders +
+                              group->num_connectors++] = connector->base.id;
+
+       return 0;
+}
+
+/**
+ * drm_mode_config_cleanup - free up DRM mode_config info
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Free up all the connectors and CRTCs associated with this DRM device, then
+ * free up the framebuffers and associated buffer objects.
+ *
+ * FIXME: cleanup any dangling user buffer objects too
+ */
+void drm_mode_config_cleanup(struct drm_device *dev)
+{
+       struct drm_connector *connector, *ot;
+       struct drm_crtc *crtc, *ct;
+       struct drm_encoder *encoder, *enct;
+       struct drm_framebuffer *fb, *fbt;
+       struct drm_property *property, *pt;
+
+       list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list,
+                                head) {
+               encoder->funcs->destroy(encoder);
+       }
+
+       list_for_each_entry_safe(connector, ot,
+                                &dev->mode_config.connector_list, head) {
+               connector->funcs->destroy(connector);
+       }
+
+       list_for_each_entry_safe(property, pt, &dev->mode_config.property_list,
+                                head) {
+               drm_property_destroy(dev, property);
+       }
+
+       list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
+               fb->funcs->destroy(fb);
+       }
+
+       list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
+               crtc->funcs->destroy(crtc);
+       }
+
+}
+EXPORT_SYMBOL(drm_mode_config_cleanup);
+
+/**
+ * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
+ * @out: drm_mode_modeinfo struct to return to the user
+ * @in: drm_display_mode to use
+ *
+ * LOCKING:
+ * None.
+ *
+ * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
+ * the user.
+ */
+void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
+                              struct drm_display_mode *in)
+{
+       out->clock = in->clock;
+       out->hdisplay = in->hdisplay;
+       out->hsync_start = in->hsync_start;
+       out->hsync_end = in->hsync_end;
+       out->htotal = in->htotal;
+       out->hskew = in->hskew;
+       out->vdisplay = in->vdisplay;
+       out->vsync_start = in->vsync_start;
+       out->vsync_end = in->vsync_end;
+       out->vtotal = in->vtotal;
+       out->vscan = in->vscan;
+       out->vrefresh = in->vrefresh;
+       out->flags = in->flags;
+       out->type = in->type;
+       strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+       out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+}
+
+/**
+ * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
+ * @out: drm_display_mode to return to the user
+ * @in: drm_mode_modeinfo to use
+ *
+ * LOCKING:
+ * None.
+ *
+ * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
+ * the caller.
+ */
+void drm_crtc_convert_umode(struct drm_display_mode *out,
+                           struct drm_mode_modeinfo *in)
+{
+       out->clock = in->clock;
+       out->hdisplay = in->hdisplay;
+       out->hsync_start = in->hsync_start;
+       out->hsync_end = in->hsync_end;
+       out->htotal = in->htotal;
+       out->hskew = in->hskew;
+       out->vdisplay = in->vdisplay;
+       out->vsync_start = in->vsync_start;
+       out->vsync_end = in->vsync_end;
+       out->vtotal = in->vtotal;
+       out->vscan = in->vscan;
+       out->vrefresh = in->vrefresh;
+       out->flags = in->flags;
+       out->type = in->type;
+       strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+       out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+}
+
+/**
+ * drm_mode_getresources - get graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Construct a set of configuration description structures and return
+ * them to the user, including CRTC, connector and framebuffer configuration.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getresources(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_mode_card_res *card_res = data;
+       struct list_head *lh;
+       struct drm_framebuffer *fb;
+       struct drm_connector *connector;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int ret = 0;
+       int connector_count = 0;
+       int crtc_count = 0;
+       int fb_count = 0;
+       int encoder_count = 0;
+       int copied = 0, i;
+       uint32_t __user *fb_id;
+       uint32_t __user *crtc_id;
+       uint32_t __user *connector_id;
+       uint32_t __user *encoder_id;
+       struct drm_mode_group *mode_group;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       /*
+        * For the non-control nodes we need to limit the list of resources
+        * by IDs in the group list for this node
+        */
+       list_for_each(lh, &file_priv->fbs)
+               fb_count++;
+
+       mode_group = &file_priv->master->minor->mode_group;
+       if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+
+               list_for_each(lh, &dev->mode_config.crtc_list)
+                       crtc_count++;
+
+               list_for_each(lh, &dev->mode_config.connector_list)
+                       connector_count++;
+
+               list_for_each(lh, &dev->mode_config.encoder_list)
+                       encoder_count++;
+       } else {
+
+               crtc_count = mode_group->num_crtcs;
+               connector_count = mode_group->num_connectors;
+               encoder_count = mode_group->num_encoders;
+       }
+
+       card_res->max_height = dev->mode_config.max_height;
+       card_res->min_height = dev->mode_config.min_height;
+       card_res->max_width = dev->mode_config.max_width;
+       card_res->min_width = dev->mode_config.min_width;
+
+       /* handle this in 4 parts */
+       /* FBs */
+       if (card_res->count_fbs >= fb_count) {
+               copied = 0;
+               fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
+               list_for_each_entry(fb, &file_priv->fbs, head) {
+                       if (put_user(fb->base.id, fb_id + copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_fbs = fb_count;
+
+       /* CRTCs */
+       if (card_res->count_crtcs >= crtc_count) {
+               copied = 0;
+               crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
+               if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+                       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                                           head) {
+                               DRM_DEBUG("CRTC ID is %d\n", crtc->base.id);
+                               if (put_user(crtc->base.id, crtc_id + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               } else {
+                       for (i = 0; i < mode_group->num_crtcs; i++) {
+                               if (put_user(mode_group->id_list[i],
+                                            crtc_id + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       card_res->count_crtcs = crtc_count;
+
+       /* Encoders */
+       if (card_res->count_encoders >= encoder_count) {
+               copied = 0;
+               encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
+               if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+                       list_for_each_entry(encoder,
+                                           &dev->mode_config.encoder_list,
+                                           head) {
+                               DRM_DEBUG("ENCODER ID is %d\n",
+                                         encoder->base.id);
+                               if (put_user(encoder->base.id, encoder_id +
+                                            copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               } else {
+                       for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) {
+                               if (put_user(mode_group->id_list[i],
+                                            encoder_id + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+
+               }
+       }
+       card_res->count_encoders = encoder_count;
+
+       /* Connectors */
+       if (card_res->count_connectors >= connector_count) {
+               copied = 0;
+               connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
+               if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+                       list_for_each_entry(connector,
+                                           &dev->mode_config.connector_list,
+                                           head) {
+                               DRM_DEBUG("CONNECTOR ID is %d\n",
+                                         connector->base.id);
+                               if (put_user(connector->base.id,
+                                            connector_id + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               } else {
+                       int start = mode_group->num_crtcs +
+                               mode_group->num_encoders;
+                       for (i = start; i < start + mode_group->num_connectors; i++) {
+                               if (put_user(mode_group->id_list[i],
+                                            connector_id + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       card_res->count_connectors = connector_count;
+
+       DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs,
+                 card_res->count_connectors, card_res->count_encoders);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getcrtc - get CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a CRTC configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getcrtc(struct drm_device *dev,
+                    void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc *crtc_resp = data;
+       struct drm_crtc *crtc;
+       struct drm_mode_object *obj;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
+                                  DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       crtc_resp->x = crtc->x;
+       crtc_resp->y = crtc->y;
+       crtc_resp->gamma_size = crtc->gamma_size;
+       if (crtc->fb)
+               crtc_resp->fb_id = crtc->fb->base.id;
+       else
+               crtc_resp->fb_id = 0;
+
+       if (crtc->enabled) {
+
+               drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+               crtc_resp->mode_valid = 1;
+
+       } else {
+               crtc_resp->mode_valid = 0;
+       }
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getconnector - get connector configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a connector configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getconnector(struct drm_device *dev, void *data,
+                         struct drm_file *file_priv)
+{
+       struct drm_mode_get_connector *out_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_connector *connector;
+       struct drm_display_mode *mode;
+       int mode_count = 0;
+       int props_count = 0;
+       int encoders_count = 0;
+       int ret = 0;
+       int copied = 0;
+       int i;
+       struct drm_mode_modeinfo u_mode;
+       struct drm_mode_modeinfo __user *mode_ptr;
+       uint32_t __user *prop_ptr;
+       uint64_t __user *prop_values;
+       uint32_t __user *encoder_ptr;
+
+       memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+
+       DRM_DEBUG("connector id %d:\n", out_resp->connector_id);
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, out_resp->connector_id,
+                                  DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] != 0) {
+                       props_count++;
+               }
+       }
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] != 0) {
+                       encoders_count++;
+               }
+       }
+
+       if (out_resp->count_modes == 0) {
+               connector->funcs->fill_modes(connector,
+                                            dev->mode_config.max_width,
+                                            dev->mode_config.max_height);
+       }
+
+       /* delayed so we get modes regardless of pre-fill_modes state */
+       list_for_each_entry(mode, &connector->modes, head)
+               mode_count++;
+
+       out_resp->connector_id = connector->base.id;
+       out_resp->connector_type = connector->connector_type;
+       out_resp->connector_type_id = connector->connector_type_id;
+       out_resp->mm_width = connector->display_info.width_mm;
+       out_resp->mm_height = connector->display_info.height_mm;
+       out_resp->subpixel = connector->display_info.subpixel_order;
+       out_resp->connection = connector->status;
+       if (connector->encoder)
+               out_resp->encoder_id = connector->encoder->base.id;
+       else
+               out_resp->encoder_id = 0;
+
+       /*
+        * This ioctl is called twice, once to determine how much space is
+        * needed, and the 2nd time to fill it.
+        */
+       if ((out_resp->count_modes >= mode_count) && mode_count) {
+               copied = 0;
+               mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr;
+               list_for_each_entry(mode, &connector->modes, head) {
+                       drm_crtc_convert_to_umode(&u_mode, mode);
+                       if (copy_to_user(mode_ptr + copied,
+                                        &u_mode, sizeof(u_mode))) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       out_resp->count_modes = mode_count;
+
+       if ((out_resp->count_props >= props_count) && props_count) {
+               copied = 0;
+               prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr);
+               prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr);
+               for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+                       if (connector->property_ids[i] != 0) {
+                               if (put_user(connector->property_ids[i],
+                                            prop_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+
+                               if (put_user(connector->property_values[i],
+                                            prop_values + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       out_resp->count_props = props_count;
+
+       if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
+               copied = 0;
+               encoder_ptr = (uint32_t *)(unsigned long)(out_resp->encoders_ptr);
+               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+                       if (connector->encoder_ids[i] != 0) {
+                               if (put_user(connector->encoder_ids[i],
+                                            encoder_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       out_resp->count_encoders = encoders_count;
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_getencoder(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_mode_get_encoder *enc_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, enc_resp->encoder_id,
+                                  DRM_MODE_OBJECT_ENCODER);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       encoder = obj_to_encoder(obj);
+
+       if (encoder->crtc)
+               enc_resp->crtc_id = encoder->crtc->base.id;
+       else
+               enc_resp->crtc_id = 0;
+       enc_resp->encoder_type = encoder->encoder_type;
+       enc_resp->encoder_id = encoder->base.id;
+       enc_resp->possible_crtcs = encoder->possible_crtcs;
+       enc_resp->possible_clones = encoder->possible_clones;
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_setcrtc - set CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Build a new CRTC configuration based on user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_setcrtc(struct drm_device *dev, void *data,
+                    struct drm_file *file_priv)
+{
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_mode_crtc *crtc_req = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc, *crtcfb;
+       struct drm_connector **connector_set = NULL, *connector;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_display_mode *mode = NULL;
+       struct drm_mode_set set;
+       uint32_t __user *set_connectors_ptr;
+       int ret = 0;
+       int i;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, crtc_req->crtc_id,
+                                  DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id);
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       if (crtc_req->mode_valid) {
+               /* If we have a mode we need a framebuffer. */
+               /* If we pass -1, set the mode with the currently bound fb */
+               if (crtc_req->fb_id == -1) {
+                       list_for_each_entry(crtcfb,
+                                           &dev->mode_config.crtc_list, head) {
+                               if (crtcfb == crtc) {
+                                       DRM_DEBUG("Using current fb for setmode\n");
+                                       fb = crtc->fb;
+                               }
+                       }
+               } else {
+                       obj = drm_mode_object_find(dev, crtc_req->fb_id,
+                                                  DRM_MODE_OBJECT_FB);
+                       if (!obj) {
+                               DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       fb = obj_to_fb(obj);
+               }
+
+               mode = drm_mode_create(dev);
+               drm_crtc_convert_umode(mode, &crtc_req->mode);
+               drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       }
+
+       if (crtc_req->count_connectors == 0 && mode) {
+               DRM_DEBUG("Count connectors is 0 but mode set\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->count_connectors > 0 && !mode && !fb) {
+               DRM_DEBUG("Count connectors is %d but no mode or fb set\n",
+                         crtc_req->count_connectors);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->count_connectors > 0) {
+               u32 out_id;
+
+               /* Avoid unbounded kernel memory allocation */
+               if (crtc_req->count_connectors > config->num_connector) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               connector_set = kmalloc(crtc_req->count_connectors *
+                                       sizeof(struct drm_connector *),
+                                       GFP_KERNEL);
+               if (!connector_set) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               for (i = 0; i < crtc_req->count_connectors; i++) {
+                       set_connectors_ptr = (uint32_t *)(unsigned long)crtc_req->set_connectors_ptr;
+                       if (get_user(out_id, &set_connectors_ptr[i])) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+
+                       obj = drm_mode_object_find(dev, out_id,
+                                                  DRM_MODE_OBJECT_CONNECTOR);
+                       if (!obj) {
+                               DRM_DEBUG("Connector id %d unknown\n", out_id);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       connector = obj_to_connector(obj);
+
+                       connector_set[i] = connector;
+               }
+       }
+
+       set.crtc = crtc;
+       set.x = crtc_req->x;
+       set.y = crtc_req->y;
+       set.mode = mode;
+       set.connectors = connector_set;
+       set.num_connectors = crtc_req->count_connectors;
+       set.fb =fb;
+       ret = crtc->funcs->set_config(&set);
+
+out:
+       kfree(connector_set);
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+                       void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor *req = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+
+       if (!req->flags) {
+               DRM_ERROR("no operation set\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc_id);
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       if (req->flags & DRM_MODE_CURSOR_BO) {
+               if (!crtc->funcs->cursor_set) {
+                       DRM_ERROR("crtc does not support cursor\n");
+                       ret = -ENXIO;
+                       goto out;
+               }
+               /* Turns off the cursor if handle is 0 */
+               ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
+                                             req->width, req->height);
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_MOVE) {
+               if (crtc->funcs->cursor_move) {
+                       ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+               } else {
+                       DRM_ERROR("crtc does not support cursor\n");
+                       ret = -EFAULT;
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_addfb - add an FB to the graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Add a new FB to the specified CRTC, given a user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_addfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *r = data;
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+
+       if ((config->min_width > r->width) || (r->width > config->max_width)) {
+               DRM_ERROR("mode new framebuffer width not within limits\n");
+               return -EINVAL;
+       }
+       if ((config->min_height > r->height) || (r->height > config->max_height)) {
+               DRM_ERROR("mode new framebuffer height not within limits\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       /* TODO check buffer is sufficently large */
+       /* TODO setup destructor callback */
+
+       fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
+       if (!fb) {
+               DRM_ERROR("could not create framebuffer\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       r->fb_id = fb->base.id;
+       list_add(&fb->filp_head, &file_priv->fbs);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_rmfb - remove an FB from the configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Remove the FB specified by the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_rmfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_framebuffer *fbl = NULL;
+       uint32_t *id = data;
+       int ret = 0;
+       int found = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
+       /* TODO check that we realy get a framebuffer back. */
+       if (!obj) {
+               DRM_ERROR("mode invalid framebuffer id\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       fb = obj_to_fb(obj);
+
+       list_for_each_entry(fbl, &file_priv->fbs, filp_head)
+               if (fb == fbl)
+                       found = 1;
+
+       if (!found) {
+               DRM_ERROR("tried to remove a fb that we didn't own\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* TODO release all crtc connected to the framebuffer */
+       /* TODO unhock the destructor from the buffer object */
+
+       list_del(&fb->filp_head);
+       fb->funcs->destroy(fb);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getfb - get FB info
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *r = data;
+       struct drm_mode_object *obj;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
+       if (!obj) {
+               DRM_ERROR("invalid framebuffer id\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       fb = obj_to_fb(obj);
+
+       r->height = fb->height;
+       r->width = fb->width;
+       r->depth = fb->depth;
+       r->bpp = fb->bits_per_pixel;
+       r->pitch = fb->pitch;
+       fb->funcs->create_handle(fb, file_priv, &r->handle);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_fb_release - remove and free the FBs on this file
+ * @filp: file * from the ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Destroy all the FBs associated with @filp.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+void drm_fb_release(struct file *filp)
+{
+       struct drm_file *priv = filp->private_data;
+       struct drm_device *dev = priv->minor->dev;
+       struct drm_framebuffer *fb, *tfb;
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+               list_del(&fb->filp_head);
+               fb->funcs->destroy(fb);
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+/**
+ * drm_mode_attachmode - add a mode to the user mode list
+ * @dev: DRM device
+ * @connector: connector to add the mode to
+ * @mode: mode to add
+ *
+ * Add @mode to @connector's user mode list.
+ */
+static int drm_mode_attachmode(struct drm_device *dev,
+                              struct drm_connector *connector,
+                              struct drm_display_mode *mode)
+{
+       int ret = 0;
+
+       list_add_tail(&mode->head, &connector->user_modes);
+       return ret;
+}
+
+int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
+                            struct drm_display_mode *mode)
+{
+       struct drm_connector *connector;
+       int ret = 0;
+       struct drm_display_mode *dup_mode;
+       int need_dup = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       break;
+               if (connector->encoder->crtc == crtc) {
+                       if (need_dup)
+                               dup_mode = drm_mode_duplicate(dev, mode);
+                       else
+                               dup_mode = mode;
+                       ret = drm_mode_attachmode(dev, connector, dup_mode);
+                       if (ret)
+                               return ret;
+                       need_dup = 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_attachmode_crtc);
+
+static int drm_mode_detachmode(struct drm_device *dev,
+                              struct drm_connector *connector,
+                              struct drm_display_mode *mode)
+{
+       int found = 0;
+       int ret = 0;
+       struct drm_display_mode *match_mode, *t;
+
+       list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) {
+               if (drm_mode_equal(match_mode, mode)) {
+                       list_del(&match_mode->head);
+                       drm_mode_destroy(dev, match_mode);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               drm_mode_detachmode(dev, connector, mode);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_detachmode_crtc);
+
+/**
+ * drm_fb_attachmode - Attach a user mode to an connector
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * This attaches a user specified mode to an connector.
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_attachmode_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_mode_cmd *mode_cmd = data;
+       struct drm_connector *connector;
+       struct drm_display_mode *mode;
+       struct drm_mode_object *obj;
+       struct drm_mode_modeinfo *umode = &mode_cmd->mode;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       mode = drm_mode_create(dev);
+       if (!mode) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       drm_crtc_convert_umode(mode, umode);
+
+       ret = drm_mode_attachmode(dev, connector, mode);
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+
+/**
+ * drm_fb_detachmode - Detach a user specified mode from an connector
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_detachmode_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_mode_mode_cmd *mode_cmd = data;
+       struct drm_connector *connector;
+       struct drm_display_mode mode;
+       struct drm_mode_modeinfo *umode = &mode_cmd->mode;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       drm_crtc_convert_umode(&mode, umode);
+       ret = drm_mode_detachmode(dev, connector, &mode);
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                        const char *name, int num_values)
+{
+       struct drm_property *property = NULL;
+
+       property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
+       if (!property)
+               return NULL;
+
+       if (num_values) {
+               property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
+               if (!property->values)
+                       goto fail;
+       }
+
+       drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY);
+       property->flags = flags;
+       property->num_values = num_values;
+       INIT_LIST_HEAD(&property->enum_blob_list);
+
+       if (name)
+               strncpy(property->name, name, DRM_PROP_NAME_LEN);
+
+       list_add_tail(&property->head, &dev->mode_config.property_list);
+       return property;
+fail:
+       kfree(property);
+       return NULL;
+}
+EXPORT_SYMBOL(drm_property_create);
+
+int drm_property_add_enum(struct drm_property *property, int index,
+                         uint64_t value, const char *name)
+{
+       struct drm_property_enum *prop_enum;
+
+       if (!(property->flags & DRM_MODE_PROP_ENUM))
+               return -EINVAL;
+
+       if (!list_empty(&property->enum_blob_list)) {
+               list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+                       if (prop_enum->value == value) {
+                               strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
+                               prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+                               return 0;
+                       }
+               }
+       }
+
+       prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
+       if (!prop_enum)
+               return -ENOMEM;
+
+       strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN);
+       prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+       prop_enum->value = value;
+
+       property->values[index] = value;
+       list_add_tail(&prop_enum->head, &property->enum_blob_list);
+       return 0;
+}
+EXPORT_SYMBOL(drm_property_add_enum);
+
+void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
+{
+       struct drm_property_enum *prop_enum, *pt;
+
+       list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
+               list_del(&prop_enum->head);
+               kfree(prop_enum);
+       }
+
+       if (property->num_values)
+               kfree(property->values);
+       drm_mode_object_put(dev, &property->base);
+       list_del(&property->head);
+       kfree(property);
+}
+EXPORT_SYMBOL(drm_property_destroy);
+
+int drm_connector_attach_property(struct drm_connector *connector,
+                              struct drm_property *property, uint64_t init_val)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == 0) {
+                       connector->property_ids[i] = property->base.id;
+                       connector->property_values[i] = init_val;
+                       break;
+               }
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_property);
+
+int drm_connector_property_set_value(struct drm_connector *connector,
+                                 struct drm_property *property, uint64_t value)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == property->base.id) {
+                       connector->property_values[i] = value;
+                       break;
+               }
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_property_set_value);
+
+int drm_connector_property_get_value(struct drm_connector *connector,
+                                 struct drm_property *property, uint64_t *val)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == property->base.id) {
+                       *val = connector->property_values[i];
+                       break;
+               }
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL(drm_connector_property_get_value);
+
+int drm_mode_getproperty_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_mode_get_property *out_resp = data;
+       struct drm_property *property;
+       int enum_count = 0;
+       int blob_count = 0;
+       int value_count = 0;
+       int ret = 0, i;
+       int copied;
+       struct drm_property_enum *prop_enum;
+       struct drm_mode_property_enum __user *enum_ptr;
+       struct drm_property_blob *prop_blob;
+       uint32_t *blob_id_ptr;
+       uint64_t __user *values_ptr;
+       uint32_t __user *blob_length_ptr;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
+       if (!obj) {
+               ret = -EINVAL;
+               goto done;
+       }
+       property = obj_to_property(obj);
+
+       if (property->flags & DRM_MODE_PROP_ENUM) {
+               list_for_each_entry(prop_enum, &property->enum_blob_list, head)
+                       enum_count++;
+       } else if (property->flags & DRM_MODE_PROP_BLOB) {
+               list_for_each_entry(prop_blob, &property->enum_blob_list, head)
+                       blob_count++;
+       }
+
+       value_count = property->num_values;
+
+       strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
+       out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
+       out_resp->flags = property->flags;
+
+       if ((out_resp->count_values >= value_count) && value_count) {
+               values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr;
+               for (i = 0; i < value_count; i++) {
+                       if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
+                               ret = -EFAULT;
+                               goto done;
+                       }
+               }
+       }
+       out_resp->count_values = value_count;
+
+       if (property->flags & DRM_MODE_PROP_ENUM) {
+               if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
+                       copied = 0;
+                       enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr;
+                       list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+
+                               if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               if (copy_to_user(&enum_ptr[copied].name,
+                                                &prop_enum->name, DRM_PROP_NAME_LEN)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = enum_count;
+       }
+
+       if (property->flags & DRM_MODE_PROP_BLOB) {
+               if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
+                       copied = 0;
+                       blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr;
+                       blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr;
+
+                       list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
+                               if (put_user(prop_blob->base.id, blob_id_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               if (put_user(prop_blob->length, blob_length_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = blob_count;
+       }
+done:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
+                                                         void *data)
+{
+       struct drm_property_blob *blob;
+
+       if (!length || !data)
+               return NULL;
+
+       blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
+       if (!blob)
+               return NULL;
+
+       blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob));
+       blob->length = length;
+
+       memcpy(blob->data, data, length);
+
+       drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB);
+
+       list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
+       return blob;
+}
+
+static void drm_property_destroy_blob(struct drm_device *dev,
+                              struct drm_property_blob *blob)
+{
+       drm_mode_object_put(dev, &blob->base);
+       list_del(&blob->head);
+       kfree(blob);
+}
+
+int drm_mode_getblob_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_object *obj;
+       struct drm_mode_get_blob *out_resp = data;
+       struct drm_property_blob *blob;
+       int ret = 0;
+       void *blob_ptr;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
+       if (!obj) {
+               ret = -EINVAL;
+               goto done;
+       }
+       blob = obj_to_blob(obj);
+
+       if (out_resp->length == blob->length) {
+               blob_ptr = (void *)(unsigned long)out_resp->data;
+               if (copy_to_user(blob_ptr, blob->data, blob->length)){
+                       ret = -EFAULT;
+                       goto done;
+               }
+       }
+       out_resp->length = blob->length;
+
+done:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_connector_update_edid_property(struct drm_connector *connector,
+                                           struct edid *edid)
+{
+       struct drm_device *dev = connector->dev;
+       int ret = 0;
+
+       if (connector->edid_blob_ptr)
+               drm_property_destroy_blob(dev, connector->edid_blob_ptr);
+
+       /* Delete edid, when there is none. */
+       if (!edid) {
+               connector->edid_blob_ptr = NULL;
+               ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0);
+               return ret;
+       }
+
+       connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid);
+
+       ret = drm_connector_property_set_value(connector,
+                                              dev->mode_config.edid_property,
+                                              connector->edid_blob_ptr->base.id);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
+
+int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
+                                      void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_connector_set_property *out_resp = data;
+       struct drm_mode_object *obj;
+       struct drm_property *property;
+       struct drm_connector *connector;
+       int ret = -EINVAL;
+       int i;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+       if (!obj) {
+               goto out;
+       }
+       connector = obj_to_connector(obj);
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
+               if (connector->property_ids[i] == out_resp->prop_id)
+                       break;
+       }
+
+       if (i == DRM_CONNECTOR_MAX_PROPERTY) {
+               goto out;
+       }
+
+       obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
+       if (!obj) {
+               goto out;
+       }
+       property = obj_to_property(obj);
+
+       if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+               goto out;
+
+       if (property->flags & DRM_MODE_PROP_RANGE) {
+               if (out_resp->value < property->values[0])
+                       goto out;
+
+               if (out_resp->value > property->values[1])
+                       goto out;
+       } else {
+               int found = 0;
+               for (i = 0; i < property->num_values; i++) {
+                       if (property->values[i] == out_resp->value) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       goto out;
+               }
+       }
+
+       if (connector->funcs->set_property)
+               ret = connector->funcs->set_property(connector, property, out_resp->value);
+
+       /* store the property value if succesful */
+       if (!ret)
+               drm_connector_property_set_value(connector, property, out_resp->value);
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_connector_attach_encoder(struct drm_connector *connector,
+                                     struct drm_encoder *encoder)
+{
+       int i;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0) {
+                       connector->encoder_ids[i] = encoder->base.id;
+                       return 0;
+               }
+       }
+       return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
+
+void drm_mode_connector_detach_encoder(struct drm_connector *connector,
+                                   struct drm_encoder *encoder)
+{
+       int i;
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == encoder->base.id) {
+                       connector->encoder_ids[i] = 0;
+                       if (connector->encoder == encoder)
+                               connector->encoder = NULL;
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
+
+bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+                                 int gamma_size)
+{
+       crtc->gamma_size = gamma_size;
+
+       crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
+       if (!crtc->gamma_store) {
+               crtc->gamma_size = 0;
+               return false;
+       }
+
+       return true;
+}
+EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
+
+int drm_mode_gamma_set_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       void *r_base, *g_base, *b_base;
+       int size;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       /* memcpy into gamma store */
+       if (crtc_lut->gamma_size != crtc->gamma_size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       size = crtc_lut->gamma_size * (sizeof(uint16_t));
+       r_base = crtc->gamma_store;
+       if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       g_base = r_base + size;
+       if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       b_base = g_base + size;
+       if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+
+}
+
+int drm_mode_gamma_get_ioctl(struct drm_device *dev,
+                            void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc_lut *crtc_lut = data;
+       struct drm_mode_object *obj;
+       struct drm_crtc *crtc;
+       void *r_base, *g_base, *b_base;
+       int size;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
+       if (!obj) {
+               ret = -EINVAL;
+               goto out;
+       }
+       crtc = obj_to_crtc(obj);
+
+       /* memcpy into gamma store */
+       if (crtc_lut->gamma_size != crtc->gamma_size) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       size = crtc_lut->gamma_size * (sizeof(uint16_t));
+       r_base = crtc->gamma_store;
+       if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       g_base = r_base + size;
+       if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       b_base = g_base + size;
+       if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
+               ret = -EFAULT;
+               goto out;
+       }
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
new file mode 100644 (file)
index 0000000..d8a982b
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * Copyright (c) 2006-2008 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ *
+ * DRM core CRTC related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ *      Keith Packard
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+/*
+ * Detailed mode info for 800x600@60Hz
+ */
+static struct drm_display_mode std_mode[] = {
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
+                  968, 1056, 0, 600, 601, 605, 628, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+};
+
+/**
+ * drm_helper_probe_connector_modes - get complete set of display modes
+ * @dev: DRM device
+ * @maxX: max width for modes
+ * @maxY: max height for modes
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Based on @dev's mode_config layout, scan all the connectors and try to detect
+ * modes on them.  Modes will first be added to the connector's probed_modes
+ * list, then culled (based on validity and the @maxX, @maxY parameters) and
+ * put into the normal modes list.
+ *
+ * Intended to be used either at bootup time or when major configuration
+ * changes have occurred.
+ *
+ * FIXME: take into account monitor limits
+ */
+void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
+                                            uint32_t maxX, uint32_t maxY)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_display_mode *mode, *t;
+       struct drm_connector_helper_funcs *connector_funcs =
+               connector->helper_private;
+       int ret;
+
+       DRM_DEBUG("%s\n", drm_get_connector_name(connector));
+       /* set all modes to the unverified state */
+       list_for_each_entry_safe(mode, t, &connector->modes, head)
+               mode->status = MODE_UNVERIFIED;
+
+       connector->status = connector->funcs->detect(connector);
+
+       if (connector->status == connector_status_disconnected) {
+               DRM_DEBUG("%s is disconnected\n",
+                         drm_get_connector_name(connector));
+               /* TODO set EDID to NULL */
+               return;
+       }
+
+       ret = (*connector_funcs->get_modes)(connector);
+
+       if (ret) {
+               drm_mode_connector_list_update(connector);
+       }
+
+       if (maxX && maxY)
+               drm_mode_validate_size(dev, &connector->modes, maxX,
+                                      maxY, 0);
+       list_for_each_entry_safe(mode, t, &connector->modes, head) {
+               if (mode->status == MODE_OK)
+                       mode->status = connector_funcs->mode_valid(connector,
+                                                                  mode);
+       }
+
+
+       drm_mode_prune_invalid(dev, &connector->modes, true);
+
+       if (list_empty(&connector->modes)) {
+               struct drm_display_mode *stdmode;
+
+               DRM_DEBUG("No valid modes on %s\n",
+                         drm_get_connector_name(connector));
+
+               /* Should we do this here ???
+                * When no valid EDID modes are available we end up
+                * here and bailed in the past, now we add a standard
+                * 640x480@60Hz mode and carry on.
+                */
+               stdmode = drm_mode_duplicate(dev, &std_mode[0]);
+               drm_mode_probed_add(connector, stdmode);
+               drm_mode_list_concat(&connector->probed_modes,
+                                    &connector->modes);
+
+               DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
+                         drm_get_connector_name(connector));
+       }
+
+       drm_mode_sort(&connector->modes);
+
+       DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(connector));
+       list_for_each_entry_safe(mode, t, &connector->modes, head) {
+               mode->vrefresh = drm_mode_vrefresh(mode);
+
+               drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+               drm_mode_debug_printmodeline(mode);
+       }
+}
+EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
+
+void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
+                                     uint32_t maxY)
+{
+       struct drm_connector *connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               drm_helper_probe_single_connector_modes(connector, maxX, maxY);
+       }
+}
+EXPORT_SYMBOL(drm_helper_probe_connector_modes);
+
+
+/**
+ * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
+ * @crtc: CRTC to check
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Walk @crtc's DRM device's mode_config and see if it's in use.
+ *
+ * RETURNS:
+ * True if @crtc is part of the mode_config, false otherwise.
+ */
+bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
+{
+       struct drm_encoder *encoder;
+       struct drm_device *dev = crtc->dev;
+       /* FIXME: Locking around list access? */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+               if (encoder->crtc == crtc)
+                       return true;
+       return false;
+}
+EXPORT_SYMBOL(drm_helper_crtc_in_use);
+
+/**
+ * drm_disable_unused_functions - disable unused objects
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled
+ * by calling its dpms function, which should power it off.
+ */
+void drm_helper_disable_unused_functions(struct drm_device *dev)
+{
+       struct drm_encoder *encoder;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               encoder_funcs = encoder->helper_private;
+               if (!encoder->crtc)
+                       (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+               crtc->enabled = drm_helper_crtc_in_use(crtc);
+               if (!crtc->enabled) {
+                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+                       crtc->fb = NULL;
+               }
+       }
+}
+EXPORT_SYMBOL(drm_helper_disable_unused_functions);
+
+static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
+{
+       struct drm_display_mode *mode;
+
+       list_for_each_entry(mode, &connector->modes, head) {
+               if (drm_mode_width(mode) > width ||
+                   drm_mode_height(mode) > height)
+                       continue;
+               if (mode->type & DRM_MODE_TYPE_PREFERRED)
+                       return mode;
+       }
+       return NULL;
+}
+
+static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
+{
+       bool enable;
+
+       if (strict) {
+               enable = connector->status == connector_status_connected;
+       } else {
+               enable = connector->status != connector_status_disconnected;
+       }
+       return enable;
+}
+
+static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
+{
+       bool any_enabled = false;
+       struct drm_connector *connector;
+       int i = 0;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               enabled[i] = drm_connector_enabled(connector, true);
+               any_enabled |= enabled[i];
+               i++;
+       }
+
+       if (any_enabled)
+               return;
+
+       i = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               enabled[i] = drm_connector_enabled(connector, false);
+               i++;
+       }
+}
+
+static bool drm_target_preferred(struct drm_device *dev,
+                                struct drm_display_mode **modes,
+                                bool *enabled, int width, int height)
+{
+       struct drm_connector *connector;
+       int i = 0;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+
+               if (enabled[i] == false) {
+                       i++;
+                       continue;
+               }
+
+               modes[i] = drm_has_preferred_mode(connector, width, height);
+               if (!modes[i]) {
+                       list_for_each_entry(modes[i], &connector->modes, head)
+                               break;
+               }
+               i++;
+       }
+       return true;
+}
+
+static int drm_pick_crtcs(struct drm_device *dev,
+                         struct drm_crtc **best_crtcs,
+                         struct drm_display_mode **modes,
+                         int n, int width, int height)
+{
+       int c, o;
+       struct drm_connector *connector;
+       struct drm_connector_helper_funcs *connector_funcs;
+       struct drm_encoder *encoder;
+       struct drm_crtc *best_crtc;
+       int my_score, best_score, score;
+       struct drm_crtc **crtcs, *crtc;
+
+       if (n == dev->mode_config.num_connector)
+               return 0;
+       c = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (c == n)
+                       break;
+               c++;
+       }
+
+       best_crtcs[n] = NULL;
+       best_crtc = NULL;
+       best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height);
+       if (modes[n] == NULL)
+               return best_score;
+
+       crtcs = kmalloc(dev->mode_config.num_connector *
+                       sizeof(struct drm_crtc *), GFP_KERNEL);
+       if (!crtcs)
+               return best_score;
+
+       my_score = 1;
+       if (connector->status == connector_status_connected)
+               my_score++;
+       if (drm_has_preferred_mode(connector, width, height))
+               my_score++;
+
+       connector_funcs = connector->helper_private;
+       encoder = connector_funcs->best_encoder(connector);
+       if (!encoder)
+               goto out;
+
+       connector->encoder = encoder;
+
+       /* select a crtc for this connector and then attempt to configure
+          remaining connectors */
+       c = 0;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+
+               if ((connector->encoder->possible_crtcs & (1 << c)) == 0) {
+                       c++;
+                       continue;
+               }
+
+               for (o = 0; o < n; o++)
+                       if (best_crtcs[o] == crtc)
+                               break;
+
+               if (o < n) {
+                       /* ignore cloning for now */
+                       c++;
+                       continue;
+               }
+
+               crtcs[n] = crtc;
+               memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *));
+               score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1,
+                                                 width, height);
+               if (score > best_score) {
+                       best_crtc = crtc;
+                       best_score = score;
+                       memcpy(best_crtcs, crtcs,
+                              dev->mode_config.num_connector *
+                              sizeof(struct drm_crtc *));
+               }
+               c++;
+       }
+out:
+       kfree(crtcs);
+       return best_score;
+}
+
+static void drm_setup_crtcs(struct drm_device *dev)
+{
+       struct drm_crtc **crtcs;
+       struct drm_display_mode **modes;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       bool *enabled;
+       int width, height;
+       int i, ret;
+
+       width = dev->mode_config.max_width;
+       height = dev->mode_config.max_height;
+
+       /* clean out all the encoder/crtc combos */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               encoder->crtc = NULL;
+       }
+
+       crtcs = kcalloc(dev->mode_config.num_connector,
+                       sizeof(struct drm_crtc *), GFP_KERNEL);
+       modes = kcalloc(dev->mode_config.num_connector,
+                       sizeof(struct drm_display_mode *), GFP_KERNEL);
+       enabled = kcalloc(dev->mode_config.num_connector,
+                         sizeof(bool), GFP_KERNEL);
+
+       drm_enable_connectors(dev, enabled);
+
+       ret = drm_target_preferred(dev, modes, enabled, width, height);
+       if (!ret)
+               DRM_ERROR("Unable to find initial modes\n");
+
+       drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
+
+       i = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct drm_display_mode *mode = modes[i];
+               struct drm_crtc *crtc = crtcs[i];
+
+               if (connector->encoder == NULL) {
+                       i++;
+                       continue;
+               }
+
+               if (mode && crtc) {
+                       crtc->desired_mode = mode;
+                       connector->encoder->crtc = crtc;
+               } else
+                       connector->encoder->crtc = NULL;
+               i++;
+       }
+
+       kfree(crtcs);
+       kfree(modes);
+       kfree(enabled);
+}
+/**
+ * drm_crtc_set_mode - set a mode
+ * @crtc: CRTC to program
+ * @mode: mode to use
+ * @x: width of mode
+ * @y: height of mode
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
+ * to fixup or reject the mode prior to trying to set it.
+ *
+ * RETURNS:
+ * True if the mode was set successfully, or false otherwise.
+ */
+bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
+                             struct drm_display_mode *mode,
+                             int x, int y,
+                             struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_display_mode *adjusted_mode, saved_mode;
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       int saved_x, saved_y;
+       struct drm_encoder *encoder;
+       bool ret = true;
+
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+
+       crtc->enabled = drm_helper_crtc_in_use(crtc);
+
+       if (!crtc->enabled)
+               return true;
+
+       saved_mode = crtc->mode;
+       saved_x = crtc->x;
+       saved_y = crtc->y;
+
+       /* Update crtc values up front so the driver can rely on them for mode
+        * setting.
+        */
+       crtc->mode = *mode;
+       crtc->x = x;
+       crtc->y = y;
+
+       if (drm_mode_equal(&saved_mode, &crtc->mode)) {
+               if (saved_x != crtc->x || saved_y != crtc->y) {
+                       crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
+                                                 old_fb);
+                       goto done;
+               }
+       }
+
+       /* Pass our mode to the connectors and the CRTC to give them a chance to
+        * adjust it according to limitations or connector properties, and also
+        * a chance to reject the mode entirely.
+        */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+
+               if (encoder->crtc != crtc)
+                       continue;
+               encoder_funcs = encoder->helper_private;
+               if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
+                                                     adjusted_mode))) {
+                       goto done;
+               }
+       }
+
+       if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
+               goto done;
+       }
+
+       /* Prepare the encoders and CRTCs before setting the mode. */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+
+               if (encoder->crtc != crtc)
+                       continue;
+               encoder_funcs = encoder->helper_private;
+               /* Disable the encoders as the first thing we do. */
+               encoder_funcs->prepare(encoder);
+       }
+
+       crtc_funcs->prepare(crtc);
+
+       /* Set up the DPLL and any encoders state that needs to adjust or depend
+        * on the DPLL.
+        */
+       crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+
+               if (encoder->crtc != crtc)
+                       continue;
+
+               DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder),
+                        mode->name, mode->base.id);
+               encoder_funcs = encoder->helper_private;
+               encoder_funcs->mode_set(encoder, mode, adjusted_mode);
+       }
+
+       /* Now enable the clocks, plane, pipe, and connectors that we set up. */
+       crtc_funcs->commit(crtc);
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+
+               if (encoder->crtc != crtc)
+                       continue;
+
+               encoder_funcs = encoder->helper_private;
+               encoder_funcs->commit(encoder);
+
+       }
+
+       /* XXX free adjustedmode */
+       drm_mode_destroy(dev, adjusted_mode);
+       /* FIXME: add subpixel order */
+done:
+       if (!ret) {
+               crtc->mode = saved_mode;
+               crtc->x = saved_x;
+               crtc->y = saved_y;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_crtc_helper_set_mode);
+
+
+/**
+ * drm_crtc_helper_set_config - set a new config from userspace
+ * @crtc: CRTC to setup
+ * @crtc_info: user provided configuration
+ * @new_mode: new mode to set
+ * @connector_set: set of connectors for the new config
+ * @fb: new framebuffer
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Setup a new configuration, provided by the user in @crtc_info, and enable
+ * it.
+ *
+ * RETURNS:
+ * Zero. (FIXME)
+ */
+int drm_crtc_helper_set_config(struct drm_mode_set *set)
+{
+       struct drm_device *dev;
+       struct drm_crtc **save_crtcs, *new_crtc;
+       struct drm_encoder **save_encoders, *new_encoder;
+       struct drm_framebuffer *old_fb;
+       bool save_enabled;
+       bool changed = false;
+       bool flip_or_move = false;
+       struct drm_connector *connector;
+       int count = 0, ro, fail = 0;
+       struct drm_crtc_helper_funcs *crtc_funcs;
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+
+       if (!set)
+               return -EINVAL;
+
+       if (!set->crtc)
+               return -EINVAL;
+
+       if (!set->crtc->helper_private)
+               return -EINVAL;
+
+       crtc_funcs = set->crtc->helper_private;
+
+       DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %d (x, y) (%i, %i)\n",
+                 set->crtc, set->crtc->base.id, set->fb, set->connectors,
+                 (int)set->num_connectors, set->x, set->y);
+
+       dev = set->crtc->dev;
+
+       /* save previous config */
+       save_enabled = set->crtc->enabled;
+
+       /* this is meant to be num_connector not num_crtc */
+       save_crtcs = kzalloc(dev->mode_config.num_connector *
+                            sizeof(struct drm_crtc *), GFP_KERNEL);
+       if (!save_crtcs)
+               return -ENOMEM;
+
+       save_encoders = kzalloc(dev->mode_config.num_connector *
+                               sizeof(struct drm_encoders *), GFP_KERNEL);
+       if (!save_encoders) {
+               kfree(save_crtcs);
+               return -ENOMEM;
+       }
+
+       /* We should be able to check here if the fb has the same properties
+        * and then just flip_or_move it */
+       if (set->crtc->fb != set->fb) {
+               /* if we have no fb then its a change not a flip */
+               if (set->crtc->fb == NULL)
+                       changed = true;
+               else
+                       flip_or_move = true;
+       }
+
+       if (set->x != set->crtc->x || set->y != set->crtc->y)
+               flip_or_move = true;
+
+       if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
+               DRM_DEBUG("modes are different\n");
+               drm_mode_debug_printmodeline(&set->crtc->mode);
+               drm_mode_debug_printmodeline(set->mode);
+               changed = true;
+       }
+
+       /* a) traverse passed in connector list and get encoders for them */
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct drm_connector_helper_funcs *connector_funcs =
+                       connector->helper_private;
+               save_encoders[count++] = connector->encoder;
+               new_encoder = connector->encoder;
+               for (ro = 0; ro < set->num_connectors; ro++) {
+                       if (set->connectors[ro] == connector) {
+                               new_encoder = connector_funcs->best_encoder(connector);
+                               /* if we can't get an encoder for a connector
+                                  we are setting now - then fail */
+                               if (new_encoder == NULL)
+                                       /* don't break so fail path works correct */
+                                       fail = 1;
+                               break;
+                       }
+               }
+
+               if (new_encoder != connector->encoder) {
+                       changed = true;
+                       connector->encoder = new_encoder;
+               }
+       }
+
+       if (fail) {
+               ret = -EINVAL;
+               goto fail_no_encoder;
+       }
+
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       continue;
+
+               save_crtcs[count++] = connector->encoder->crtc;
+
+               if (connector->encoder->crtc == set->crtc)
+                       new_crtc = NULL;
+               else
+                       new_crtc = connector->encoder->crtc;
+
+               for (ro = 0; ro < set->num_connectors; ro++) {
+                       if (set->connectors[ro] == connector)
+                               new_crtc = set->crtc;
+               }
+               if (new_crtc != connector->encoder->crtc) {
+                       changed = true;
+                       connector->encoder->crtc = new_crtc;
+               }
+       }
+
+       /* mode_set_base is not a required function */
+       if (flip_or_move && !crtc_funcs->mode_set_base)
+               changed = true;
+
+       if (changed) {
+               old_fb = set->crtc->fb;
+               set->crtc->fb = set->fb;
+               set->crtc->enabled = (set->mode != NULL);
+               if (set->mode != NULL) {
+                       DRM_DEBUG("attempting to set mode from userspace\n");
+                       drm_mode_debug_printmodeline(set->mode);
+                       if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
+                                                     set->x, set->y,
+                                                     old_fb)) {
+                               ret = -EINVAL;
+                               goto fail_set_mode;
+                       }
+                       /* TODO are these needed? */
+                       set->crtc->desired_x = set->x;
+                       set->crtc->desired_y = set->y;
+                       set->crtc->desired_mode = set->mode;
+               }
+               drm_helper_disable_unused_functions(dev);
+       } else if (flip_or_move) {
+               old_fb = set->crtc->fb;
+               if (set->crtc->fb != set->fb)
+                       set->crtc->fb = set->fb;
+               crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
+       }
+
+       kfree(save_encoders);
+       kfree(save_crtcs);
+       return 0;
+
+fail_set_mode:
+       set->crtc->enabled = save_enabled;
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               connector->encoder->crtc = save_crtcs[count++];
+fail_no_encoder:
+       kfree(save_crtcs);
+       count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               connector->encoder = save_encoders[count++];
+       }
+       kfree(save_encoders);
+       return ret;
+}
+EXPORT_SYMBOL(drm_crtc_helper_set_config);
+
+bool drm_helper_plugged_event(struct drm_device *dev)
+{
+       DRM_DEBUG("\n");
+
+       drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
+                                        dev->mode_config.max_height);
+
+       drm_setup_crtcs(dev);
+
+       /* alert the driver fb layer */
+       dev->mode_config.funcs->fb_changed(dev);
+
+       /* FIXME: send hotplug event */
+       return true;
+}
+/**
+ * drm_initial_config - setup a sane initial connector configuration
+ * @dev: DRM device
+ * @can_grow: this configuration is growable
+ *
+ * LOCKING:
+ * Called at init time, must take mode config lock.
+ *
+ * Scan the CRTCs and connectors and try to put together an initial setup.
+ * At the moment, this is a cloned configuration across all heads with
+ * a new framebuffer object as the backing store.
+ *
+ * RETURNS:
+ * Zero if everything went ok, nonzero otherwise.
+ */
+bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
+{
+       int ret = false;
+
+       drm_helper_plugged_event(dev);
+       return ret;
+}
+EXPORT_SYMBOL(drm_helper_initial_config);
+
+/**
+ * drm_hotplug_stage_two
+ * @dev DRM device
+ * @connector hotpluged connector
+ *
+ * LOCKING.
+ * Caller must hold mode config lock, function might grab struct lock.
+ *
+ * Stage two of a hotplug.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_helper_hotplug_stage_two(struct drm_device *dev)
+{
+       drm_helper_plugged_event(dev);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_helper_hotplug_stage_two);
+
+int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
+                                  struct drm_mode_fb_cmd *mode_cmd)
+{
+       fb->width = mode_cmd->width;
+       fb->height = mode_cmd->height;
+       fb->pitch = mode_cmd->pitch;
+       fb->bits_per_pixel = mode_cmd->bpp;
+       fb->depth = mode_cmd->depth;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
+
+int drm_helper_resume_force_mode(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       int ret;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+
+               if (!crtc->enabled)
+                       continue;
+
+               ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
+                                              crtc->x, crtc->y, crtc->fb);
+
+               if (ret == false)
+                       DRM_ERROR("failed to set mode on crtc %p\n", crtc);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_helper_resume_force_mode);
index 996097acb5e76b3c3d7698c0885f563ad9248522..febb517ee679255a7e3ea694f8b68225118b95f0 100644 (file)
@@ -74,6 +74,9 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
 
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
+
        DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -123,6 +126,23 @@ static struct drm_ioctl_desc drm_ioctls[] = {
        DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW),
 };
 
 #define DRM_CORE_IOCTL_COUNT   ARRAY_SIZE( drm_ioctls )
@@ -138,8 +158,6 @@ static struct drm_ioctl_desc drm_ioctls[] = {
  */
 int drm_lastclose(struct drm_device * dev)
 {
-       struct drm_magic_entry *pt, *next;
-       struct drm_map_list *r_list, *list_t;
        struct drm_vma_entry *vma, *vma_temp;
        int i;
 
@@ -149,13 +167,7 @@ int drm_lastclose(struct drm_device * dev)
                dev->driver->lastclose(dev);
        DRM_DEBUG("driver lastclose completed\n");
 
-       if (dev->unique) {
-               drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
-               dev->unique = NULL;
-               dev->unique_len = 0;
-       }
-
-       if (dev->irq_enabled)
+       if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET))
                drm_irq_uninstall(dev);
 
        mutex_lock(&dev->struct_mutex);
@@ -164,18 +176,9 @@ int drm_lastclose(struct drm_device * dev)
        drm_drawable_free_all(dev);
        del_timer(&dev->timer);
 
-       /* Clear pid list */
-       if (dev->magicfree.next) {
-               list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
-                       list_del(&pt->head);
-                       drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
-                       drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
-               }
-               drm_ht_remove(&dev->magiclist);
-       }
-
        /* Clear AGP information */
-       if (drm_core_has_AGP(dev) && dev->agp) {
+       if (drm_core_has_AGP(dev) && dev->agp &&
+           !drm_core_check_feature(dev, DRIVER_MODESET)) {
                struct drm_agp_mem *entry, *tempe;
 
                /* Remove AGP resources, but leave dev->agp
@@ -194,7 +197,8 @@ int drm_lastclose(struct drm_device * dev)
                dev->agp->acquired = 0;
                dev->agp->enabled = 0;
        }
-       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
+       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg &&
+           !drm_core_check_feature(dev, DRIVER_MODESET)) {
                drm_sg_cleanup(dev->sg);
                dev->sg = NULL;
        }
@@ -205,13 +209,6 @@ int drm_lastclose(struct drm_device * dev)
                drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
        }
 
-       list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
-               if (!(r_list->map->flags & _DRM_DRIVER)) {
-                       drm_rmmap_locked(dev, r_list->map);
-                       r_list = NULL;
-               }
-       }
-
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
                for (i = 0; i < dev->queue_count; i++) {
                        if (dev->queuelist[i]) {
@@ -228,14 +225,11 @@ int drm_lastclose(struct drm_device * dev)
        }
        dev->queue_count = 0;
 
-       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
+       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
+           !drm_core_check_feature(dev, DRIVER_MODESET))
                drm_dma_takedown(dev);
 
-       if (dev->lock.hw_lock) {
-               dev->sigdata.lock = dev->lock.hw_lock = NULL;   /* SHM removed */
-               dev->lock.file_priv = NULL;
-               wake_up_interruptible(&dev->lock.lock_queue);
-       }
+       dev->dev_mapping = NULL;
        mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG("lastclose completed\n");
@@ -263,6 +257,8 @@ int drm_init(struct drm_driver *driver)
 
        DRM_DEBUG("\n");
 
+       INIT_LIST_HEAD(&driver->device_list);
+
        for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
                pid = (struct pci_device_id *)&driver->pci_driver.id_table[i];
 
@@ -329,35 +325,24 @@ static void drm_cleanup(struct drm_device * dev)
        drm_ht_remove(&dev->map_hash);
        drm_ctxbitmap_cleanup(dev);
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_put_minor(&dev->control);
+
+       if (dev->driver->driver_features & DRIVER_GEM)
+               drm_gem_destroy(dev);
+
        drm_put_minor(&dev->primary);
        if (drm_put_dev(dev))
                DRM_ERROR("Cannot unload module\n");
 }
 
-static int drm_minors_cleanup(int id, void *ptr, void *data)
-{
-       struct drm_minor *minor = ptr;
-       struct drm_device *dev;
-       struct drm_driver *driver = data;
-
-       dev = minor->dev;
-       if (minor->dev->driver != driver)
-               return 0;
-
-       if (minor->type != DRM_MINOR_LEGACY)
-               return 0;
-
-       if (dev)
-               pci_dev_put(dev->pdev);
-       drm_cleanup(dev);
-       return 1;
-}
-
 void drm_exit(struct drm_driver *driver)
 {
+       struct drm_device *dev, *tmp;
        DRM_DEBUG("\n");
 
-       idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver);
+       list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+               drm_cleanup(dev);
 
        DRM_INFO("Module unloaded\n");
 }
@@ -503,7 +488,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
                retcode = -EINVAL;
        } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
                   ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
-                  ((ioctl->flags & DRM_MASTER) && !file_priv->master)) {
+                  ((ioctl->flags & DRM_MASTER) && !file_priv->is_master)) {
                retcode = -EACCES;
        } else {
                if (cmd & (IOC_IN | IOC_OUT)) {
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
new file mode 100644 (file)
index 0000000..0fbb0da
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * Copyright (c) 2006 Luc Verhaegen (quirks list)
+ * Copyright (c) 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
+ * FB layer.
+ *   Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm_edid.h"
+
+/*
+ * TODO:
+ *   - support EDID 1.4 (incl. CE blocks)
+ */
+
+/*
+ * EDID blocks out in the wild have a variety of bugs, try to collect
+ * them here (note that userspace may work around broken monitors first,
+ * but fixes should make their way here so that the kernel "just works"
+ * on as many displays as possible).
+ */
+
+/* First detailed mode wrong, use largest 60Hz mode */
+#define EDID_QUIRK_PREFER_LARGE_60             (1 << 0)
+/* Reported 135MHz pixel clock is too high, needs adjustment */
+#define EDID_QUIRK_135_CLOCK_TOO_HIGH          (1 << 1)
+/* Prefer the largest mode at 75 Hz */
+#define EDID_QUIRK_PREFER_LARGE_75             (1 << 2)
+/* Detail timing is in cm not mm */
+#define EDID_QUIRK_DETAILED_IN_CM              (1 << 3)
+/* Detailed timing descriptors have bogus size values, so just take the
+ * maximum size and use that.
+ */
+#define EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE   (1 << 4)
+/* Monitor forgot to set the first detailed is preferred bit. */
+#define EDID_QUIRK_FIRST_DETAILED_PREFERRED    (1 << 5)
+/* use +hsync +vsync for detailed mode */
+#define EDID_QUIRK_DETAILED_SYNC_PP            (1 << 6)
+
+static struct edid_quirk {
+       char *vendor;
+       int product_id;
+       u32 quirks;
+} edid_quirk_list[] = {
+       /* Acer AL1706 */
+       { "ACR", 44358, EDID_QUIRK_PREFER_LARGE_60 },
+       /* Acer F51 */
+       { "API", 0x7602, EDID_QUIRK_PREFER_LARGE_60 },
+       /* Unknown Acer */
+       { "ACR", 2423, EDID_QUIRK_FIRST_DETAILED_PREFERRED },
+
+       /* Belinea 10 15 55 */
+       { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
+       { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
+
+       /* Envision Peripherals, Inc. EN-7100e */
+       { "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH },
+
+       /* Funai Electronics PM36B */
+       { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
+         EDID_QUIRK_DETAILED_IN_CM },
+
+       /* LG Philips LCD LP154W01-A5 */
+       { "LPL", 0, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
+       { "LPL", 0x2a00, EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE },
+
+       /* Philips 107p5 CRT */
+       { "PHL", 57364, EDID_QUIRK_FIRST_DETAILED_PREFERRED },
+
+       /* Proview AY765C */
+       { "PTS", 765, EDID_QUIRK_FIRST_DETAILED_PREFERRED },
+
+       /* Samsung SyncMaster 205BW.  Note: irony */
+       { "SAM", 541, EDID_QUIRK_DETAILED_SYNC_PP },
+       /* Samsung SyncMaster 22[5-6]BW */
+       { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 },
+       { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 },
+};
+
+
+/* Valid EDID header has these bytes */
+static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+
+/**
+ * edid_is_valid - sanity check EDID data
+ * @edid: EDID data
+ *
+ * Sanity check the EDID block by looking at the header, the version number
+ * and the checksum.  Return 0 if the EDID doesn't check out, or 1 if it's
+ * valid.
+ */
+static bool edid_is_valid(struct edid *edid)
+{
+       int i;
+       u8 csum = 0;
+       u8 *raw_edid = (u8 *)edid;
+
+       if (memcmp(edid->header, edid_header, sizeof(edid_header)))
+               goto bad;
+       if (edid->version != 1) {
+               DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
+               goto bad;
+       }
+       if (edid->revision <= 0 || edid->revision > 3) {
+               DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
+               goto bad;
+       }
+
+       for (i = 0; i < EDID_LENGTH; i++)
+               csum += raw_edid[i];
+       if (csum) {
+               DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
+               goto bad;
+       }
+
+       return 1;
+
+bad:
+       if (raw_edid) {
+               DRM_ERROR("Raw EDID:\n");
+               print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH);
+               printk("\n");
+       }
+       return 0;
+}
+
+/**
+ * edid_vendor - match a string against EDID's obfuscated vendor field
+ * @edid: EDID to match
+ * @vendor: vendor string
+ *
+ * Returns true if @vendor is in @edid, false otherwise
+ */
+static bool edid_vendor(struct edid *edid, char *vendor)
+{
+       char edid_vendor[3];
+
+       edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@';
+       edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) |
+                         ((edid->mfg_id[1] & 0xe0) >> 5)) + '@';
+       edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@';
+
+       return !strncmp(edid_vendor, vendor, 3);
+}
+
+/**
+ * edid_get_quirks - return quirk flags for a given EDID
+ * @edid: EDID to process
+ *
+ * This tells subsequent routines what fixes they need to apply.
+ */
+static u32 edid_get_quirks(struct edid *edid)
+{
+       struct edid_quirk *quirk;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) {
+               quirk = &edid_quirk_list[i];
+
+               if (edid_vendor(edid, quirk->vendor) &&
+                   (EDID_PRODUCT_ID(edid) == quirk->product_id))
+                       return quirk->quirks;
+       }
+
+       return 0;
+}
+
+#define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
+#define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh))
+
+
+/**
+ * edid_fixup_preferred - set preferred modes based on quirk list
+ * @connector: has mode list to fix up
+ * @quirks: quirks list
+ *
+ * Walk the mode list for @connector, clearing the preferred status
+ * on existing modes and setting it anew for the right mode ala @quirks.
+ */
+static void edid_fixup_preferred(struct drm_connector *connector,
+                                u32 quirks)
+{
+       struct drm_display_mode *t, *cur_mode, *preferred_mode;
+       int target_refresh = 0;
+
+       if (list_empty(&connector->probed_modes))
+               return;
+
+       if (quirks & EDID_QUIRK_PREFER_LARGE_60)
+               target_refresh = 60;
+       if (quirks & EDID_QUIRK_PREFER_LARGE_75)
+               target_refresh = 75;
+
+       preferred_mode = list_first_entry(&connector->probed_modes,
+                                         struct drm_display_mode, head);
+
+       list_for_each_entry_safe(cur_mode, t, &connector->probed_modes, head) {
+               cur_mode->type &= ~DRM_MODE_TYPE_PREFERRED;
+
+               if (cur_mode == preferred_mode)
+                       continue;
+
+               /* Largest mode is preferred */
+               if (MODE_SIZE(cur_mode) > MODE_SIZE(preferred_mode))
+                       preferred_mode = cur_mode;
+
+               /* At a given size, try to get closest to target refresh */
+               if ((MODE_SIZE(cur_mode) == MODE_SIZE(preferred_mode)) &&
+                   MODE_REFRESH_DIFF(cur_mode, target_refresh) <
+                   MODE_REFRESH_DIFF(preferred_mode, target_refresh)) {
+                       preferred_mode = cur_mode;
+               }
+       }
+
+       preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
+}
+
+/**
+ * drm_mode_std - convert standard mode info (width, height, refresh) into mode
+ * @t: standard timing params
+ *
+ * Take the standard timing params (in this case width, aspect, and refresh)
+ * and convert them into a real mode using CVT.
+ *
+ * Punts for now, but should eventually use the FB layer's CVT based mode
+ * generation code.
+ */
+struct drm_display_mode *drm_mode_std(struct drm_device *dev,
+                                     struct std_timing *t)
+{
+       struct drm_display_mode *mode;
+       int hsize = t->hsize * 8 + 248, vsize;
+
+       mode = drm_mode_create(dev);
+       if (!mode)
+               return NULL;
+
+       if (t->aspect_ratio == 0)
+               vsize = (hsize * 10) / 16;
+       else if (t->aspect_ratio == 1)
+               vsize = (hsize * 3) / 4;
+       else if (t->aspect_ratio == 2)
+               vsize = (hsize * 4) / 5;
+       else
+               vsize = (hsize * 9) / 16;
+
+       drm_mode_set_name(mode);
+
+       return mode;
+}
+
+/**
+ * drm_mode_detailed - create a new mode from an EDID detailed timing section
+ * @dev: DRM device (needed to create new mode)
+ * @edid: EDID block
+ * @timing: EDID detailed timing info
+ * @quirks: quirks to apply
+ *
+ * An EDID detailed timing block contains enough info for us to create and
+ * return a new struct drm_display_mode.
+ */
+static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
+                                                 struct edid *edid,
+                                                 struct detailed_timing *timing,
+                                                 u32 quirks)
+{
+       struct drm_display_mode *mode;
+       struct detailed_pixel_timing *pt = &timing->data.pixel_data;
+
+       if (pt->stereo) {
+               printk(KERN_WARNING "stereo mode not supported\n");
+               return NULL;
+       }
+       if (!pt->separate_sync) {
+               printk(KERN_WARNING "integrated sync not supported\n");
+               return NULL;
+       }
+
+       mode = drm_mode_create(dev);
+       if (!mode)
+               return NULL;
+
+       mode->type = DRM_MODE_TYPE_DRIVER;
+
+       if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH)
+               timing->pixel_clock = 1088;
+
+       mode->clock = timing->pixel_clock * 10;
+
+       mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo;
+       mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) |
+                                             pt->hsync_offset_lo);
+       mode->hsync_end = mode->hsync_start +
+               ((pt->hsync_pulse_width_hi << 8) |
+                pt->hsync_pulse_width_lo);
+       mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo);
+
+       mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
+       mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) |
+                                             pt->vsync_offset_lo);
+       mode->vsync_end = mode->vsync_start +
+               ((pt->vsync_pulse_width_hi << 8) |
+                pt->vsync_pulse_width_lo);
+       mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo);
+
+       drm_mode_set_name(mode);
+
+       if (pt->interlaced)
+               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+       if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
+               pt->hsync_positive = 1;
+               pt->vsync_positive = 1;
+       }
+
+       mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
+       mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
+
+       mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8);
+       mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8);
+
+       if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
+               mode->width_mm *= 10;
+               mode->height_mm *= 10;
+       }
+
+       if (quirks & EDID_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
+               mode->width_mm = edid->width_cm * 10;
+               mode->height_mm = edid->height_cm * 10;
+       }
+
+       return mode;
+}
+
+/*
+ * Detailed mode info for the EDID "established modes" data to use.
+ */
+static struct drm_display_mode edid_est_modes[] = {
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+                  968, 1056, 0, 600, 601, 605, 628, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+                  896, 1024, 0, 600, 601, 603,  625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+                  720, 840, 0, 480, 481, 484, 500, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+                  704,  832, 0, 480, 489, 491, 520, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
+                  768,  864, 0, 480, 483, 486, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
+                  752, 800, 0, 480, 490, 492, 525, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
+                  846, 900, 0, 400, 421, 423,  449, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
+                  846,  900, 0, 400, 412, 414, 449, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
+                  1136, 1312, 0,  768, 769, 772, 800, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+                  1184, 1328, 0,  768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+                  1184, 1344, 0,  768, 771, 777, 806, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+                  1208, 1264, 0, 768, 768, 776, 817, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
+       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
+                  928, 1152, 0, 624, 625, 628, 667, 0,
+                  DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+                  896, 1056, 0, 600, 601, 604,  625, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+                  976, 1040, 0, 600, 637, 643, 666, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
+       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+                  1344, 1600, 0,  864, 865, 868, 900, 0,
+                  DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
+};
+
+#define EDID_EST_TIMINGS 16
+#define EDID_STD_TIMINGS 8
+#define EDID_DETAILED_TIMINGS 4
+
+/**
+ * add_established_modes - get est. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Each EDID block contains a bitmap of the supported "established modes" list
+ * (defined above).  Tease them out and add them to the global modes list.
+ */
+static int add_established_modes(struct drm_connector *connector, struct edid *edid)
+{
+       struct drm_device *dev = connector->dev;
+       unsigned long est_bits = edid->established_timings.t1 |
+               (edid->established_timings.t2 << 8) |
+               ((edid->established_timings.mfg_rsvd & 0x80) << 9);
+       int i, modes = 0;
+
+       for (i = 0; i <= EDID_EST_TIMINGS; i++)
+               if (est_bits & (1<<i)) {
+                       struct drm_display_mode *newmode;
+                       newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
+                       if (newmode) {
+                               drm_mode_probed_add(connector, newmode);
+                               modes++;
+                       }
+               }
+
+       return modes;
+}
+
+/**
+ * add_standard_modes - get std. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Standard modes can be calculated using the CVT standard.  Grab them from
+ * @edid, calculate them, and add them to the list.
+ */
+static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
+{
+       struct drm_device *dev = connector->dev;
+       int i, modes = 0;
+
+       for (i = 0; i < EDID_STD_TIMINGS; i++) {
+               struct std_timing *t = &edid->standard_timings[i];
+               struct drm_display_mode *newmode;
+
+               /* If std timings bytes are 1, 1 it's empty */
+               if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1)
+                       continue;
+
+               newmode = drm_mode_std(dev, &edid->standard_timings[i]);
+               if (newmode) {
+                       drm_mode_probed_add(connector, newmode);
+                       modes++;
+               }
+       }
+
+       return modes;
+}
+
+/**
+ * add_detailed_modes - get detailed mode info from EDID data
+ * @connector: attached connector
+ * @edid: EDID block to scan
+ * @quirks: quirks to apply
+ *
+ * Some of the detailed timing sections may contain mode information.  Grab
+ * it and add it to the list.
+ */
+static int add_detailed_info(struct drm_connector *connector,
+                            struct edid *edid, u32 quirks)
+{
+       struct drm_device *dev = connector->dev;
+       int i, j, modes = 0;
+
+       for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
+               struct detailed_timing *timing = &edid->detailed_timings[i];
+               struct detailed_non_pixel *data = &timing->data.other_data;
+               struct drm_display_mode *newmode;
+
+               /* EDID up to and including 1.2 may put monitor info here */
+               if (edid->version == 1 && edid->revision < 3)
+                       continue;
+
+               /* Detailed mode timing */
+               if (timing->pixel_clock) {
+                       newmode = drm_mode_detailed(dev, edid, timing, quirks);
+                       if (!newmode)
+                               continue;
+
+                       /* First detailed mode is preferred */
+                       if (i == 0 && edid->preferred_timing)
+                               newmode->type |= DRM_MODE_TYPE_PREFERRED;
+                       drm_mode_probed_add(connector, newmode);
+
+                       modes++;
+                       continue;
+               }
+
+               /* Other timing or info */
+               switch (data->type) {
+               case EDID_DETAIL_MONITOR_SERIAL:
+                       break;
+               case EDID_DETAIL_MONITOR_STRING:
+                       break;
+               case EDID_DETAIL_MONITOR_RANGE:
+                       /* Get monitor range data */
+                       break;
+               case EDID_DETAIL_MONITOR_NAME:
+                       break;
+               case EDID_DETAIL_MONITOR_CPDATA:
+                       break;
+               case EDID_DETAIL_STD_MODES:
+                       /* Five modes per detailed section */
+                       for (j = 0; j < 5; i++) {
+                               struct std_timing *std;
+                               struct drm_display_mode *newmode;
+
+                               std = &data->data.timings[j];
+                               newmode = drm_mode_std(dev, std);
+                               if (newmode) {
+                                       drm_mode_probed_add(connector, newmode);
+                                       modes++;
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return modes;
+}
+
+#define DDC_ADDR 0x50
+
+unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
+{
+       unsigned char start = 0x0;
+       unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = DDC_ADDR,
+                       .flags  = 0,
+                       .len    = 1,
+                       .buf    = &start,
+               }, {
+                       .addr   = DDC_ADDR,
+                       .flags  = I2C_M_RD,
+                       .len    = EDID_LENGTH,
+                       .buf    = buf,
+               }
+       };
+
+       if (!buf) {
+               dev_warn(&adapter->dev, "unable to allocate memory for EDID "
+                        "block.\n");
+               return NULL;
+       }
+
+       if (i2c_transfer(adapter, msgs, 2) == 2)
+               return buf;
+
+       dev_info(&adapter->dev, "unable to read EDID block.\n");
+       kfree(buf);
+       return NULL;
+}
+EXPORT_SYMBOL(drm_do_probe_ddc_edid);
+
+static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
+{
+       struct i2c_algo_bit_data *algo_data = adapter->algo_data;
+       unsigned char *edid = NULL;
+       int i, j;
+
+       algo_data->setscl(algo_data->data, 1);
+
+       for (i = 0; i < 1; i++) {
+               /* For some old monitors we need the
+                * following process to initialize/stop DDC
+                */
+               algo_data->setsda(algo_data->data, 1);
+               msleep(13);
+
+               algo_data->setscl(algo_data->data, 1);
+               for (j = 0; j < 5; j++) {
+                       msleep(10);
+                       if (algo_data->getscl(algo_data->data))
+                               break;
+               }
+               if (j == 5)
+                       continue;
+
+               algo_data->setsda(algo_data->data, 0);
+               msleep(15);
+               algo_data->setscl(algo_data->data, 0);
+               msleep(15);
+               algo_data->setsda(algo_data->data, 1);
+               msleep(15);
+
+               /* Do the real work */
+               edid = drm_do_probe_ddc_edid(adapter);
+               algo_data->setsda(algo_data->data, 0);
+               algo_data->setscl(algo_data->data, 0);
+               msleep(15);
+
+               algo_data->setscl(algo_data->data, 1);
+               for (j = 0; j < 10; j++) {
+                       msleep(10);
+                       if (algo_data->getscl(algo_data->data))
+                               break;
+               }
+
+               algo_data->setsda(algo_data->data, 1);
+               msleep(15);
+               algo_data->setscl(algo_data->data, 0);
+               algo_data->setsda(algo_data->data, 0);
+               if (edid)
+                       break;
+       }
+       /* Release the DDC lines when done or the Apple Cinema HD display
+        * will switch off
+        */
+       algo_data->setsda(algo_data->data, 1);
+       algo_data->setscl(algo_data->data, 1);
+
+       return edid;
+}
+
+/**
+ * drm_get_edid - get EDID data, if available
+ * @connector: connector we're probing
+ * @adapter: i2c adapter to use for DDC
+ *
+ * Poke the given connector's i2c channel to grab EDID data if possible.
+ *
+ * Return edid data or NULL if we couldn't find any.
+ */
+struct edid *drm_get_edid(struct drm_connector *connector,
+                         struct i2c_adapter *adapter)
+{
+       struct edid *edid;
+
+       edid = (struct edid *)drm_ddc_read(adapter);
+       if (!edid) {
+               dev_warn(&connector->dev->pdev->dev, "%s: no EDID data\n",
+                        drm_get_connector_name(connector));
+               return NULL;
+       }
+       if (!edid_is_valid(edid)) {
+               dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
+                        drm_get_connector_name(connector));
+               kfree(edid);
+               return NULL;
+       }
+
+       connector->display_info.raw_edid = (char *)edid;
+
+       return edid;
+}
+EXPORT_SYMBOL(drm_get_edid);
+
+/**
+ * drm_add_edid_modes - add modes from EDID data, if available
+ * @connector: connector we're probing
+ * @edid: edid data
+ *
+ * Add the specified modes to the connector's mode list.
+ *
+ * Return number of modes added or 0 if we couldn't find any.
+ */
+int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
+{
+       int num_modes = 0;
+       u32 quirks;
+
+       if (edid == NULL) {
+               return 0;
+       }
+       if (!edid_is_valid(edid)) {
+               dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n",
+                        drm_get_connector_name(connector));
+               return 0;
+       }
+
+       quirks = edid_get_quirks(edid);
+
+       num_modes += add_established_modes(connector, edid);
+       num_modes += add_standard_modes(connector, edid);
+       num_modes += add_detailed_info(connector, edid, quirks);
+
+       if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
+               edid_fixup_preferred(connector, quirks);
+
+       connector->display_info.serration_vsync = edid->serration_vsync;
+       connector->display_info.sync_on_green = edid->sync_on_green;
+       connector->display_info.composite_sync = edid->composite_sync;
+       connector->display_info.separate_syncs = edid->separate_syncs;
+       connector->display_info.blank_to_black = edid->blank_to_black;
+       connector->display_info.video_level = edid->video_level;
+       connector->display_info.digital = edid->digital;
+       connector->display_info.width_mm = edid->width_cm * 10;
+       connector->display_info.height_mm = edid->height_cm * 10;
+       connector->display_info.gamma = edid->gamma;
+       connector->display_info.gtf_supported = edid->default_gtf;
+       connector->display_info.standard_color = edid->standard_color;
+       connector->display_info.display_type = edid->display_type;
+       connector->display_info.active_off_supported = edid->pm_active_off;
+       connector->display_info.suspend_supported = edid->pm_suspend;
+       connector->display_info.standby_supported = edid->pm_standby;
+       connector->display_info.gamma = edid->gamma;
+
+       return num_modes;
+}
+EXPORT_SYMBOL(drm_add_edid_modes);
index 78eeed5caaff1ed68ed01cb2cd27a2ed156caa49..3733e36d135ed2700e221fb6609a0b8809c481c5 100644 (file)
@@ -35,7 +35,6 @@
  */
 
 #include "drmP.h"
-#include "drm_sarea.h"
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 
@@ -44,10 +43,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
 static int drm_setup(struct drm_device * dev)
 {
-       drm_local_map_t *map;
        int i;
        int ret;
-       u32 sareapage;
 
        if (dev->driver->firstopen) {
                ret = dev->driver->firstopen(dev);
@@ -55,20 +52,14 @@ static int drm_setup(struct drm_device * dev)
                        return ret;
        }
 
-       dev->magicfree.next = NULL;
-
-       /* prebuild the SAREA */
-       sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
-       i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
-       if (i != 0)
-               return i;
-
        atomic_set(&dev->ioctl_count, 0);
        atomic_set(&dev->vma_count, 0);
-       dev->buf_use = 0;
-       atomic_set(&dev->buf_alloc, 0);
 
-       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
+       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
+           !drm_core_check_feature(dev, DRIVER_MODESET)) {
+               dev->buf_use = 0;
+               atomic_set(&dev->buf_alloc, 0);
+
                i = drm_dma_setup(dev);
                if (i < 0)
                        return i;
@@ -77,16 +68,12 @@ static int drm_setup(struct drm_device * dev)
        for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
                atomic_set(&dev->counts[i], 0);
 
-       drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
-       INIT_LIST_HEAD(&dev->magicfree);
-
        dev->sigdata.lock = NULL;
-       init_waitqueue_head(&dev->lock.lock_queue);
+
        dev->queue_count = 0;
        dev->queue_reserved = 0;
        dev->queue_slots = 0;
        dev->queuelist = NULL;
-       dev->irq_enabled = 0;
        dev->context_flag = 0;
        dev->interrupt_flag = 0;
        dev->dma_flag = 0;
@@ -147,10 +134,20 @@ int drm_open(struct inode *inode, struct file *filp)
                spin_lock(&dev->count_lock);
                if (!dev->open_count++) {
                        spin_unlock(&dev->count_lock);
-                       return drm_setup(dev);
+                       retcode = drm_setup(dev);
+                       goto out;
                }
                spin_unlock(&dev->count_lock);
        }
+out:
+       mutex_lock(&dev->struct_mutex);
+       if (minor->type == DRM_MINOR_LEGACY) {
+               BUG_ON((dev->dev_mapping != NULL) &&
+                       (dev->dev_mapping != inode->i_mapping));
+               if (dev->dev_mapping == NULL)
+                       dev->dev_mapping = inode->i_mapping;
+       }
+       mutex_unlock(&dev->struct_mutex);
 
        return retcode;
 }
@@ -255,6 +252,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        priv->lock_count = 0;
 
        INIT_LIST_HEAD(&priv->lhead);
+       INIT_LIST_HEAD(&priv->fbs);
 
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_open(dev, priv);
@@ -265,10 +263,42 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                        goto out_free;
        }
 
+
+       /* if there is no current master make this fd it */
        mutex_lock(&dev->struct_mutex);
-       if (list_empty(&dev->filelist))
-               priv->master = 1;
+       if (!priv->minor->master) {
+               /* create a new master */
+               priv->minor->master = drm_master_create(priv->minor);
+               if (!priv->minor->master) {
+                       ret = -ENOMEM;
+                       goto out_free;
+               }
 
+               priv->is_master = 1;
+               /* take another reference for the copy in the local file priv */
+               priv->master = drm_master_get(priv->minor->master);
+
+               priv->authenticated = 1;
+
+               mutex_unlock(&dev->struct_mutex);
+               if (dev->driver->master_create) {
+                       ret = dev->driver->master_create(dev, priv->master);
+                       if (ret) {
+                               mutex_lock(&dev->struct_mutex);
+                               /* drop both references if this fails */
+                               drm_master_put(&priv->minor->master);
+                               drm_master_put(&priv->master);
+                               mutex_unlock(&dev->struct_mutex);
+                               goto out_free;
+                       }
+               }
+       } else {
+               /* get a reference to the master */
+               priv->master = drm_master_get(priv->minor->master);
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       mutex_lock(&dev->struct_mutex);
        list_add(&priv->lhead, &dev->filelist);
        mutex_unlock(&dev->struct_mutex);
 
@@ -314,6 +344,74 @@ int drm_fasync(int fd, struct file *filp, int on)
 }
 EXPORT_SYMBOL(drm_fasync);
 
+/*
+ * Reclaim locked buffers; note that this may be a bad idea if the current
+ * context doesn't have the hw lock...
+ */
+static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f)
+{
+       struct drm_file *file_priv = f->private_data;
+
+       if (drm_i_have_hw_lock(dev, file_priv)) {
+               dev->driver->reclaim_buffers_locked(dev, file_priv);
+       } else {
+               unsigned long _end = jiffies + 3 * DRM_HZ;
+               int locked = 0;
+
+               drm_idlelock_take(&file_priv->master->lock);
+
+               /*
+                * Wait for a while.
+                */
+               do {
+                       spin_lock_bh(&file_priv->master->lock.spinlock);
+                       locked = file_priv->master->lock.idle_has_lock;
+                       spin_unlock_bh(&file_priv->master->lock.spinlock);
+                       if (locked)
+                               break;
+                       schedule();
+               } while (!time_after_eq(jiffies, _end));
+
+               if (!locked) {
+                       DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
+                                 "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
+                                 "\tI will go on reclaiming the buffers anyway.\n");
+               }
+
+               dev->driver->reclaim_buffers_locked(dev, file_priv);
+               drm_idlelock_release(&file_priv->master->lock);
+       }
+}
+
+static void drm_master_release(struct drm_device *dev, struct file *filp)
+{
+       struct drm_file *file_priv = filp->private_data;
+
+       if (dev->driver->reclaim_buffers_locked &&
+           file_priv->master->lock.hw_lock)
+               drm_reclaim_locked_buffers(dev, filp);
+
+       if (dev->driver->reclaim_buffers_idlelocked &&
+           file_priv->master->lock.hw_lock) {
+               drm_idlelock_take(&file_priv->master->lock);
+               dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
+               drm_idlelock_release(&file_priv->master->lock);
+       }
+
+
+       if (drm_i_have_hw_lock(dev, file_priv)) {
+               DRM_DEBUG("File %p released, freeing lock for context %d\n",
+                         filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+               drm_lock_free(&file_priv->master->lock,
+                             _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
+       }
+
+       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
+           !dev->driver->reclaim_buffers_locked) {
+               dev->driver->reclaim_buffers(dev, file_priv);
+       }
+}
+
 /**
  * Release file.
  *
@@ -348,60 +446,9 @@ int drm_release(struct inode *inode, struct file *filp)
                  (long)old_encode_dev(file_priv->minor->device),
                  dev->open_count);
 
-       if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
-               if (drm_i_have_hw_lock(dev, file_priv)) {
-                       dev->driver->reclaim_buffers_locked(dev, file_priv);
-               } else {
-                       unsigned long endtime = jiffies + 3 * DRM_HZ;
-                       int locked = 0;
-
-                       drm_idlelock_take(&dev->lock);
-
-                       /*
-                        * Wait for a while.
-                        */
-
-                       do{
-                               spin_lock_bh(&dev->lock.spinlock);
-                               locked = dev->lock.idle_has_lock;
-                               spin_unlock_bh(&dev->lock.spinlock);
-                               if (locked)
-                                       break;
-                               schedule();
-                       } while (!time_after_eq(jiffies, endtime));
-
-                       if (!locked) {
-                               DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
-                                         "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
-                                         "\tI will go on reclaiming the buffers anyway.\n");
-                       }
-
-                       dev->driver->reclaim_buffers_locked(dev, file_priv);
-                       drm_idlelock_release(&dev->lock);
-               }
-       }
-
-       if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
-
-               drm_idlelock_take(&dev->lock);
-               dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
-               drm_idlelock_release(&dev->lock);
-
-       }
-
-       if (drm_i_have_hw_lock(dev, file_priv)) {
-               DRM_DEBUG("File %p released, freeing lock for context %d\n",
-                         filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
-               drm_lock_free(&dev->lock,
-                             _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-       }
-
-
-       if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
-           !dev->driver->reclaim_buffers_locked) {
-               dev->driver->reclaim_buffers(dev, file_priv);
-       }
+       /* if the master has gone away we can't do anything with the lock */
+       if (file_priv->minor->master)
+               drm_master_release(dev, filp);
 
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, file_priv);
@@ -428,12 +475,24 @@ int drm_release(struct inode *inode, struct file *filp)
        mutex_unlock(&dev->ctxlist_mutex);
 
        mutex_lock(&dev->struct_mutex);
-       if (file_priv->remove_auth_on_close == 1) {
+
+       if (file_priv->is_master) {
                struct drm_file *temp;
+               list_for_each_entry(temp, &dev->filelist, lhead) {
+                       if ((temp->master == file_priv->master) &&
+                           (temp != file_priv))
+                               temp->authenticated = 0;
+               }
 
-               list_for_each_entry(temp, &dev->filelist, lhead)
-                       temp->authenticated = 0;
+               if (file_priv->minor->master == file_priv->master) {
+                       /* drop the reference held my the minor */
+                       drm_master_put(&file_priv->minor->master);
+               }
        }
+
+       /* drop the reference held my the file priv */
+       drm_master_put(&file_priv->master);
+       file_priv->is_master = 0;
        list_del(&file_priv->lhead);
        mutex_unlock(&dev->struct_mutex);
 
@@ -448,9 +507,9 @@ int drm_release(struct inode *inode, struct file *filp)
        atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
        spin_lock(&dev->count_lock);
        if (!--dev->open_count) {
-               if (atomic_read(&dev->ioctl_count) || dev->blocked) {
-                       DRM_ERROR("Device busy: %d %d\n",
-                                 atomic_read(&dev->ioctl_count), dev->blocked);
+               if (atomic_read(&dev->ioctl_count)) {
+                       DRM_ERROR("Device busy: %d\n",
+                                 atomic_read(&dev->ioctl_count));
                        spin_unlock(&dev->count_lock);
                        unlock_kernel();
                        return -EBUSY;
index ccd1afdede0249f5109e614732d85e67bbfd8b4b..9da5814528749a82b4ef12a1b13134d34635557b 100644 (file)
  * up at a later date, and as our interface with shmfs for memory allocation.
  */
 
+/*
+ * We make up offsets for buffer objects so we can recognize them at
+ * mmap time.
+ */
+#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
+#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
+
 /**
  * Initialize the GEM device fields
  */
@@ -71,6 +78,8 @@
 int
 drm_gem_init(struct drm_device *dev)
 {
+       struct drm_gem_mm *mm;
+
        spin_lock_init(&dev->object_name_lock);
        idr_init(&dev->object_name_idr);
        atomic_set(&dev->object_count, 0);
@@ -79,9 +88,41 @@ drm_gem_init(struct drm_device *dev)
        atomic_set(&dev->pin_memory, 0);
        atomic_set(&dev->gtt_count, 0);
        atomic_set(&dev->gtt_memory, 0);
+
+       mm = drm_calloc(1, sizeof(struct drm_gem_mm), DRM_MEM_MM);
+       if (!mm) {
+               DRM_ERROR("out of memory\n");
+               return -ENOMEM;
+       }
+
+       dev->mm_private = mm;
+
+       if (drm_ht_create(&mm->offset_hash, 19)) {
+               drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
+               return -ENOMEM;
+       }
+
+       if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
+                       DRM_FILE_PAGE_OFFSET_SIZE)) {
+               drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
+               drm_ht_remove(&mm->offset_hash);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
+void
+drm_gem_destroy(struct drm_device *dev)
+{
+       struct drm_gem_mm *mm = dev->mm_private;
+
+       drm_mm_takedown(&mm->offset_manager);
+       drm_ht_remove(&mm->offset_hash);
+       drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
+       dev->mm_private = NULL;
+}
+
 /**
  * Allocate a GEM object of the specified size with shmfs backing store
  */
@@ -419,3 +460,73 @@ drm_gem_object_handle_free(struct kref *kref)
 }
 EXPORT_SYMBOL(drm_gem_object_handle_free);
 
+/**
+ * drm_gem_mmap - memory map routine for GEM objects
+ * @filp: DRM file pointer
+ * @vma: VMA for the area to be mapped
+ *
+ * If a driver supports GEM object mapping, mmap calls on the DRM file
+ * descriptor will end up here.
+ *
+ * If we find the object based on the offset passed in (vma->vm_pgoff will
+ * contain the fake offset we created when the GTT map ioctl was called on
+ * the object), we set up the driver fault handler so that any accesses
+ * to the object can be trapped, to perform migration, GTT binding, surface
+ * register allocation, or performance monitoring.
+ */
+int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *priv = filp->private_data;
+       struct drm_device *dev = priv->minor->dev;
+       struct drm_gem_mm *mm = dev->mm_private;
+       struct drm_map *map = NULL;
+       struct drm_gem_object *obj;
+       struct drm_hash_item *hash;
+       unsigned long prot;
+       int ret = 0;
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
+               mutex_unlock(&dev->struct_mutex);
+               return drm_mmap(filp, vma);
+       }
+
+       map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
+       if (!map ||
+           ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
+               ret =  -EPERM;
+               goto out_unlock;
+       }
+
+       /* Check for valid size. */
+       if (map->size < vma->vm_end - vma->vm_start) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       obj = map->handle;
+       if (!obj->dev->driver->gem_vm_ops) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
+       vma->vm_ops = obj->dev->driver->gem_vm_ops;
+       vma->vm_private_data = map->handle;
+       /* FIXME: use pgprot_writecombine when available */
+       prot = pgprot_val(vma->vm_page_prot);
+#ifdef CONFIG_X86
+       prot |= _PAGE_CACHE_WC;
+#endif
+       vma->vm_page_prot = __pgprot(prot);
+
+       vma->vm_file = filp;    /* Needed for drm_vm_open() */
+       drm_vm_open_locked(vma);
+
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_gem_mmap);
index 33160673a7b7846406400226665ae68c409e5e73..af539f7d87dd2639bafe0c1576e069d4c971da1e 100644 (file)
@@ -127,6 +127,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
        }
        return 0;
 }
+EXPORT_SYMBOL(drm_ht_insert_item);
 
 /*
  * Just insert an item and return any "bits" bit key that hasn't been
@@ -188,6 +189,7 @@ int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
        ht->fill--;
        return 0;
 }
+EXPORT_SYMBOL(drm_ht_remove_item);
 
 void drm_ht_remove(struct drm_open_hash *ht)
 {
index 16829fb3089d8adbfadda119d427e65bcaa8157c..1fad76289e665d0cfbc6f7026f6f568ff6809a53 100644 (file)
@@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_unique *u = data;
+       struct drm_master *master = file_priv->master;
 
-       if (u->unique_len >= dev->unique_len) {
-               if (copy_to_user(u->unique, dev->unique, dev->unique_len))
+       if (u->unique_len >= master->unique_len) {
+               if (copy_to_user(u->unique, master->unique, master->unique_len))
                        return -EFAULT;
        }
-       u->unique_len = dev->unique_len;
+       u->unique_len = master->unique_len;
 
        return 0;
 }
@@ -81,36 +82,38 @@ int drm_setunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_unique *u = data;
+       struct drm_master *master = file_priv->master;
        int domain, bus, slot, func, ret;
 
-       if (dev->unique_len || dev->unique)
+       if (master->unique_len || master->unique)
                return -EBUSY;
 
        if (!u->unique_len || u->unique_len > 1024)
                return -EINVAL;
 
-       dev->unique_len = u->unique_len;
-       dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
-       if (!dev->unique)
+       master->unique_len = u->unique_len;
+       master->unique_size = u->unique_len + 1;
+       master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER);
+       if (!master->unique)
                return -ENOMEM;
-       if (copy_from_user(dev->unique, u->unique, dev->unique_len))
+       if (copy_from_user(master->unique, u->unique, master->unique_len))
                return -EFAULT;
 
-       dev->unique[dev->unique_len] = '\0';
+       master->unique[master->unique_len] = '\0';
 
        dev->devname =
            drm_alloc(strlen(dev->driver->pci_driver.name) +
-                     strlen(dev->unique) + 2, DRM_MEM_DRIVER);
+                     strlen(master->unique) + 2, DRM_MEM_DRIVER);
        if (!dev->devname)
                return -ENOMEM;
 
        sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
-               dev->unique);
+               master->unique);
 
        /* Return error if the busid submitted doesn't match the device's actual
         * busid.
         */
-       ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+       ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
        if (ret != 3)
                return -EINVAL;
        domain = bus >> 8;
@@ -125,34 +128,38 @@ int drm_setunique(struct drm_device *dev, void *data,
        return 0;
 }
 
-static int drm_set_busid(struct drm_device * dev)
+static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
 {
+       struct drm_master *master = file_priv->master;
        int len;
 
-       if (dev->unique != NULL)
-               return 0;
+       if (master->unique != NULL)
+               return -EBUSY;
 
-       dev->unique_len = 40;
-       dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
-       if (dev->unique == NULL)
+       master->unique_len = 40;
+       master->unique_size = master->unique_len;
+       master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER);
+       if (master->unique == NULL)
                return -ENOMEM;
 
-       len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
-                      drm_get_pci_domain(dev), dev->pdev->bus->number,
+       len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
+                      drm_get_pci_domain(dev),
+                      dev->pdev->bus->number,
                       PCI_SLOT(dev->pdev->devfn),
                       PCI_FUNC(dev->pdev->devfn));
-
-       if (len > dev->unique_len)
-               DRM_ERROR("Unique buffer overflowed\n");
+       if (len >= master->unique_len)
+               DRM_ERROR("buffer overflow");
+       else
+               master->unique_len = len;
 
        dev->devname =
-           drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
+           drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len +
                      2, DRM_MEM_DRIVER);
        if (dev->devname == NULL)
                return -ENOMEM;
 
        sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
-               dev->unique);
+               master->unique);
 
        return 0;
 }
@@ -276,7 +283,7 @@ int drm_getstats(struct drm_device *dev, void *data,
        for (i = 0; i < dev->counters; i++) {
                if (dev->types[i] == _DRM_STAT_LOCK)
                        stats->data[i].value =
-                           (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
+                           (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0);
                else
                        stats->data[i].value = atomic_read(&dev->counts[i]);
                stats->data[i].type = dev->types[i];
@@ -318,7 +325,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
                        /*
                         * Version 1.1 includes tying of DRM to specific device
                         */
-                       drm_set_busid(dev);
+                       drm_set_busid(dev, file_priv);
                }
        }
 
index 1e787f894b3cf38f6c46eeda39c73cb8a49ad1c5..724e505873cf19e77c6710968a1a8ba6888cedd2 100644 (file)
@@ -116,6 +116,9 @@ void drm_vblank_cleanup(struct drm_device *dev)
                 dev->num_crtcs, DRM_MEM_DRIVER);
        drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs,
                 DRM_MEM_DRIVER);
+       drm_free(dev->last_vblank_wait,
+                sizeof(*dev->last_vblank_wait) * dev->num_crtcs,
+                DRM_MEM_DRIVER);
        drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) *
                 dev->num_crtcs, DRM_MEM_DRIVER);
 
@@ -161,6 +164,11 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
        if (!dev->last_vblank)
                goto err;
 
+       dev->last_vblank_wait = drm_calloc(num_crtcs, sizeof(u32),
+                                          DRM_MEM_DRIVER);
+       if (!dev->last_vblank_wait)
+               goto err;
+
        dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int),
                                         DRM_MEM_DRIVER);
        if (!dev->vblank_inmodeset)
@@ -305,6 +313,8 @@ int drm_control(struct drm_device *dev, void *data,
        case DRM_INST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       return 0;
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
                    ctl->irq != dev->pdev->irq)
                        return -EINVAL;
@@ -312,6 +322,8 @@ int drm_control(struct drm_device *dev, void *data,
        case DRM_UNINST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       return 0;
                return drm_irq_uninstall(dev);
        default:
                return -EINVAL;
@@ -426,6 +438,45 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
+/**
+ * drm_vblank_pre_modeset - account for vblanks across mode sets
+ * @dev: DRM device
+ * @crtc: CRTC in question
+ * @post: post or pre mode set?
+ *
+ * Account for vblank events across mode setting events, which will likely
+ * reset the hardware frame counter.
+ */
+void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
+{
+       /*
+        * To avoid all the problems that might happen if interrupts
+        * were enabled/disabled around or between these calls, we just
+        * have the kernel take a reference on the CRTC (just once though
+        * to avoid corrupting the count if multiple, mismatch calls occur),
+        * so that interrupts remain enabled in the interim.
+        */
+       if (!dev->vblank_inmodeset[crtc]) {
+               dev->vblank_inmodeset[crtc] = 1;
+               drm_vblank_get(dev, crtc);
+       }
+}
+EXPORT_SYMBOL(drm_vblank_pre_modeset);
+
+void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
+{
+       unsigned long irqflags;
+
+       if (dev->vblank_inmodeset[crtc]) {
+               spin_lock_irqsave(&dev->vbl_lock, irqflags);
+               dev->vblank_disable_allowed = 1;
+               dev->vblank_inmodeset[crtc] = 0;
+               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+               drm_vblank_put(dev, crtc);
+       }
+}
+EXPORT_SYMBOL(drm_vblank_post_modeset);
+
 /**
  * drm_modeset_ctl - handle vblank event counter changes across mode switch
  * @DRM_IOCTL_ARGS: standard ioctl arguments
@@ -441,7 +492,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       unsigned long irqflags;
        int crtc, ret = 0;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
@@ -454,28 +504,12 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                goto out;
        }
 
-       /*
-        * To avoid all the problems that might happen if interrupts
-        * were enabled/disabled around or between these calls, we just
-        * have the kernel take a reference on the CRTC (just once though
-        * to avoid corrupting the count if multiple, mismatch calls occur),
-        * so that interrupts remain enabled in the interim.
-        */
        switch (modeset->cmd) {
        case _DRM_PRE_MODESET:
-               if (!dev->vblank_inmodeset[crtc]) {
-                       dev->vblank_inmodeset[crtc] = 1;
-                       drm_vblank_get(dev, crtc);
-               }
+               drm_vblank_pre_modeset(dev, crtc);
                break;
        case _DRM_POST_MODESET:
-               if (dev->vblank_inmodeset[crtc]) {
-                       spin_lock_irqsave(&dev->vbl_lock, irqflags);
-                       dev->vblank_disable_allowed = 1;
-                       dev->vblank_inmodeset[crtc] = 0;
-                       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-                       drm_vblank_put(dev, crtc);
-               }
+               drm_vblank_post_modeset(dev, crtc);
                break;
        default:
                ret = -EINVAL;
@@ -616,6 +650,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
        } else {
                DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
                          vblwait->request.sequence, crtc);
+               dev->last_vblank_wait[crtc] = vblwait->request.sequence;
                DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
                            ((drm_vblank_count(dev, crtc)
                              - vblwait->request.sequence) <= (1 << 23)));
index 1cfa72031f8f6291f18fce595c0c7e179cea07d5..46e7b28f0707397d545948dc21bbcc272f16eb6f 100644 (file)
@@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        DECLARE_WAITQUEUE(entry, current);
        struct drm_lock *lock = data;
+       struct drm_master *master = file_priv->master;
        int ret = 0;
 
        ++file_priv->lock_count;
@@ -64,26 +65,27 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
                  lock->context, task_pid_nr(current),
-                 dev->lock.hw_lock->lock, lock->flags);
+                 master->lock.hw_lock->lock, lock->flags);
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
                if (lock->context < 0)
                        return -EINVAL;
 
-       add_wait_queue(&dev->lock.lock_queue, &entry);
-       spin_lock_bh(&dev->lock.spinlock);
-       dev->lock.user_waiters++;
-       spin_unlock_bh(&dev->lock.spinlock);
+       add_wait_queue(&master->lock.lock_queue, &entry);
+       spin_lock_bh(&master->lock.spinlock);
+       master->lock.user_waiters++;
+       spin_unlock_bh(&master->lock.spinlock);
+
        for (;;) {
                __set_current_state(TASK_INTERRUPTIBLE);
-               if (!dev->lock.hw_lock) {
+               if (!master->lock.hw_lock) {
                        /* Device has been unregistered */
                        ret = -EINTR;
                        break;
                }
-               if (drm_lock_take(&dev->lock, lock->context)) {
-                       dev->lock.file_priv = file_priv;
-                       dev->lock.lock_time = jiffies;
+               if (drm_lock_take(&master->lock, lock->context)) {
+                       master->lock.file_priv = file_priv;
+                       master->lock.lock_time = jiffies;
                        atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
                        break;  /* Got lock */
                }
@@ -95,11 +97,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                        break;
                }
        }
-       spin_lock_bh(&dev->lock.spinlock);
-       dev->lock.user_waiters--;
-       spin_unlock_bh(&dev->lock.spinlock);
+       spin_lock_bh(&master->lock.spinlock);
+       master->lock.user_waiters--;
+       spin_unlock_bh(&master->lock.spinlock);
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&dev->lock.lock_queue, &entry);
+       remove_wait_queue(&master->lock.lock_queue, &entry);
 
        DRM_DEBUG("%d %s\n", lock->context,
                  ret ? "interrupted" : "has lock");
@@ -108,14 +110,14 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
        /* don't set the block all signals on the master process for now 
         * really probably not the correct answer but lets us debug xkb
         * xserver for now */
-       if (!file_priv->master) {
+       if (!file_priv->is_master) {
                sigemptyset(&dev->sigmask);
                sigaddset(&dev->sigmask, SIGSTOP);
                sigaddset(&dev->sigmask, SIGTSTP);
                sigaddset(&dev->sigmask, SIGTTIN);
                sigaddset(&dev->sigmask, SIGTTOU);
                dev->sigdata.context = lock->context;
-               dev->sigdata.lock = dev->lock.hw_lock;
+               dev->sigdata.lock = master->lock.hw_lock;
                block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
        }
 
@@ -154,6 +156,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_lock *lock = data;
+       struct drm_master *master = file_priv->master;
 
        if (lock->context == DRM_KERNEL_CONTEXT) {
                DRM_ERROR("Process %d using kernel context %d\n",
@@ -169,7 +172,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
        if (dev->driver->kernel_context_switch_unlock)
                dev->driver->kernel_context_switch_unlock(dev);
        else {
-               if (drm_lock_free(&dev->lock,lock->context)) {
+               if (drm_lock_free(&master->lock, lock->context)) {
                        /* FIXME: Should really bail out here. */
                }
        }
@@ -379,9 +382,10 @@ EXPORT_SYMBOL(drm_idlelock_release);
 
 int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
 {
-       return (file_priv->lock_count && dev->lock.hw_lock &&
-               _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
-               dev->lock.file_priv == file_priv);
+       struct drm_master *master = file_priv->master;
+       return (file_priv->lock_count && master->lock.hw_lock &&
+               _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
+               master->lock.file_priv == file_priv);
 }
 
 EXPORT_SYMBOL(drm_i_have_hw_lock);
index 217ad7dc70765ef174ad159c8e769fa10392c531..367c590ffbba2d83b5f516d76cb6efacdd1baff1 100644 (file)
@@ -296,3 +296,4 @@ void drm_mm_takedown(struct drm_mm * mm)
 
        drm_free(entry, sizeof(*entry), DRM_MEM_MM);
 }
+EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
new file mode 100644 (file)
index 0000000..c9b80fd
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * The list_sort function is (presumably) licensed under the GPL (see the
+ * top level "COPYING" file for details).
+ *
+ * The remainder of this file is:
+ *
+ * Copyright Â© 1997-2003 by The XFree86 Project, Inc.
+ * Copyright Â© 2007 Dave Airlie
+ * Copyright Â© 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+#include <linux/list.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+
+/**
+ * drm_mode_debug_printmodeline - debug print a mode
+ * @dev: DRM device
+ * @mode: mode to print
+ *
+ * LOCKING:
+ * None.
+ *
+ * Describe @mode using DRM_DEBUG.
+ */
+void drm_mode_debug_printmodeline(struct drm_display_mode *mode)
+{
+       DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
+                 mode->base.id, mode->name, mode->vrefresh, mode->clock,
+                 mode->hdisplay, mode->hsync_start,
+                 mode->hsync_end, mode->htotal,
+                 mode->vdisplay, mode->vsync_start,
+                 mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+}
+EXPORT_SYMBOL(drm_mode_debug_printmodeline);
+
+/**
+ * drm_mode_set_name - set the name on a mode
+ * @mode: name will be set in this mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Set the name of @mode to a standard format.
+ */
+void drm_mode_set_name(struct drm_display_mode *mode)
+{
+       snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay,
+                mode->vdisplay);
+}
+EXPORT_SYMBOL(drm_mode_set_name);
+
+/**
+ * drm_mode_list_concat - move modes from one list to another
+ * @head: source list
+ * @new: dst list
+ *
+ * LOCKING:
+ * Caller must ensure both lists are locked.
+ *
+ * Move all the modes from @head to @new.
+ */
+void drm_mode_list_concat(struct list_head *head, struct list_head *new)
+{
+
+       struct list_head *entry, *tmp;
+
+       list_for_each_safe(entry, tmp, head) {
+               list_move_tail(entry, new);
+       }
+}
+EXPORT_SYMBOL(drm_mode_list_concat);
+
+/**
+ * drm_mode_width - get the width of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's width (hdisplay) value.
+ *
+ * FIXME: is this needed?
+ *
+ * RETURNS:
+ * @mode->hdisplay
+ */
+int drm_mode_width(struct drm_display_mode *mode)
+{
+       return mode->hdisplay;
+
+}
+EXPORT_SYMBOL(drm_mode_width);
+
+/**
+ * drm_mode_height - get the height of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's height (vdisplay) value.
+ *
+ * FIXME: is this needed?
+ *
+ * RETURNS:
+ * @mode->vdisplay
+ */
+int drm_mode_height(struct drm_display_mode *mode)
+{
+       return mode->vdisplay;
+}
+EXPORT_SYMBOL(drm_mode_height);
+
+/**
+ * drm_mode_vrefresh - get the vrefresh of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's vrefresh rate or calculate it if necessary.
+ *
+ * FIXME: why is this needed?  shouldn't vrefresh be set already?
+ *
+ * RETURNS:
+ * Vertical refresh rate of @mode x 1000. For precision reasons.
+ */
+int drm_mode_vrefresh(struct drm_display_mode *mode)
+{
+       int refresh = 0;
+       unsigned int calc_val;
+
+       if (mode->vrefresh > 0)
+               refresh = mode->vrefresh;
+       else if (mode->htotal > 0 && mode->vtotal > 0) {
+               /* work out vrefresh the value will be x1000 */
+               calc_val = (mode->clock * 1000);
+
+               calc_val /= mode->htotal;
+               calc_val *= 1000;
+               calc_val /= mode->vtotal;
+
+               refresh = calc_val;
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       refresh *= 2;
+               if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+                       refresh /= 2;
+               if (mode->vscan > 1)
+                       refresh /= mode->vscan;
+       }
+       return refresh;
+}
+EXPORT_SYMBOL(drm_mode_vrefresh);
+
+/**
+ * drm_mode_set_crtcinfo - set CRTC modesetting parameters
+ * @p: mode
+ * @adjust_flags: unused? (FIXME)
+ *
+ * LOCKING:
+ * None.
+ *
+ * Setup the CRTC modesetting parameters for @p, adjusting if necessary.
+ */
+void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
+{
+       if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
+               return;
+
+       p->crtc_hdisplay = p->hdisplay;
+       p->crtc_hsync_start = p->hsync_start;
+       p->crtc_hsync_end = p->hsync_end;
+       p->crtc_htotal = p->htotal;
+       p->crtc_hskew = p->hskew;
+       p->crtc_vdisplay = p->vdisplay;
+       p->crtc_vsync_start = p->vsync_start;
+       p->crtc_vsync_end = p->vsync_end;
+       p->crtc_vtotal = p->vtotal;
+
+       if (p->flags & DRM_MODE_FLAG_INTERLACE) {
+               if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
+                       p->crtc_vdisplay /= 2;
+                       p->crtc_vsync_start /= 2;
+                       p->crtc_vsync_end /= 2;
+                       p->crtc_vtotal /= 2;
+               }
+
+               p->crtc_vtotal |= 1;
+       }
+
+       if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
+               p->crtc_vdisplay *= 2;
+               p->crtc_vsync_start *= 2;
+               p->crtc_vsync_end *= 2;
+               p->crtc_vtotal *= 2;
+       }
+
+       if (p->vscan > 1) {
+               p->crtc_vdisplay *= p->vscan;
+               p->crtc_vsync_start *= p->vscan;
+               p->crtc_vsync_end *= p->vscan;
+               p->crtc_vtotal *= p->vscan;
+       }
+
+       p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
+       p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
+       p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
+       p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
+
+       p->crtc_hadjusted = false;
+       p->crtc_vadjusted = false;
+}
+EXPORT_SYMBOL(drm_mode_set_crtcinfo);
+
+
+/**
+ * drm_mode_duplicate - allocate and duplicate an existing mode
+ * @m: mode to duplicate
+ *
+ * LOCKING:
+ * None.
+ *
+ * Just allocate a new mode, copy the existing mode into it, and return
+ * a pointer to it.  Used to create new instances of established modes.
+ */
+struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+                                           struct drm_display_mode *mode)
+{
+       struct drm_display_mode *nmode;
+       int new_id;
+
+       nmode = drm_mode_create(dev);
+       if (!nmode)
+               return NULL;
+
+       new_id = nmode->base.id;
+       *nmode = *mode;
+       nmode->base.id = new_id;
+       INIT_LIST_HEAD(&nmode->head);
+       return nmode;
+}
+EXPORT_SYMBOL(drm_mode_duplicate);
+
+/**
+ * drm_mode_equal - test modes for equality
+ * @mode1: first mode
+ * @mode2: second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Check to see if @mode1 and @mode2 are equivalent.
+ *
+ * RETURNS:
+ * True if the modes are equal, false otherwise.
+ */
+bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2)
+{
+       /* do clock check convert to PICOS so fb modes get matched
+        * the same */
+       if (mode1->clock && mode2->clock) {
+               if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock))
+                       return false;
+       } else if (mode1->clock != mode2->clock)
+               return false;
+
+       if (mode1->hdisplay == mode2->hdisplay &&
+           mode1->hsync_start == mode2->hsync_start &&
+           mode1->hsync_end == mode2->hsync_end &&
+           mode1->htotal == mode2->htotal &&
+           mode1->hskew == mode2->hskew &&
+           mode1->vdisplay == mode2->vdisplay &&
+           mode1->vsync_start == mode2->vsync_start &&
+           mode1->vsync_end == mode2->vsync_end &&
+           mode1->vtotal == mode2->vtotal &&
+           mode1->vscan == mode2->vscan &&
+           mode1->flags == mode2->flags)
+               return true;
+
+       return false;
+}
+EXPORT_SYMBOL(drm_mode_equal);
+
+/**
+ * drm_mode_validate_size - make sure modes adhere to size constraints
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @maxX: maximum width
+ * @maxY: maximum height
+ * @maxPitch: max pitch
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * The DRM device (@dev) has size and pitch limits.  Here we validate the
+ * modes we probed for @dev against those limits and set their status as
+ * necessary.
+ */
+void drm_mode_validate_size(struct drm_device *dev,
+                           struct list_head *mode_list,
+                           int maxX, int maxY, int maxPitch)
+{
+       struct drm_display_mode *mode;
+
+       list_for_each_entry(mode, mode_list, head) {
+               if (maxPitch > 0 && mode->hdisplay > maxPitch)
+                       mode->status = MODE_BAD_WIDTH;
+
+               if (maxX > 0 && mode->hdisplay > maxX)
+                       mode->status = MODE_VIRTUAL_X;
+
+               if (maxY > 0 && mode->vdisplay > maxY)
+                       mode->status = MODE_VIRTUAL_Y;
+       }
+}
+EXPORT_SYMBOL(drm_mode_validate_size);
+
+/**
+ * drm_mode_validate_clocks - validate modes against clock limits
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @min: minimum clock rate array
+ * @max: maximum clock rate array
+ * @n_ranges: number of clock ranges (size of arrays)
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Some code may need to check a mode list against the clock limits of the
+ * device in question.  This function walks the mode list, testing to make
+ * sure each mode falls within a given range (defined by @min and @max
+ * arrays) and sets @mode->status as needed.
+ */
+void drm_mode_validate_clocks(struct drm_device *dev,
+                             struct list_head *mode_list,
+                             int *min, int *max, int n_ranges)
+{
+       struct drm_display_mode *mode;
+       int i;
+
+       list_for_each_entry(mode, mode_list, head) {
+               bool good = false;
+               for (i = 0; i < n_ranges; i++) {
+                       if (mode->clock >= min[i] && mode->clock <= max[i]) {
+                               good = true;
+                               break;
+                       }
+               }
+               if (!good)
+                       mode->status = MODE_CLOCK_RANGE;
+       }
+}
+EXPORT_SYMBOL(drm_mode_validate_clocks);
+
+/**
+ * drm_mode_prune_invalid - remove invalid modes from mode list
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @verbose: be verbose about it
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Once mode list generation is complete, a caller can use this routine to
+ * remove invalid modes from a mode list.  If any of the modes have a
+ * status other than %MODE_OK, they are removed from @mode_list and freed.
+ */
+void drm_mode_prune_invalid(struct drm_device *dev,
+                           struct list_head *mode_list, bool verbose)
+{
+       struct drm_display_mode *mode, *t;
+
+       list_for_each_entry_safe(mode, t, mode_list, head) {
+               if (mode->status != MODE_OK) {
+                       list_del(&mode->head);
+                       if (verbose) {
+                               drm_mode_debug_printmodeline(mode);
+                               DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
+                       }
+                       drm_mode_destroy(dev, mode);
+               }
+       }
+}
+EXPORT_SYMBOL(drm_mode_prune_invalid);
+
+/**
+ * drm_mode_compare - compare modes for favorability
+ * @lh_a: list_head for first mode
+ * @lh_b: list_head for second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
+ * which is better.
+ *
+ * RETURNS:
+ * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
+ * positive if @lh_b is better than @lh_a.
+ */
+static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b)
+{
+       struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
+       struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
+       int diff;
+
+       diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
+               ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
+       if (diff)
+               return diff;
+       diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
+       if (diff)
+               return diff;
+       diff = b->clock - a->clock;
+       return diff;
+}
+
+/* FIXME: what we don't have a list sort function? */
+/* list sort from Mark J Roberts (mjr@znex.org) */
+void list_sort(struct list_head *head,
+              int (*cmp)(struct list_head *a, struct list_head *b))
+{
+       struct list_head *p, *q, *e, *list, *tail, *oldhead;
+       int insize, nmerges, psize, qsize, i;
+
+       list = head->next;
+       list_del(head);
+       insize = 1;
+       for (;;) {
+               p = oldhead = list;
+               list = tail = NULL;
+               nmerges = 0;
+
+               while (p) {
+                       nmerges++;
+                       q = p;
+                       psize = 0;
+                       for (i = 0; i < insize; i++) {
+                               psize++;
+                               q = q->next == oldhead ? NULL : q->next;
+                               if (!q)
+                                       break;
+                       }
+
+                       qsize = insize;
+                       while (psize > 0 || (qsize > 0 && q)) {
+                               if (!psize) {
+                                       e = q;
+                                       q = q->next;
+                                       qsize--;
+                                       if (q == oldhead)
+                                               q = NULL;
+                               } else if (!qsize || !q) {
+                                       e = p;
+                                       p = p->next;
+                                       psize--;
+                                       if (p == oldhead)
+                                               p = NULL;
+                               } else if (cmp(p, q) <= 0) {
+                                       e = p;
+                                       p = p->next;
+                                       psize--;
+                                       if (p == oldhead)
+                                               p = NULL;
+                               } else {
+                                       e = q;
+                                       q = q->next;
+                                       qsize--;
+                                       if (q == oldhead)
+                                               q = NULL;
+                               }
+                               if (tail)
+                                       tail->next = e;
+                               else
+                                       list = e;
+                               e->prev = tail;
+                               tail = e;
+                       }
+                       p = q;
+               }
+
+               tail->next = list;
+               list->prev = tail;
+
+               if (nmerges <= 1)
+                       break;
+
+               insize *= 2;
+       }
+
+       head->next = list;
+       head->prev = list->prev;
+       list->prev->next = head;
+       list->prev = head;
+}
+
+/**
+ * drm_mode_sort - sort mode list
+ * @mode_list: list to sort
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Sort @mode_list by favorability, putting good modes first.
+ */
+void drm_mode_sort(struct list_head *mode_list)
+{
+       list_sort(mode_list, drm_mode_compare);
+}
+EXPORT_SYMBOL(drm_mode_sort);
+
+/**
+ * drm_mode_connector_list_update - update the mode list for the connector
+ * @connector: the connector to update
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * This moves the modes from the @connector probed_modes list
+ * to the actual mode list. It compares the probed mode against the current
+ * list and only adds different modes. All modes unverified after this point
+ * will be removed by the prune invalid modes.
+ */
+void drm_mode_connector_list_update(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode;
+       struct drm_display_mode *pmode, *pt;
+       int found_it;
+
+       list_for_each_entry_safe(pmode, pt, &connector->probed_modes,
+                                head) {
+               found_it = 0;
+               /* go through current modes checking for the new probed mode */
+               list_for_each_entry(mode, &connector->modes, head) {
+                       if (drm_mode_equal(pmode, mode)) {
+                               found_it = 1;
+                               /* if equal delete the probed mode */
+                               mode->status = pmode->status;
+                               list_del(&pmode->head);
+                               drm_mode_destroy(connector->dev, pmode);
+                               break;
+                       }
+               }
+
+               if (!found_it) {
+                       list_move_tail(&pmode->head, &connector->modes);
+               }
+       }
+}
+EXPORT_SYMBOL(drm_mode_connector_list_update);
index ae73b7f7249ad36059dde96219fe2fb33022b082..8df849f66830fbd50bc371fb13abf04360afa914 100644 (file)
@@ -49,6 +49,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset,
                           int request, int *eof, void *data);
 static int drm_bufs_info(char *buf, char **start, off_t offset,
                         int request, int *eof, void *data);
+static int drm_vblank_info(char *buf, char **start, off_t offset,
+                          int request, int *eof, void *data);
 static int drm_gem_name_info(char *buf, char **start, off_t offset,
                             int request, int *eof, void *data);
 static int drm_gem_object_info(char *buf, char **start, off_t offset,
@@ -72,6 +74,7 @@ static struct drm_proc_list {
        {"clients", drm_clients_info, 0},
        {"queues", drm_queues_info, 0},
        {"bufs", drm_bufs_info, 0},
+       {"vblank", drm_vblank_info, 0},
        {"gem_names", drm_gem_name_info, DRIVER_GEM},
        {"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
@@ -195,6 +198,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
                         int *eof, void *data)
 {
        struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_master *master = minor->master;
        struct drm_device *dev = minor->dev;
        int len = 0;
 
@@ -203,13 +207,16 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
                return 0;
        }
 
+       if (!master)
+               return 0;
+
        *start = &buf[offset];
        *eof = 0;
 
-       if (dev->unique) {
+       if (master->unique) {
                DRM_PROC_PRINT("%s %s %s\n",
                               dev->driver->pci_driver.name,
-                              pci_name(dev->pdev), dev->unique);
+                              pci_name(dev->pdev), master->unique);
        } else {
                DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,
                               pci_name(dev->pdev));
@@ -453,6 +460,66 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
        return ret;
 }
 
+/**
+ * Called when "/proc/dri/.../vblank" is read.
+ *
+ * \param buf output buffer.
+ * \param start start of output data.
+ * \param offset requested start offset.
+ * \param request requested number of bytes.
+ * \param eof whether there is no more data to return.
+ * \param data private data.
+ * \return number of written bytes.
+ */
+static int drm__vblank_info(char *buf, char **start, off_t offset, int request,
+                         int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       int len = 0;
+       int crtc;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+
+       for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
+               DRM_PROC_PRINT("CRTC %d enable:     %d\n",
+                              crtc, atomic_read(&dev->vblank_refcount[crtc]));
+               DRM_PROC_PRINT("CRTC %d counter:    %d\n",
+                              crtc, drm_vblank_count(dev, crtc));
+               DRM_PROC_PRINT("CRTC %d last wait:  %d\n",
+                              crtc, dev->last_vblank_wait[crtc]);
+               DRM_PROC_PRINT("CRTC %d in modeset: %d\n",
+                              crtc, dev->vblank_inmodeset[crtc]);
+       }
+
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
+/**
+ * Simply calls _vblank_info() while holding the drm_device::struct_mutex lock.
+ */
+static int drm_vblank_info(char *buf, char **start, off_t offset, int request,
+                        int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       int ret;
+
+       mutex_lock(&dev->struct_mutex);
+       ret = drm__vblank_info(buf, start, offset, request, eof, data);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
 /**
  * Called when "/proc/dri/.../clients" is read.
  *
index 66c96ec66672ca2746dc70709772d8c780aea426..5ca132afa4f2e128999e319e44e31ad156e6ab74 100644 (file)
@@ -57,6 +57,14 @@ static int drm_minor_get_id(struct drm_device *dev, int type)
        int ret;
        int base = 0, limit = 63;
 
+       if (type == DRM_MINOR_CONTROL) {
+                base += 64;
+                limit = base + 127;
+        } else if (type == DRM_MINOR_RENDER) {
+                base += 128;
+                limit = base + 255;
+        }
+
 again:
        if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) {
                DRM_ERROR("Out of memory expanding drawable idr\n");
@@ -79,6 +87,104 @@ again:
        return new_id;
 }
 
+struct drm_master *drm_master_create(struct drm_minor *minor)
+{
+       struct drm_master *master;
+
+       master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER);
+       if (!master)
+               return NULL;
+
+       kref_init(&master->refcount);
+       spin_lock_init(&master->lock.spinlock);
+       init_waitqueue_head(&master->lock.lock_queue);
+       drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
+       INIT_LIST_HEAD(&master->magicfree);
+       master->minor = minor;
+
+       list_add_tail(&master->head, &minor->master_list);
+
+       return master;
+}
+
+struct drm_master *drm_master_get(struct drm_master *master)
+{
+       kref_get(&master->refcount);
+       return master;
+}
+
+static void drm_master_destroy(struct kref *kref)
+{
+       struct drm_master *master = container_of(kref, struct drm_master, refcount);
+       struct drm_magic_entry *pt, *next;
+       struct drm_device *dev = master->minor->dev;
+
+       list_del(&master->head);
+
+       if (dev->driver->master_destroy)
+               dev->driver->master_destroy(dev, master);
+
+       if (master->unique) {
+               drm_free(master->unique, master->unique_size, DRM_MEM_DRIVER);
+               master->unique = NULL;
+               master->unique_len = 0;
+       }
+
+       list_for_each_entry_safe(pt, next, &master->magicfree, head) {
+               list_del(&pt->head);
+               drm_ht_remove_item(&master->magiclist, &pt->hash_item);
+               drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+       }
+
+       drm_ht_remove(&master->magiclist);
+
+       if (master->lock.hw_lock) {
+               if (dev->sigdata.lock == master->lock.hw_lock)
+                       dev->sigdata.lock = NULL;
+               master->lock.hw_lock = NULL;
+               master->lock.file_priv = NULL;
+               wake_up_interruptible(&master->lock.lock_queue);
+       }
+
+       drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
+}
+
+void drm_master_put(struct drm_master **master)
+{
+       kref_put(&(*master)->refcount, drm_master_destroy);
+       *master = NULL;
+}
+
+int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
+               return -EINVAL;
+
+       if (!file_priv->master)
+               return -EINVAL;
+
+       if (!file_priv->minor->master &&
+           file_priv->minor->master != file_priv->master) {
+               mutex_lock(&dev->struct_mutex);
+               file_priv->minor->master = drm_master_get(file_priv->master);
+               mutex_lock(&dev->struct_mutex);
+       }
+
+       return 0;
+}
+
+int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       if (!file_priv->master)
+               return -EINVAL;
+       mutex_lock(&dev->struct_mutex);
+       drm_master_put(&file_priv->minor->master);
+       mutex_unlock(&dev->struct_mutex);
+       return 0;
+}
+
 static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                           const struct pci_device_id *ent,
                           struct drm_driver *driver)
@@ -92,7 +198,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
 
        spin_lock_init(&dev->count_lock);
        spin_lock_init(&dev->drw_lock);
-       spin_lock_init(&dev->lock.spinlock);
        init_timer(&dev->timer);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
@@ -140,9 +245,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                }
        }
 
-       if (dev->driver->load)
-               if ((retcode = dev->driver->load(dev, ent->driver_data)))
-                       goto error_out_unreg;
 
        retcode = drm_ctxbitmap_init(dev);
        if (retcode) {
@@ -200,6 +302,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
        new_minor->device = MKDEV(DRM_MAJOR, minor_id);
        new_minor->dev = dev;
        new_minor->index = minor_id;
+       INIT_LIST_HEAD(&new_minor->master_list);
 
        idr_replace(&drm_minors_idr, new_minor, minor_id);
 
@@ -267,8 +370,30 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
                goto err_g2;
        }
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
+               if (ret)
+                       goto err_g2;
+       }
+
        if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
-               goto err_g2;
+               goto err_g3;
+
+       if (dev->driver->load) {
+               ret = dev->driver->load(dev, ent->driver_data);
+               if (ret)
+                       goto err_g3;
+       }
+
+        /* setup the grouping for the legacy output */
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group);
+               if (ret)
+                       goto err_g3;
+       }
+
+       list_add_tail(&dev->driver_item, &driver->device_list);
 
        DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
                 driver->name, driver->major, driver->minor, driver->patchlevel,
@@ -276,6 +401,8 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
 
        return 0;
 
+err_g3:
+       drm_put_minor(&dev->primary);
 err_g2:
        pci_disable_device(pdev);
 err_g1:
@@ -297,11 +424,6 @@ int drm_put_dev(struct drm_device * dev)
 {
        DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
 
-       if (dev->unique) {
-               drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
-               dev->unique = NULL;
-               dev->unique_len = 0;
-       }
        if (dev->devname) {
                drm_free(dev->devname, strlen(dev->devname) + 1,
                         DRM_MEM_DRIVER);
index 1611b9bcbe7fd6378bc91a069ff8b8afab0d968b..65d72d094c81803757c00133bc9bd58895a2d03a 100644 (file)
@@ -20,6 +20,7 @@
 #include "drmP.h"
 
 #define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
+#define to_drm_connector(d) container_of(d, struct drm_connector, kdev)
 
 /**
  * drm_sysfs_suspend - DRM class suspend hook
@@ -34,7 +35,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
        struct drm_minor *drm_minor = to_drm_minor(dev);
        struct drm_device *drm_dev = drm_minor->dev;
 
-       if (drm_dev->driver->suspend)
+       if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->suspend)
                return drm_dev->driver->suspend(drm_dev, state);
 
        return 0;
@@ -52,7 +53,7 @@ static int drm_sysfs_resume(struct device *dev)
        struct drm_minor *drm_minor = to_drm_minor(dev);
        struct drm_device *drm_dev = drm_minor->dev;
 
-       if (drm_dev->driver->resume)
+       if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->resume)
                return drm_dev->driver->resume(drm_dev);
 
        return 0;
@@ -144,6 +145,323 @@ static void drm_sysfs_device_release(struct device *dev)
        return;
 }
 
+/*
+ * Connector properties
+ */
+static ssize_t status_show(struct device *device,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
+       enum drm_connector_status status;
+
+       status = connector->funcs->detect(connector);
+       return snprintf(buf, PAGE_SIZE, "%s",
+                       drm_get_connector_status_name(status));
+}
+
+static ssize_t dpms_show(struct device *device,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
+       struct drm_device *dev = connector->dev;
+       uint64_t dpms_status;
+       int ret;
+
+       ret = drm_connector_property_get_value(connector,
+                                           dev->mode_config.dpms_property,
+                                           &dpms_status);
+       if (ret)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%s",
+                       drm_get_dpms_name((int)dpms_status));
+}
+
+static ssize_t enabled_show(struct device *device,
+                           struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
+
+       return snprintf(buf, PAGE_SIZE, connector->encoder ? "enabled" :
+                       "disabled");
+}
+
+static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr,
+                        char *buf, loff_t off, size_t count)
+{
+       struct device *connector_dev = container_of(kobj, struct device, kobj);
+       struct drm_connector *connector = to_drm_connector(connector_dev);
+       unsigned char *edid;
+       size_t size;
+
+       if (!connector->edid_blob_ptr)
+               return 0;
+
+       edid = connector->edid_blob_ptr->data;
+       size = connector->edid_blob_ptr->length;
+       if (!edid)
+               return 0;
+
+       if (off >= size)
+               return 0;
+
+       if (off + count > size)
+               count = size - off;
+       memcpy(buf, edid + off, count);
+
+       return count;
+}
+
+static ssize_t modes_show(struct device *device,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
+       struct drm_display_mode *mode;
+       int written = 0;
+
+       list_for_each_entry(mode, &connector->modes, head) {
+               written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
+                                   mode->name);
+       }
+
+       return written;
+}
+
+static ssize_t subconnector_show(struct device *device,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
+       struct drm_device *dev = connector->dev;
+       struct drm_property *prop = NULL;
+       uint64_t subconnector;
+       int is_tv = 0;
+       int ret;
+
+       switch (connector->connector_type) {
+               case DRM_MODE_CONNECTOR_DVII:
+                       prop = dev->mode_config.dvi_i_subconnector_property;
+                       break;
+               case DRM_MODE_CONNECTOR_Composite:
+               case DRM_MODE_CONNECTOR_SVIDEO:
+               case DRM_MODE_CONNECTOR_Component:
+                       prop = dev->mode_config.tv_subconnector_property;
+                       is_tv = 1;
+                       break;
+               default:
+                       DRM_ERROR("Wrong connector type for this property\n");
+                       return 0;
+       }
+
+       if (!prop) {
+               DRM_ERROR("Unable to find subconnector property\n");
+               return 0;
+       }
+
+       ret = drm_connector_property_get_value(connector, prop, &subconnector);
+       if (ret)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
+                       drm_get_tv_subconnector_name((int)subconnector) :
+                       drm_get_dvi_i_subconnector_name((int)subconnector));
+}
+
+static ssize_t select_subconnector_show(struct device *device,
+                          struct device_attribute *attr,
+                          char *buf)
+{
+       struct drm_connector *connector = to_drm_connector(device);
+       struct drm_device *dev = connector->dev;
+       struct drm_property *prop = NULL;
+       uint64_t subconnector;
+       int is_tv = 0;
+       int ret;
+
+       switch (connector->connector_type) {
+               case DRM_MODE_CONNECTOR_DVII:
+                       prop = dev->mode_config.dvi_i_select_subconnector_property;
+                       break;
+               case DRM_MODE_CONNECTOR_Composite:
+               case DRM_MODE_CONNECTOR_SVIDEO:
+               case DRM_MODE_CONNECTOR_Component:
+                       prop = dev->mode_config.tv_select_subconnector_property;
+                       is_tv = 1;
+                       break;
+               default:
+                       DRM_ERROR("Wrong connector type for this property\n");
+                       return 0;
+       }
+
+       if (!prop) {
+               DRM_ERROR("Unable to find select subconnector property\n");
+               return 0;
+       }
+
+       ret = drm_connector_property_get_value(connector, prop, &subconnector);
+       if (ret)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
+                       drm_get_tv_select_name((int)subconnector) :
+                       drm_get_dvi_i_select_name((int)subconnector));
+}
+
+static struct device_attribute connector_attrs[] = {
+       __ATTR_RO(status),
+       __ATTR_RO(enabled),
+       __ATTR_RO(dpms),
+       __ATTR_RO(modes),
+};
+
+/* These attributes are for both DVI-I connectors and all types of tv-out. */
+static struct device_attribute connector_attrs_opt1[] = {
+       __ATTR_RO(subconnector),
+       __ATTR_RO(select_subconnector),
+};
+
+static struct bin_attribute edid_attr = {
+       .attr.name = "edid",
+       .size = 128,
+       .read = edid_show,
+};
+
+/**
+ * drm_sysfs_connector_add - add an connector to sysfs
+ * @connector: connector to add
+ *
+ * Create an connector device in sysfs, along with its associated connector
+ * properties (so far, connection status, dpms, mode list & edid) and
+ * generate a hotplug event so userspace knows there's a new connector
+ * available.
+ *
+ * Note:
+ * This routine should only be called *once* for each DRM minor registered.
+ * A second call for an already registered device will trigger the BUG_ON
+ * below.
+ */
+int drm_sysfs_connector_add(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       int ret = 0, i, j;
+
+       /* We shouldn't get called more than once for the same connector */
+       BUG_ON(device_is_registered(&connector->kdev));
+
+       connector->kdev.parent = &dev->primary->kdev;
+       connector->kdev.class = drm_class;
+       connector->kdev.release = drm_sysfs_device_release;
+
+       DRM_DEBUG("adding \"%s\" to sysfs\n",
+                 drm_get_connector_name(connector));
+
+       snprintf(connector->kdev.bus_id, BUS_ID_SIZE, "card%d-%s",
+                dev->primary->index, drm_get_connector_name(connector));
+       ret = device_register(&connector->kdev);
+
+       if (ret) {
+               DRM_ERROR("failed to register connector device: %d\n", ret);
+               goto out;
+       }
+
+       /* Standard attributes */
+
+       for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) {
+               ret = device_create_file(&connector->kdev, &connector_attrs[i]);
+               if (ret)
+                       goto err_out_files;
+       }
+
+       /* Optional attributes */
+       /*
+        * In the long run it maybe a good idea to make one set of
+        * optionals per connector type.
+        */
+       switch (connector->connector_type) {
+               case DRM_MODE_CONNECTOR_DVII:
+               case DRM_MODE_CONNECTOR_Composite:
+               case DRM_MODE_CONNECTOR_SVIDEO:
+               case DRM_MODE_CONNECTOR_Component:
+                       for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) {
+                               ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]);
+                               if (ret)
+                                       goto err_out_files;
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr);
+       if (ret)
+               goto err_out_files;
+
+       /* Let userspace know we have a new connector */
+       drm_sysfs_hotplug_event(dev);
+
+       return 0;
+
+err_out_files:
+       if (i > 0)
+               for (j = 0; j < i; j++)
+                       device_remove_file(&connector->kdev,
+                                          &connector_attrs[i]);
+       device_unregister(&connector->kdev);
+
+out:
+       return ret;
+}
+EXPORT_SYMBOL(drm_sysfs_connector_add);
+
+/**
+ * drm_sysfs_connector_remove - remove an connector device from sysfs
+ * @connector: connector to remove
+ *
+ * Remove @connector and its associated attributes from sysfs.  Note that
+ * the device model core will take care of sending the "remove" uevent
+ * at this time, so we don't need to do it.
+ *
+ * Note:
+ * This routine should only be called if the connector was previously
+ * successfully registered.  If @connector hasn't been registered yet,
+ * you'll likely see a panic somewhere deep in sysfs code when called.
+ */
+void drm_sysfs_connector_remove(struct drm_connector *connector)
+{
+       int i;
+
+       DRM_DEBUG("removing \"%s\" from sysfs\n",
+                 drm_get_connector_name(connector));
+
+       for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
+               device_remove_file(&connector->kdev, &connector_attrs[i]);
+       sysfs_remove_bin_file(&connector->kdev.kobj, &edid_attr);
+       device_unregister(&connector->kdev);
+}
+EXPORT_SYMBOL(drm_sysfs_connector_remove);
+
+/**
+ * drm_sysfs_hotplug_event - generate a DRM uevent
+ * @dev: DRM device
+ *
+ * Send a uevent for the DRM device specified by @dev.  Currently we only
+ * set HOTPLUG=1 in the uevent environment, but this could be expanded to
+ * deal with other types of events.
+ */
+void drm_sysfs_hotplug_event(struct drm_device *dev)
+{
+       char *event_string = "HOTPLUG=1";
+       char *envp[] = { event_string, NULL };
+
+       DRM_DEBUG("generating hotplug event\n");
+
+       kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
+}
+
 /**
  * drm_sysfs_device_add - adds a class device to sysfs for a character driver
  * @dev: DRM device to be added
@@ -163,7 +481,12 @@ int drm_sysfs_device_add(struct drm_minor *minor)
        minor->kdev.class = drm_class;
        minor->kdev.release = drm_sysfs_device_release;
        minor->kdev.devt = minor->device;
-       minor_str = "card%d";
+       if (minor->type == DRM_MINOR_CONTROL)
+               minor_str = "controlD%d";
+        else if (minor->type == DRM_MINOR_RENDER)
+                minor_str = "renderD%d";
+        else
+                minor_str = "card%d";
 
        snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index);
 
index c234c6f24a8d8fd157a1af029d530d5bbc09bd84..3ffae021d28052173898a3ed449adbc6e96d61d1 100644 (file)
@@ -267,6 +267,9 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                                dmah.size = map->size;
                                __drm_pci_free(dev, &dmah);
                                break;
+                       case _DRM_GEM:
+                               DRM_ERROR("tried to rmmap GEM object\n");
+                               break;
                        }
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                }
@@ -399,7 +402,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {
  * Create a new drm_vma_entry structure as the \p vma private data entry and
  * add it to drm_device::vmalist.
  */
-static void drm_vm_open_locked(struct vm_area_struct *vma)
+void drm_vm_open_locked(struct vm_area_struct *vma)
 {
        struct drm_file *priv = vma->vm_file->private_data;
        struct drm_device *dev = priv->minor->dev;
@@ -540,7 +543,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
  * according to the mapping type and remaps the pages. Finally sets the file
  * pointer and calls vm_open().
  */
-static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
+int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
index d8fb5d8ee7ea38aa55308bda89ebee06978f1366..dd57a5bd457248505922e552be656982c295ad56 100644 (file)
@@ -8,7 +8,22 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          i915_gem.o \
          i915_gem_debug.o \
          i915_gem_proc.o \
-         i915_gem_tiling.o
+         i915_gem_tiling.o \
+         intel_display.o \
+         intel_crt.o \
+         intel_lvds.o \
+         intel_bios.o \
+         intel_sdvo.o \
+         intel_modes.o \
+         intel_i2c.o \
+         intel_fb.o \
+         intel_tv.o \
+         intel_dvo.o \
+         dvo_ch7xxx.o \
+         dvo_ch7017.o \
+         dvo_ivch.o \
+         dvo_tfp410.o \
+         dvo_sil164.o
 
 i915-$(CONFIG_ACPI)    += i915_opregion.o
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h
new file mode 100644 (file)
index 0000000..e747ac4
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright Â© 2006 Eric Anholt
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _INTEL_DVO_H
+#define _INTEL_DVO_H
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+
+struct intel_dvo_device {
+       char *name;
+       int type;
+       /* DVOA/B/C output register */
+       u32 dvo_reg;
+       /* GPIO register used for i2c bus to control this device */
+       u32 gpio;
+       int slave_addr;
+       struct intel_i2c_chan *i2c_bus;
+
+       const struct intel_dvo_dev_ops *dev_ops;
+       void *dev_priv;
+
+       struct drm_display_mode *panel_fixed_mode;
+       bool panel_wants_dither;
+};
+
+struct intel_dvo_dev_ops {
+       /*
+        * Initialize the device at startup time.
+        * Returns NULL if the device does not exist.
+        */
+       bool (*init)(struct intel_dvo_device *dvo,
+                    struct intel_i2c_chan *i2cbus);
+
+       /*
+        * Called to allow the output a chance to create properties after the
+        * RandR objects have been created.
+        */
+       void (*create_resources)(struct intel_dvo_device *dvo);
+
+       /*
+        * Turn on/off output or set intermediate power levels if available.
+        *
+        * Unsupported intermediate modes drop to the lower power setting.
+        * If the  mode is DPMSModeOff, the output must be disabled,
+        * as the DPLL may be disabled afterwards.
+        */
+       void (*dpms)(struct intel_dvo_device *dvo, int mode);
+
+       /*
+        * Saves the output's state for restoration on VT switch.
+        */
+       void (*save)(struct intel_dvo_device *dvo);
+
+       /*
+        * Restore's the output's state at VT switch.
+        */
+       void (*restore)(struct intel_dvo_device *dvo);
+
+       /*
+        * Callback for testing a video mode for a given output.
+        *
+        * This function should only check for cases where a mode can't
+        * be supported on the output specifically, and not represent
+        * generic CRTC limitations.
+        *
+        * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
+        */
+       int (*mode_valid)(struct intel_dvo_device *dvo,
+                         struct drm_display_mode *mode);
+
+       /*
+        * Callback to adjust the mode to be set in the CRTC.
+        *
+        * This allows an output to adjust the clock or even the entire set of
+        * timings, which is used for panels with fixed timings or for
+        * buses with clock limitations.
+        */
+       bool (*mode_fixup)(struct intel_dvo_device *dvo,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+
+       /*
+        * Callback for preparing mode changes on an output
+        */
+       void (*prepare)(struct intel_dvo_device *dvo);
+
+       /*
+        * Callback for committing mode changes on an output
+        */
+       void (*commit)(struct intel_dvo_device *dvo);
+
+       /*
+        * Callback for setting up a video mode after fixups have been made.
+        *
+        * This is only called while the output is disabled.  The dpms callback
+        * must be all that's necessary for the output, to turn the output on
+        * after this function is called.
+        */
+       void (*mode_set)(struct intel_dvo_device *dvo,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode);
+
+       /*
+        * Probe for a connected output, and return detect_status.
+        */
+       enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
+
+       /**
+        * Query the device for the modes it provides.
+        *
+        * This function may also update MonInfo, mm_width, and mm_height.
+        *
+        * \return singly-linked list of modes or NULL if no modes found.
+        */
+       struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
+
+       /**
+        * Clean up driver-specific bits of the output
+        */
+       void (*destroy) (struct intel_dvo_device *dvo);
+
+       /**
+        * Debugging hook to dump device registers to log file
+        */
+       void (*dump_regs)(struct intel_dvo_device *dvo);
+};
+
+extern struct intel_dvo_dev_ops sil164_ops;
+extern struct intel_dvo_dev_ops ch7xxx_ops;
+extern struct intel_dvo_dev_ops ivch_ops;
+extern struct intel_dvo_dev_ops tfp410_ops;
+extern struct intel_dvo_dev_ops ch7017_ops;
+
+#endif /* _INTEL_DVO_H */
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
new file mode 100644 (file)
index 0000000..03d4b49
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright Â© 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "dvo.h"
+
+#define CH7017_TV_DISPLAY_MODE         0x00
+#define CH7017_FLICKER_FILTER          0x01
+#define CH7017_VIDEO_BANDWIDTH         0x02
+#define CH7017_TEXT_ENHANCEMENT                0x03
+#define CH7017_START_ACTIVE_VIDEO      0x04
+#define CH7017_HORIZONTAL_POSITION     0x05
+#define CH7017_VERTICAL_POSITION       0x06
+#define CH7017_BLACK_LEVEL             0x07
+#define CH7017_CONTRAST_ENHANCEMENT    0x08
+#define CH7017_TV_PLL                  0x09
+#define CH7017_TV_PLL_M                        0x0a
+#define CH7017_TV_PLL_N                        0x0b
+#define CH7017_SUB_CARRIER_0           0x0c
+#define CH7017_CIV_CONTROL             0x10
+#define CH7017_CIV_0                   0x11
+#define CH7017_CHROMA_BOOST            0x14
+#define CH7017_CLOCK_MODE              0x1c
+#define CH7017_INPUT_CLOCK             0x1d
+#define CH7017_GPIO_CONTROL            0x1e
+#define CH7017_INPUT_DATA_FORMAT       0x1f
+#define CH7017_CONNECTION_DETECT       0x20
+#define CH7017_DAC_CONTROL             0x21
+#define CH7017_BUFFERED_CLOCK_OUTPUT   0x22
+#define CH7017_DEFEAT_VSYNC            0x47
+#define CH7017_TEST_PATTERN            0x48
+
+#define CH7017_POWER_MANAGEMENT                0x49
+/** Enables the TV output path. */
+#define CH7017_TV_EN                   (1 << 0)
+#define CH7017_DAC0_POWER_DOWN         (1 << 1)
+#define CH7017_DAC1_POWER_DOWN         (1 << 2)
+#define CH7017_DAC2_POWER_DOWN         (1 << 3)
+#define CH7017_DAC3_POWER_DOWN         (1 << 4)
+/** Powers down the TV out block, and DAC0-3 */
+#define CH7017_TV_POWER_DOWN_EN                (1 << 5)
+
+#define CH7017_VERSION_ID              0x4a
+
+#define CH7017_DEVICE_ID               0x4b
+#define CH7017_DEVICE_ID_VALUE         0x1b
+#define CH7018_DEVICE_ID_VALUE         0x1a
+#define CH7019_DEVICE_ID_VALUE         0x19
+
+#define CH7017_XCLK_D2_ADJUST          0x53
+#define CH7017_UP_SCALER_COEFF_0       0x55
+#define CH7017_UP_SCALER_COEFF_1       0x56
+#define CH7017_UP_SCALER_COEFF_2       0x57
+#define CH7017_UP_SCALER_COEFF_3       0x58
+#define CH7017_UP_SCALER_COEFF_4       0x59
+#define CH7017_UP_SCALER_VERTICAL_INC_0        0x5a
+#define CH7017_UP_SCALER_VERTICAL_INC_1        0x5b
+#define CH7017_GPIO_INVERT             0x5c
+#define CH7017_UP_SCALER_HORIZONTAL_INC_0      0x5d
+#define CH7017_UP_SCALER_HORIZONTAL_INC_1      0x5e
+
+#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT   0x5f
+/**< Low bits of horizontal active pixel input */
+
+#define CH7017_ACTIVE_INPUT_LINE_OUTPUT        0x60
+/** High bits of horizontal active pixel input */
+#define CH7017_LVDS_HAP_INPUT_MASK     (0x7 << 0)
+/** High bits of vertical active line output */
+#define CH7017_LVDS_VAL_HIGH_MASK      (0x7 << 3)
+
+#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT     0x61
+/**< Low bits of vertical active line output */
+
+#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT  0x62
+/**< Low bits of horizontal active pixel output */
+
+#define CH7017_LVDS_POWER_DOWN         0x63
+/** High bits of horizontal active pixel output */
+#define CH7017_LVDS_HAP_HIGH_MASK      (0x7 << 0)
+/** Enables the LVDS power down state transition */
+#define CH7017_LVDS_POWER_DOWN_EN      (1 << 6)
+/** Enables the LVDS upscaler */
+#define CH7017_LVDS_UPSCALER_EN                (1 << 7)
+#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08
+
+#define CH7017_LVDS_ENCODING           0x64
+#define CH7017_LVDS_DITHER_2D          (1 << 2)
+#define CH7017_LVDS_DITHER_DIS         (1 << 3)
+#define CH7017_LVDS_DUAL_CHANNEL_EN    (1 << 4)
+#define CH7017_LVDS_24_BIT             (1 << 5)
+
+#define CH7017_LVDS_ENCODING_2         0x65
+
+#define CH7017_LVDS_PLL_CONTROL                0x66
+/** Enables the LVDS panel output path */
+#define CH7017_LVDS_PANEN              (1 << 0)
+/** Enables the LVDS panel backlight */
+#define CH7017_LVDS_BKLEN              (1 << 3)
+
+#define CH7017_POWER_SEQUENCING_T1     0x67
+#define CH7017_POWER_SEQUENCING_T2     0x68
+#define CH7017_POWER_SEQUENCING_T3     0x69
+#define CH7017_POWER_SEQUENCING_T4     0x6a
+#define CH7017_POWER_SEQUENCING_T5     0x6b
+#define CH7017_GPIO_DRIVER_TYPE                0x6c
+#define CH7017_GPIO_DATA               0x6d
+#define CH7017_GPIO_DIRECTION_CONTROL  0x6e
+
+#define CH7017_LVDS_PLL_FEEDBACK_DIV   0x71
+# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4
+# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0
+# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80
+
+#define CH7017_LVDS_PLL_VCO_CONTROL    0x72
+# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80
+# define CH7017_LVDS_PLL_VCO_SHIFT     4
+# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0
+
+#define CH7017_OUTPUTS_ENABLE          0x73
+# define CH7017_CHARGE_PUMP_LOW                0x0
+# define CH7017_CHARGE_PUMP_HIGH       0x3
+# define CH7017_LVDS_CHANNEL_A         (1 << 3)
+# define CH7017_LVDS_CHANNEL_B         (1 << 4)
+# define CH7017_TV_DAC_A               (1 << 5)
+# define CH7017_TV_DAC_B               (1 << 6)
+# define CH7017_DDC_SELECT_DC2         (1 << 7)
+
+#define CH7017_LVDS_OUTPUT_AMPLITUDE   0x74
+#define CH7017_LVDS_PLL_EMI_REDUCTION  0x75
+#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
+
+#define CH7017_LVDS_CONTROL_2          0x78
+# define CH7017_LOOP_FILTER_SHIFT      5
+# define CH7017_PHASE_DETECTOR_SHIFT   0
+
+#define CH7017_BANG_LIMIT_CONTROL      0x7f
+
+struct ch7017_priv {
+       uint8_t save_hapi;
+       uint8_t save_vali;
+       uint8_t save_valo;
+       uint8_t save_ailo;
+       uint8_t save_lvds_pll_vco;
+       uint8_t save_feedback_div;
+       uint8_t save_lvds_control_2;
+       uint8_t save_outputs_enable;
+       uint8_t save_lvds_power_down;
+       uint8_t save_power_management;
+};
+
+static void ch7017_dump_regs(struct intel_dvo_device *dvo);
+static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
+
+static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
+{
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+               *val= in_buf[0];
+               return true;
+       };
+
+       return false;
+}
+
+static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
+{
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       uint8_t out_buf[2];
+       struct i2c_msg msg = {
+               .addr = i2cbus->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = val;
+
+       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+               return true;
+
+       return false;
+}
+
+/** Probes for a CH7017 on the given bus and slave address. */
+static bool ch7017_init(struct intel_dvo_device *dvo,
+                       struct intel_i2c_chan *i2cbus)
+{
+       struct ch7017_priv *priv;
+       uint8_t val;
+
+       priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return false;
+
+       dvo->i2c_bus = i2cbus;
+       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->dev_priv = priv;
+
+       if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
+               goto fail;
+
+       if (val != CH7017_DEVICE_ID_VALUE &&
+           val != CH7018_DEVICE_ID_VALUE &&
+           val != CH7019_DEVICE_ID_VALUE) {
+               DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n",
+                         val, i2cbus->adapter.name,i2cbus->slave_addr);
+               goto fail;
+       }
+
+       return true;
+fail:
+       kfree(priv);
+       return false;
+}
+
+static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
+{
+       return connector_status_unknown;
+}
+
+static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       if (mode->clock > 160000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static void ch7017_mode_set(struct intel_dvo_device *dvo,
+                           struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+       uint8_t lvds_pll_feedback_div, lvds_pll_vco_control;
+       uint8_t outputs_enable, lvds_control_2, lvds_power_down;
+       uint8_t horizontal_active_pixel_input;
+       uint8_t horizontal_active_pixel_output, vertical_active_line_output;
+       uint8_t active_input_line_output;
+
+       DRM_DEBUG("Registers before mode setting\n");
+       ch7017_dump_regs(dvo);
+
+       /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
+       if (mode->clock < 100000) {
+               outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW;
+               lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
+                       (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
+                       (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
+               lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
+                       (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
+                       (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
+               lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
+                       (0 << CH7017_PHASE_DETECTOR_SHIFT);
+       } else {
+               outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH;
+               lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
+                       (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
+                       (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
+               lvds_pll_feedback_div = 35;
+               lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
+                       (0 << CH7017_PHASE_DETECTOR_SHIFT);
+               if (1) { /* XXX: dual channel panel detection.  Assume yes for now. */
+                       outputs_enable |= CH7017_LVDS_CHANNEL_B;
+                       lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
+                               (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
+                               (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
+               } else {
+                       lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
+                               (1 << CH7017_LVDS_PLL_VCO_SHIFT) |
+                               (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
+               }
+       }
+
+       horizontal_active_pixel_input = mode->hdisplay & 0x00ff;
+
+       vertical_active_line_output = mode->vdisplay & 0x00ff;
+       horizontal_active_pixel_output = mode->hdisplay & 0x00ff;
+
+       active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) |
+                                  (((mode->vdisplay & 0x0700) >> 8) << 3);
+
+       lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
+                         (mode->hdisplay & 0x0700) >> 8;
+
+       ch7017_dpms(dvo, DRM_MODE_DPMS_OFF);
+       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
+                       horizontal_active_pixel_input);
+       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
+                       horizontal_active_pixel_output);
+       ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
+                       vertical_active_line_output);
+       ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT,
+                       active_input_line_output);
+       ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
+       ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
+       ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2);
+       ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable);
+
+       /* Turn the LVDS back on with new settings. */
+       ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down);
+
+       DRM_DEBUG("Registers after mode setting\n");
+       ch7017_dump_regs(dvo);
+}
+
+/* set the CH7017 power state */
+static void ch7017_dpms(struct intel_dvo_device *dvo, int mode)
+{
+       uint8_t val;
+
+       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
+
+       /* Turn off TV/VGA, and never turn it on since we don't support it. */
+       ch7017_write(dvo, CH7017_POWER_MANAGEMENT,
+                       CH7017_DAC0_POWER_DOWN |
+                       CH7017_DAC1_POWER_DOWN |
+                       CH7017_DAC2_POWER_DOWN |
+                       CH7017_DAC3_POWER_DOWN |
+                       CH7017_TV_POWER_DOWN_EN);
+
+       if (mode == DRM_MODE_DPMS_ON) {
+               /* Turn on the LVDS */
+               ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
+                            val & ~CH7017_LVDS_POWER_DOWN_EN);
+       } else {
+               /* Turn off the LVDS */
+               ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
+                            val | CH7017_LVDS_POWER_DOWN_EN);
+       }
+
+       /* XXX: Should actually wait for update power status somehow */
+       udelay(20000);
+}
+
+static void ch7017_dump_regs(struct intel_dvo_device *dvo)
+{
+       uint8_t val;
+
+#define DUMP(reg)                                      \
+do {                                                   \
+       ch7017_read(dvo, reg, &val);                    \
+       DRM_DEBUG(#reg ": %02x\n", val);                \
+} while (0)
+
+       DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
+       DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
+       DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
+       DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT);
+       DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
+       DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
+       DUMP(CH7017_LVDS_CONTROL_2);
+       DUMP(CH7017_OUTPUTS_ENABLE);
+       DUMP(CH7017_LVDS_POWER_DOWN);
+}
+
+static void ch7017_save(struct intel_dvo_device *dvo)
+{
+       struct ch7017_priv *priv = dvo->dev_priv;
+
+       ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi);
+       ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo);
+       ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo);
+       ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco);
+       ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div);
+       ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2);
+       ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable);
+       ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down);
+       ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management);
+}
+
+static void ch7017_restore(struct intel_dvo_device *dvo)
+{
+       struct ch7017_priv *priv = dvo->dev_priv;
+
+       /* Power down before changing mode */
+       ch7017_dpms(dvo, DRM_MODE_DPMS_OFF);
+
+       ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi);
+       ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo);
+       ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo);
+       ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco);
+       ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div);
+       ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2);
+       ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable);
+       ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down);
+       ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management);
+}
+
+static void ch7017_destroy(struct intel_dvo_device *dvo)
+{
+       struct ch7017_priv *priv = dvo->dev_priv;
+
+       if (priv) {
+               kfree(priv);
+               dvo->dev_priv = NULL;
+       }
+}
+
+struct intel_dvo_dev_ops ch7017_ops = {
+       .init = ch7017_init,
+       .detect = ch7017_detect,
+       .mode_valid = ch7017_mode_valid,
+       .mode_set = ch7017_mode_set,
+       .dpms = ch7017_dpms,
+       .dump_regs = ch7017_dump_regs,
+       .save = ch7017_save,
+       .restore = ch7017_restore,
+       .destroy = ch7017_destroy,
+};
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
new file mode 100644 (file)
index 0000000..d2fd95d
--- /dev/null
@@ -0,0 +1,368 @@
+/**************************************************************************
+
+Copyright Â© 2006 Dave Airlie
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include "dvo.h"
+
+#define CH7xxx_REG_VID         0x4a
+#define CH7xxx_REG_DID         0x4b
+
+#define CH7011_VID             0x83 /* 7010 as well */
+#define CH7009A_VID            0x84
+#define CH7009B_VID            0x85
+#define CH7301_VID             0x95
+
+#define CH7xxx_VID             0x84
+#define CH7xxx_DID             0x17
+
+#define CH7xxx_NUM_REGS                0x4c
+
+#define CH7xxx_CM              0x1c
+#define CH7xxx_CM_XCM          (1<<0)
+#define CH7xxx_CM_MCP          (1<<2)
+#define CH7xxx_INPUT_CLOCK     0x1d
+#define CH7xxx_GPIO            0x1e
+#define CH7xxx_GPIO_HPIR       (1<<3)
+#define CH7xxx_IDF             0x1f
+
+#define CH7xxx_IDF_HSP         (1<<3)
+#define CH7xxx_IDF_VSP         (1<<4)
+
+#define CH7xxx_CONNECTION_DETECT 0x20
+#define CH7xxx_CDET_DVI                (1<<5)
+
+#define CH7301_DAC_CNTL                0x21
+#define CH7301_HOTPLUG         0x23
+#define CH7xxx_TCTL            0x31
+#define CH7xxx_TVCO            0x32
+#define CH7xxx_TPCP            0x33
+#define CH7xxx_TPD             0x34
+#define CH7xxx_TPVT            0x35
+#define CH7xxx_TLPF            0x36
+#define CH7xxx_TCT             0x37
+#define CH7301_TEST_PATTERN    0x48
+
+#define CH7xxx_PM              0x49
+#define CH7xxx_PM_FPD          (1<<0)
+#define CH7301_PM_DACPD0       (1<<1)
+#define CH7301_PM_DACPD1       (1<<2)
+#define CH7301_PM_DACPD2       (1<<3)
+#define CH7xxx_PM_DVIL         (1<<6)
+#define CH7xxx_PM_DVIP         (1<<7)
+
+#define CH7301_SYNC_POLARITY   0x56
+#define CH7301_SYNC_RGB_YUV    (1<<0)
+#define CH7301_SYNC_POL_DVI    (1<<5)
+
+/** @file
+ * driver for the Chrontel 7xxx DVI chip over DVO.
+ */
+
+static struct ch7xxx_id_struct {
+       uint8_t vid;
+       char *name;
+} ch7xxx_ids[] = {
+       { CH7011_VID, "CH7011" },
+       { CH7009A_VID, "CH7009A" },
+       { CH7009B_VID, "CH7009B" },
+       { CH7301_VID, "CH7301" },
+};
+
+struct ch7xxx_reg_state {
+    uint8_t regs[CH7xxx_NUM_REGS];
+};
+
+struct ch7xxx_priv {
+       bool quiet;
+
+       struct ch7xxx_reg_state save_reg;
+       struct ch7xxx_reg_state mode_reg;
+       uint8_t save_TCTL, save_TPCP, save_TPD, save_TPVT;
+       uint8_t save_TLPF, save_TCT, save_PM, save_IDF;
+};
+
+static void ch7xxx_save(struct intel_dvo_device *dvo);
+
+static char *ch7xxx_get_id(uint8_t vid)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
+               if (ch7xxx_ids[i].vid == vid)
+                       return ch7xxx_ids[i].name;
+       }
+
+       return NULL;
+}
+
+/** Reads an 8 bit register */
+static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
+{
+       struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       };
+
+       if (!ch7xxx->quiet) {
+               DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+       return false;
+}
+
+/** Writes an 8 bit register */
+static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       uint8_t out_buf[2];
+       struct i2c_msg msg = {
+               .addr = i2cbus->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+               return true;
+
+       if (!ch7xxx->quiet) {
+               DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+
+       return false;
+}
+
+static bool ch7xxx_init(struct intel_dvo_device *dvo,
+                       struct intel_i2c_chan *i2cbus)
+{
+       /* this will detect the CH7xxx chip on the specified i2c bus */
+       struct ch7xxx_priv *ch7xxx;
+       uint8_t vendor, device;
+       char *name;
+
+       ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
+       if (ch7xxx == NULL)
+               return false;
+
+       dvo->i2c_bus = i2cbus;
+       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->dev_priv = ch7xxx;
+       ch7xxx->quiet = true;
+
+       if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
+               goto out;
+
+       name = ch7xxx_get_id(vendor);
+       if (!name) {
+               DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
+                         vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+               goto out;
+       }
+
+
+       if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
+               goto out;
+
+       if (device != CH7xxx_DID) {
+               DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
+                         vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+               goto out;
+       }
+
+       ch7xxx->quiet = false;
+       DRM_DEBUG("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
+                 name, vendor, device);
+       return true;
+out:
+       kfree(ch7xxx);
+       return false;
+}
+
+static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
+{
+       uint8_t cdet, orig_pm, pm;
+
+       ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
+
+       pm = orig_pm;
+       pm &= ~CH7xxx_PM_FPD;
+       pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
+
+       ch7xxx_writeb(dvo, CH7xxx_PM, pm);
+
+       ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
+
+       ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
+
+       if (cdet & CH7xxx_CDET_DVI)
+               return connector_status_connected;
+       return connector_status_disconnected;
+}
+
+static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       if (mode->clock > 165000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
+                           struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+       uint8_t tvco, tpcp, tpd, tlpf, idf;
+
+       if (mode->clock <= 65000) {
+               tvco = 0x23;
+               tpcp = 0x08;
+               tpd = 0x16;
+               tlpf = 0x60;
+       } else {
+               tvco = 0x2d;
+               tpcp = 0x06;
+               tpd = 0x26;
+               tlpf = 0xa0;
+       }
+
+       ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
+       ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
+       ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
+       ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
+       ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
+       ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
+       ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
+
+       ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
+
+       idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               idf |= CH7xxx_IDF_HSP;
+
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               idf |= CH7xxx_IDF_HSP;
+
+       ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
+}
+
+/* set the CH7xxx power state */
+static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode)
+{
+       if (mode == DRM_MODE_DPMS_ON)
+               ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
+       else
+               ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
+}
+
+static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+       int i;
+
+       for (i = 0; i < CH7xxx_NUM_REGS; i++) {
+               if ((i % 8) == 0 )
+                       DRM_DEBUG("\n %02X: ", i);
+               DRM_DEBUG("%02X ", ch7xxx->mode_reg.regs[i]);
+       }
+}
+
+static void ch7xxx_save(struct intel_dvo_device *dvo)
+{
+       struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
+
+       ch7xxx_readb(dvo, CH7xxx_TCTL, &ch7xxx->save_TCTL);
+       ch7xxx_readb(dvo, CH7xxx_TPCP, &ch7xxx->save_TPCP);
+       ch7xxx_readb(dvo, CH7xxx_TPD, &ch7xxx->save_TPD);
+       ch7xxx_readb(dvo, CH7xxx_TPVT, &ch7xxx->save_TPVT);
+       ch7xxx_readb(dvo, CH7xxx_TLPF, &ch7xxx->save_TLPF);
+       ch7xxx_readb(dvo, CH7xxx_PM, &ch7xxx->save_PM);
+       ch7xxx_readb(dvo, CH7xxx_IDF, &ch7xxx->save_IDF);
+}
+
+static void ch7xxx_restore(struct intel_dvo_device *dvo)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+
+       ch7xxx_writeb(dvo, CH7xxx_TCTL, ch7xxx->save_TCTL);
+       ch7xxx_writeb(dvo, CH7xxx_TPCP, ch7xxx->save_TPCP);
+       ch7xxx_writeb(dvo, CH7xxx_TPD, ch7xxx->save_TPD);
+       ch7xxx_writeb(dvo, CH7xxx_TPVT, ch7xxx->save_TPVT);
+       ch7xxx_writeb(dvo, CH7xxx_TLPF, ch7xxx->save_TLPF);
+       ch7xxx_writeb(dvo, CH7xxx_IDF, ch7xxx->save_IDF);
+       ch7xxx_writeb(dvo, CH7xxx_PM, ch7xxx->save_PM);
+}
+
+static void ch7xxx_destroy(struct intel_dvo_device *dvo)
+{
+       struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
+
+       if (ch7xxx) {
+               kfree(ch7xxx);
+               dvo->dev_priv = NULL;
+       }
+}
+
+struct intel_dvo_dev_ops ch7xxx_ops = {
+       .init = ch7xxx_init,
+       .detect = ch7xxx_detect,
+       .mode_valid = ch7xxx_mode_valid,
+       .mode_set = ch7xxx_mode_set,
+       .dpms = ch7xxx_dpms,
+       .dump_regs = ch7xxx_dump_regs,
+       .save = ch7xxx_save,
+       .restore = ch7xxx_restore,
+       .destroy = ch7xxx_destroy,
+};
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
new file mode 100644 (file)
index 0000000..0c8d375
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright Â© 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#include "dvo.h"
+
+/*
+ * register definitions for the i82807aa.
+ *
+ * Documentation on this chipset can be found in datasheet #29069001 at
+ * intel.com.
+ */
+
+/*
+ * VCH Revision & GMBus Base Addr
+ */
+#define VR00           0x00
+# define VR00_BASE_ADDRESS_MASK                0x007f
+
+/*
+ * Functionality Enable
+ */
+#define VR01           0x01
+
+/*
+ * Enable the panel fitter
+ */
+# define VR01_PANEL_FIT_ENABLE         (1 << 3)
+/*
+ * Enables the LCD display.
+ *
+ * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
+ */
+# define VR01_LCD_ENABLE               (1 << 2)
+/** Enables the DVO repeater. */
+# define VR01_DVO_BYPASS_ENABLE                (1 << 1)
+/** Enables the DVO clock */
+# define VR01_DVO_ENABLE               (1 << 0)
+
+/*
+ * LCD Interface Format
+ */
+#define VR10           0x10
+/** Enables LVDS output instead of CMOS */
+# define VR10_LVDS_ENABLE              (1 << 4)
+/** Enables 18-bit LVDS output. */
+# define VR10_INTERFACE_1X18           (0 << 2)
+/** Enables 24-bit LVDS or CMOS output */
+# define VR10_INTERFACE_1X24           (1 << 2)
+/** Enables 2x18-bit LVDS or CMOS output. */
+# define VR10_INTERFACE_2X18           (2 << 2)
+/** Enables 2x24-bit LVDS output */
+# define VR10_INTERFACE_2X24           (3 << 2)
+
+/*
+ * VR20 LCD Horizontal Display Size
+ */
+#define VR20   0x20
+
+/*
+ * LCD Vertical Display Size
+ */
+#define VR21   0x20
+
+/*
+ * Panel power down status
+ */
+#define VR30           0x30
+/** Read only bit indicating that the panel is not in a safe poweroff state. */
+# define VR30_PANEL_ON                 (1 << 15)
+
+#define VR40           0x40
+# define VR40_STALL_ENABLE             (1 << 13)
+# define VR40_VERTICAL_INTERP_ENABLE   (1 << 12)
+# define VR40_ENHANCED_PANEL_FITTING   (1 << 11)
+# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10)
+# define VR40_AUTO_RATIO_ENABLE                (1 << 9)
+# define VR40_CLOCK_GATING_ENABLE      (1 << 8)
+
+/*
+ * Panel Fitting Vertical Ratio
+ * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
+ */
+#define VR41           0x41
+
+/*
+ * Panel Fitting Horizontal Ratio
+ * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
+ */
+#define VR42           0x42
+
+/*
+ * Horizontal Image Size
+ */
+#define VR43           0x43
+
+/* VR80 GPIO 0
+ */
+#define VR80       0x80
+#define VR81       0x81
+#define VR82       0x82
+#define VR83       0x83
+#define VR84       0x84
+#define VR85       0x85
+#define VR86       0x86
+#define VR87       0x87
+
+/* VR88 GPIO 8
+ */
+#define VR88       0x88
+
+/* Graphics BIOS scratch 0
+ */
+#define VR8E       0x8E
+# define VR8E_PANEL_TYPE_MASK          (0xf << 0)
+# define VR8E_PANEL_INTERFACE_CMOS     (0 << 4)
+# define VR8E_PANEL_INTERFACE_LVDS     (1 << 4)
+# define VR8E_FORCE_DEFAULT_PANEL      (1 << 5)
+
+/* Graphics BIOS scratch 1
+ */
+#define VR8F       0x8F
+# define VR8F_VCH_PRESENT              (1 << 0)
+# define VR8F_DISPLAY_CONN             (1 << 1)
+# define VR8F_POWER_MASK               (0x3c)
+# define VR8F_POWER_POS                        (2)
+
+
+struct ivch_priv {
+       bool quiet;
+
+       uint16_t width, height;
+
+       uint16_t save_VR01;
+       uint16_t save_VR40;
+};
+
+
+static void ivch_dump_regs(struct intel_dvo_device *dvo);
+
+/**
+ * Reads a register on the ivch.
+ *
+ * Each of the 256 registers are 16 bits long.
+ */
+static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       u8 out_buf[1];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 0,
+               },
+               {
+                       .addr = 0,
+                       .flags = I2C_M_NOSTART,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = I2C_M_RD | I2C_M_NOSTART,
+                       .len = 2,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+
+       if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
+               *data = (in_buf[1] << 8) | in_buf[0];
+               return true;
+       };
+
+       if (!priv->quiet) {
+               DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+       return false;
+}
+
+/** Writes a 16-bit register on the ivch */
+static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       u8 out_buf[3];
+       struct i2c_msg msg = {
+               .addr = i2cbus->slave_addr,
+               .flags = 0,
+               .len = 3,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = data & 0xff;
+       out_buf[2] = data >> 8;
+
+       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+               return true;
+
+       if (!priv->quiet) {
+               DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+
+       return false;
+}
+
+/** Probes the given bus and slave address for an ivch */
+static bool ivch_init(struct intel_dvo_device *dvo,
+                     struct intel_i2c_chan *i2cbus)
+{
+       struct ivch_priv *priv;
+       uint16_t temp;
+
+       priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
+       if (priv == NULL)
+               return false;
+
+       dvo->i2c_bus = i2cbus;
+       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->dev_priv = priv;
+       priv->quiet = true;
+
+       if (!ivch_read(dvo, VR00, &temp))
+               goto out;
+       priv->quiet = false;
+
+       /* Since the identification bits are probably zeroes, which doesn't seem
+        * very unique, check that the value in the base address field matches
+        * the address it's responding on.
+        */
+       if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
+               DRM_DEBUG("ivch detect failed due to address mismatch "
+                         "(%d vs %d)\n",
+                         (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
+               goto out;
+       }
+
+       ivch_read(dvo, VR20, &priv->width);
+       ivch_read(dvo, VR21, &priv->height);
+
+       return true;
+
+out:
+       kfree(priv);
+       return false;
+}
+
+static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
+{
+       return connector_status_connected;
+}
+
+static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
+                                           struct drm_display_mode *mode)
+{
+       if (mode->clock > 112000)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+/** Sets the power state of the panel connected to the ivch */
+static void ivch_dpms(struct intel_dvo_device *dvo, int mode)
+{
+       int i;
+       uint16_t vr01, vr30, backlight;
+
+       /* Set the new power state of the panel. */
+       if (!ivch_read(dvo, VR01, &vr01))
+               return;
+
+       if (mode == DRM_MODE_DPMS_ON)
+               backlight = 1;
+       else
+               backlight = 0;
+       ivch_write(dvo, VR80, backlight);
+
+       if (mode == DRM_MODE_DPMS_ON)
+               vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
+       else
+               vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
+
+       ivch_write(dvo, VR01, vr01);
+
+       /* Wait for the panel to make its state transition */
+       for (i = 0; i < 100; i++) {
+               if (!ivch_read(dvo, VR30, &vr30))
+                       break;
+
+               if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON))
+                       break;
+               udelay(1000);
+       }
+       /* wait some more; vch may fail to resync sometimes without this */
+       udelay(16 * 1000);
+}
+
+static void ivch_mode_set(struct intel_dvo_device *dvo,
+                         struct drm_display_mode *mode,
+                         struct drm_display_mode *adjusted_mode)
+{
+       uint16_t vr40 = 0;
+       uint16_t vr01;
+
+       vr01 = 0;
+       vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
+               VR40_HORIZONTAL_INTERP_ENABLE);
+
+       if (mode->hdisplay != adjusted_mode->hdisplay ||
+           mode->vdisplay != adjusted_mode->vdisplay) {
+               uint16_t x_ratio, y_ratio;
+
+               vr01 |= VR01_PANEL_FIT_ENABLE;
+               vr40 |= VR40_CLOCK_GATING_ENABLE;
+               x_ratio = (((mode->hdisplay - 1) << 16) /
+                          (adjusted_mode->hdisplay - 1)) >> 2;
+               y_ratio = (((mode->vdisplay - 1) << 16) /
+                          (adjusted_mode->vdisplay - 1)) >> 2;
+               ivch_write (dvo, VR42, x_ratio);
+               ivch_write (dvo, VR41, y_ratio);
+       } else {
+               vr01 &= ~VR01_PANEL_FIT_ENABLE;
+               vr40 &= ~VR40_CLOCK_GATING_ENABLE;
+       }
+       vr40 &= ~VR40_AUTO_RATIO_ENABLE;
+
+       ivch_write(dvo, VR01, vr01);
+       ivch_write(dvo, VR40, vr40);
+
+       ivch_dump_regs(dvo);
+}
+
+static void ivch_dump_regs(struct intel_dvo_device *dvo)
+{
+       uint16_t val;
+
+       ivch_read(dvo, VR00, &val);
+       DRM_DEBUG("VR00: 0x%04x\n", val);
+       ivch_read(dvo, VR01, &val);
+       DRM_DEBUG("VR01: 0x%04x\n", val);
+       ivch_read(dvo, VR30, &val);
+       DRM_DEBUG("VR30: 0x%04x\n", val);
+       ivch_read(dvo, VR40, &val);
+       DRM_DEBUG("VR40: 0x%04x\n", val);
+
+       /* GPIO registers */
+       ivch_read(dvo, VR80, &val);
+       DRM_DEBUG("VR80: 0x%04x\n", val);
+       ivch_read(dvo, VR81, &val);
+       DRM_DEBUG("VR81: 0x%04x\n", val);
+       ivch_read(dvo, VR82, &val);
+       DRM_DEBUG("VR82: 0x%04x\n", val);
+       ivch_read(dvo, VR83, &val);
+       DRM_DEBUG("VR83: 0x%04x\n", val);
+       ivch_read(dvo, VR84, &val);
+       DRM_DEBUG("VR84: 0x%04x\n", val);
+       ivch_read(dvo, VR85, &val);
+       DRM_DEBUG("VR85: 0x%04x\n", val);
+       ivch_read(dvo, VR86, &val);
+       DRM_DEBUG("VR86: 0x%04x\n", val);
+       ivch_read(dvo, VR87, &val);
+       DRM_DEBUG("VR87: 0x%04x\n", val);
+       ivch_read(dvo, VR88, &val);
+       DRM_DEBUG("VR88: 0x%04x\n", val);
+
+       /* Scratch register 0 - AIM Panel type */
+       ivch_read(dvo, VR8E, &val);
+       DRM_DEBUG("VR8E: 0x%04x\n", val);
+
+       /* Scratch register 1 - Status register */
+       ivch_read(dvo, VR8F, &val);
+       DRM_DEBUG("VR8F: 0x%04x\n", val);
+}
+
+static void ivch_save(struct intel_dvo_device *dvo)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+
+       ivch_read(dvo, VR01, &priv->save_VR01);
+       ivch_read(dvo, VR40, &priv->save_VR40);
+}
+
+static void ivch_restore(struct intel_dvo_device *dvo)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+
+       ivch_write(dvo, VR01, priv->save_VR01);
+       ivch_write(dvo, VR40, priv->save_VR40);
+}
+
+static void ivch_destroy(struct intel_dvo_device *dvo)
+{
+       struct ivch_priv *priv = dvo->dev_priv;
+
+       if (priv) {
+               kfree(priv);
+               dvo->dev_priv = NULL;
+       }
+}
+
+struct intel_dvo_dev_ops ivch_ops= {
+       .init = ivch_init,
+       .dpms = ivch_dpms,
+       .save = ivch_save,
+       .restore = ivch_restore,
+       .mode_valid = ivch_mode_valid,
+       .mode_set = ivch_mode_set,
+       .detect = ivch_detect,
+       .dump_regs = ivch_dump_regs,
+       .destroy = ivch_destroy,
+};
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
new file mode 100644 (file)
index 0000000..033a4bb
--- /dev/null
@@ -0,0 +1,302 @@
+/**************************************************************************
+
+Copyright Â© 2006 Dave Airlie
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include "dvo.h"
+
+#define SIL164_VID 0x0001
+#define SIL164_DID 0x0006
+
+#define SIL164_VID_LO 0x00
+#define SIL164_VID_HI 0x01
+#define SIL164_DID_LO 0x02
+#define SIL164_DID_HI 0x03
+#define SIL164_REV    0x04
+#define SIL164_RSVD   0x05
+#define SIL164_FREQ_LO 0x06
+#define SIL164_FREQ_HI 0x07
+
+#define SIL164_REG8 0x08
+#define SIL164_8_VEN (1<<5)
+#define SIL164_8_HEN (1<<4)
+#define SIL164_8_DSEL (1<<3)
+#define SIL164_8_BSEL (1<<2)
+#define SIL164_8_EDGE (1<<1)
+#define SIL164_8_PD   (1<<0)
+
+#define SIL164_REG9 0x09
+#define SIL164_9_VLOW (1<<7)
+#define SIL164_9_MSEL_MASK (0x7<<4)
+#define SIL164_9_TSEL (1<<3)
+#define SIL164_9_RSEN (1<<2)
+#define SIL164_9_HTPLG (1<<1)
+#define SIL164_9_MDI (1<<0)
+
+#define SIL164_REGC 0x0c
+
+struct sil164_save_rec {
+       uint8_t reg8;
+       uint8_t reg9;
+       uint8_t regc;
+};
+
+struct sil164_priv {
+       //I2CDevRec d;
+       bool quiet;
+       struct sil164_save_rec save_regs;
+       struct sil164_save_rec mode_regs;
+};
+
+#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
+
+static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
+{
+       struct sil164_priv *sil = dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       };
+
+       if (!sil->quiet) {
+               DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+       return false;
+}
+
+static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
+{
+       struct sil164_priv *sil= dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       uint8_t out_buf[2];
+       struct i2c_msg msg = {
+               .addr = i2cbus->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+               return true;
+
+       if (!sil->quiet) {
+               DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+
+       return false;
+}
+
+/* Silicon Image 164 driver for chip on i2c bus */
+static bool sil164_init(struct intel_dvo_device *dvo,
+                       struct intel_i2c_chan *i2cbus)
+{
+       /* this will detect the SIL164 chip on the specified i2c bus */
+       struct sil164_priv *sil;
+       unsigned char ch;
+
+       sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
+       if (sil == NULL)
+               return false;
+
+       dvo->i2c_bus = i2cbus;
+       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->dev_priv = sil;
+       sil->quiet = true;
+
+       if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
+               goto out;
+
+       if (ch != (SIL164_VID & 0xff)) {
+               DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
+                         ch, i2cbus->adapter.name, i2cbus->slave_addr);
+               goto out;
+       }
+
+       if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
+               goto out;
+
+       if (ch != (SIL164_DID & 0xff)) {
+               DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
+                         ch, i2cbus->adapter.name, i2cbus->slave_addr);
+               goto out;
+       }
+       sil->quiet = false;
+
+       DRM_DEBUG("init sil164 dvo controller successfully!\n");
+       return true;
+
+out:
+       kfree(sil);
+       return false;
+}
+
+static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
+{
+       uint8_t reg9;
+
+       sil164_readb(dvo, SIL164_REG9, &reg9);
+
+       if (reg9 & SIL164_9_HTPLG)
+               return connector_status_connected;
+       else
+               return connector_status_disconnected;
+}
+
+static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static void sil164_mode_set(struct intel_dvo_device *dvo,
+                           struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+       /* As long as the basics are set up, since we don't have clock
+        * dependencies in the mode setup, we can just leave the
+        * registers alone and everything will work fine.
+        */
+       /* recommended programming sequence from doc */
+       /*sil164_writeb(sil, 0x08, 0x30);
+         sil164_writeb(sil, 0x09, 0x00);
+         sil164_writeb(sil, 0x0a, 0x90);
+         sil164_writeb(sil, 0x0c, 0x89);
+         sil164_writeb(sil, 0x08, 0x31);*/
+       /* don't do much */
+       return;
+}
+
+/* set the SIL164 power state */
+static void sil164_dpms(struct intel_dvo_device *dvo, int mode)
+{
+       int ret;
+       unsigned char ch;
+
+       ret = sil164_readb(dvo, SIL164_REG8, &ch);
+       if (ret == false)
+               return;
+
+       if (mode == DRM_MODE_DPMS_ON)
+               ch |= SIL164_8_PD;
+       else
+               ch &= ~SIL164_8_PD;
+
+       sil164_writeb(dvo, SIL164_REG8, ch);
+       return;
+}
+
+static void sil164_dump_regs(struct intel_dvo_device *dvo)
+{
+       uint8_t val;
+
+       sil164_readb(dvo, SIL164_FREQ_LO, &val);
+       DRM_DEBUG("SIL164_FREQ_LO: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_FREQ_HI, &val);
+       DRM_DEBUG("SIL164_FREQ_HI: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_REG8, &val);
+       DRM_DEBUG("SIL164_REG8: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_REG9, &val);
+       DRM_DEBUG("SIL164_REG9: 0x%02x\n", val);
+       sil164_readb(dvo, SIL164_REGC, &val);
+       DRM_DEBUG("SIL164_REGC: 0x%02x\n", val);
+}
+
+static void sil164_save(struct intel_dvo_device *dvo)
+{
+       struct sil164_priv *sil= dvo->dev_priv;
+
+       if (!sil164_readb(dvo, SIL164_REG8, &sil->save_regs.reg8))
+               return;
+
+       if (!sil164_readb(dvo, SIL164_REG9, &sil->save_regs.reg9))
+               return;
+
+       if (!sil164_readb(dvo, SIL164_REGC, &sil->save_regs.regc))
+               return;
+
+       return;
+}
+
+static void sil164_restore(struct intel_dvo_device *dvo)
+{
+       struct sil164_priv *sil = dvo->dev_priv;
+
+       /* Restore it powered down initially */
+       sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8 & ~0x1);
+
+       sil164_writeb(dvo, SIL164_REG9, sil->save_regs.reg9);
+       sil164_writeb(dvo, SIL164_REGC, sil->save_regs.regc);
+       sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8);
+}
+
+static void sil164_destroy(struct intel_dvo_device *dvo)
+{
+       struct sil164_priv *sil = dvo->dev_priv;
+
+       if (sil) {
+               kfree(sil);
+               dvo->dev_priv = NULL;
+       }
+}
+
+struct intel_dvo_dev_ops sil164_ops = {
+       .init = sil164_init,
+       .detect = sil164_detect,
+       .mode_valid = sil164_mode_valid,
+       .mode_set = sil164_mode_set,
+       .dpms = sil164_dpms,
+       .dump_regs = sil164_dump_regs,
+       .save = sil164_save,
+       .restore = sil164_restore,
+       .destroy = sil164_destroy,
+};
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
new file mode 100644 (file)
index 0000000..207fda8
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright Â© 2007 Dave Mueller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Dave Mueller <dave.mueller@gmx.ch>
+ *
+ */
+
+#include "dvo.h"
+
+/* register definitions according to the TFP410 data sheet */
+#define TFP410_VID             0x014C
+#define TFP410_DID             0x0410
+
+#define TFP410_VID_LO          0x00
+#define TFP410_VID_HI          0x01
+#define TFP410_DID_LO          0x02
+#define TFP410_DID_HI          0x03
+#define TFP410_REV             0x04
+
+#define TFP410_CTL_1           0x08
+#define TFP410_CTL_1_TDIS      (1<<6)
+#define TFP410_CTL_1_VEN       (1<<5)
+#define TFP410_CTL_1_HEN       (1<<4)
+#define TFP410_CTL_1_DSEL      (1<<3)
+#define TFP410_CTL_1_BSEL      (1<<2)
+#define TFP410_CTL_1_EDGE      (1<<1)
+#define TFP410_CTL_1_PD                (1<<0)
+
+#define TFP410_CTL_2           0x09
+#define TFP410_CTL_2_VLOW      (1<<7)
+#define TFP410_CTL_2_MSEL_MASK (0x7<<4)
+#define TFP410_CTL_2_MSEL      (1<<4)
+#define TFP410_CTL_2_TSEL      (1<<3)
+#define TFP410_CTL_2_RSEN      (1<<2)
+#define TFP410_CTL_2_HTPLG     (1<<1)
+#define TFP410_CTL_2_MDI       (1<<0)
+
+#define TFP410_CTL_3           0x0A
+#define TFP410_CTL_3_DK_MASK   (0x7<<5)
+#define TFP410_CTL_3_DK                (1<<5)
+#define TFP410_CTL_3_DKEN      (1<<4)
+#define TFP410_CTL_3_CTL_MASK  (0x7<<1)
+#define TFP410_CTL_3_CTL       (1<<1)
+
+#define TFP410_USERCFG         0x0B
+
+#define TFP410_DE_DLY          0x32
+
+#define TFP410_DE_CTL          0x33
+#define TFP410_DE_CTL_DEGEN    (1<<6)
+#define TFP410_DE_CTL_VSPOL    (1<<5)
+#define TFP410_DE_CTL_HSPOL    (1<<4)
+#define TFP410_DE_CTL_DEDLY8   (1<<0)
+
+#define TFP410_DE_TOP          0x34
+
+#define TFP410_DE_CNT_LO       0x36
+#define TFP410_DE_CNT_HI       0x37
+
+#define TFP410_DE_LIN_LO       0x38
+#define TFP410_DE_LIN_HI       0x39
+
+#define TFP410_H_RES_LO                0x3A
+#define TFP410_H_RES_HI                0x3B
+
+#define TFP410_V_RES_LO                0x3C
+#define TFP410_V_RES_HI                0x3D
+
+struct tfp410_save_rec {
+       uint8_t ctl1;
+       uint8_t ctl2;
+};
+
+struct tfp410_priv {
+       bool quiet;
+
+       struct tfp410_save_rec saved_reg;
+       struct tfp410_save_rec mode_reg;
+};
+
+static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       u8 out_buf[2];
+       u8 in_buf[2];
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = i2cbus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = in_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+               *ch = in_buf[0];
+               return true;
+       };
+
+       if (!tfp->quiet) {
+               DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+       return false;
+}
+
+static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+       struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+       uint8_t out_buf[2];
+       struct i2c_msg msg = {
+               .addr = i2cbus->slave_addr,
+               .flags = 0,
+               .len = 2,
+               .buf = out_buf,
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+               return true;
+
+       if (!tfp->quiet) {
+               DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
+                         addr, i2cbus->adapter.name, i2cbus->slave_addr);
+       }
+
+       return false;
+}
+
+static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
+{
+       uint8_t ch1, ch2;
+
+       if (tfp410_readb(dvo, addr+0, &ch1) &&
+           tfp410_readb(dvo, addr+1, &ch2))
+               return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
+
+       return -1;
+}
+
+/* Ti TFP410 driver for chip on i2c bus */
+static bool tfp410_init(struct intel_dvo_device *dvo,
+                       struct intel_i2c_chan *i2cbus)
+{
+       /* this will detect the tfp410 chip on the specified i2c bus */
+       struct tfp410_priv *tfp;
+       int id;
+
+       tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
+       if (tfp == NULL)
+               return false;
+
+       dvo->i2c_bus = i2cbus;
+       dvo->i2c_bus->slave_addr = dvo->slave_addr;
+       dvo->dev_priv = tfp;
+       tfp->quiet = true;
+
+       if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
+               DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n",
+                         id, i2cbus->adapter.name, i2cbus->slave_addr);
+               goto out;
+       }
+
+       if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
+               DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n",
+                         id, i2cbus->adapter.name, i2cbus->slave_addr);
+               goto out;
+       }
+       tfp->quiet = false;
+       return true;
+out:
+       kfree(tfp);
+       return false;
+}
+
+static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
+{
+       enum drm_connector_status ret = connector_status_disconnected;
+       uint8_t ctl2;
+
+       if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
+               if (ctl2 & TFP410_CTL_2_HTPLG)
+                       ret = connector_status_connected;
+               else
+                       ret = connector_status_disconnected;
+       }
+
+       return ret;
+}
+
+static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
+                                             struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static void tfp410_mode_set(struct intel_dvo_device *dvo,
+                           struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+    /* As long as the basics are set up, since we don't have clock dependencies
+     * in the mode setup, we can just leave the registers alone and everything
+     * will work fine.
+     */
+    /* don't do much */
+    return;
+}
+
+/* set the tfp410 power state */
+static void tfp410_dpms(struct intel_dvo_device *dvo, int mode)
+{
+       uint8_t ctl1;
+
+       if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
+               return;
+
+       if (mode == DRM_MODE_DPMS_ON)
+               ctl1 |= TFP410_CTL_1_PD;
+       else
+               ctl1 &= ~TFP410_CTL_1_PD;
+
+       tfp410_writeb(dvo, TFP410_CTL_1, ctl1);
+}
+
+static void tfp410_dump_regs(struct intel_dvo_device *dvo)
+{
+       uint8_t val, val2;
+
+       tfp410_readb(dvo, TFP410_REV, &val);
+       DRM_DEBUG("TFP410_REV: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_CTL_1, &val);
+       DRM_DEBUG("TFP410_CTL1: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_CTL_2, &val);
+       DRM_DEBUG("TFP410_CTL2: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_CTL_3, &val);
+       DRM_DEBUG("TFP410_CTL3: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_USERCFG, &val);
+       DRM_DEBUG("TFP410_USERCFG: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_DLY, &val);
+       DRM_DEBUG("TFP410_DE_DLY: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_CTL, &val);
+       DRM_DEBUG("TFP410_DE_CTL: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_TOP, &val);
+       DRM_DEBUG("TFP410_DE_TOP: 0x%02X\n", val);
+       tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
+       tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
+       DRM_DEBUG("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
+       tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
+       tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
+       DRM_DEBUG("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
+       tfp410_readb(dvo, TFP410_H_RES_LO, &val);
+       tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
+       DRM_DEBUG("TFP410_H_RES: 0x%02X%02X\n", val2, val);
+       tfp410_readb(dvo, TFP410_V_RES_LO, &val);
+       tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
+       DRM_DEBUG("TFP410_V_RES: 0x%02X%02X\n", val2, val);
+}
+
+static void tfp410_save(struct intel_dvo_device *dvo)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+
+       if (!tfp410_readb(dvo, TFP410_CTL_1, &tfp->saved_reg.ctl1))
+               return;
+
+       if (!tfp410_readb(dvo, TFP410_CTL_2, &tfp->saved_reg.ctl2))
+               return;
+}
+
+static void tfp410_restore(struct intel_dvo_device *dvo)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+
+       /* Restore it powered down initially */
+       tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1 & ~0x1);
+
+       tfp410_writeb(dvo, TFP410_CTL_2, tfp->saved_reg.ctl2);
+       tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1);
+}
+
+static void tfp410_destroy(struct intel_dvo_device *dvo)
+{
+       struct tfp410_priv *tfp = dvo->dev_priv;
+
+       if (tfp) {
+               kfree(tfp);
+               dvo->dev_priv = NULL;
+       }
+}
+
+struct intel_dvo_dev_ops tfp410_ops = {
+       .init = tfp410_init,
+       .detect = tfp410_detect,
+       .mode_valid = tfp410_mode_valid,
+       .mode_set = tfp410_mode_set,
+       .dpms = tfp410_dpms,
+       .dump_regs = tfp410_dump_regs,
+       .save = tfp410_save,
+       .restore = tfp410_restore,
+       .destroy = tfp410_destroy,
+};
index afa8a12cd00902c1c34ea4f4ba83e55c3b7a74e2..3d7082af5b72b5f5287412f7b6294d9947ace12c 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "drmP.h"
 #include "drm.h"
+#include "drm_crtc_helper.h"
+#include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
 
@@ -39,6 +41,7 @@
 int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
        u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
        u32 last_acthd = I915_READ(acthd_reg);
@@ -55,8 +58,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
                if (ring->space >= n)
                        return 0;
 
-               if (dev_priv->sarea_priv)
-                       dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+               if (master_priv->sarea_priv)
+                       master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
                if (ring->head != last_head)
                        i = 0;
@@ -121,16 +124,28 @@ static void i915_free_hws(struct drm_device *dev)
 void i915_kernel_lost_context(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv;
        drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
 
+       /*
+        * We should never lose context on the ring with modesetting
+        * as we don't expose it to userspace
+        */
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
+
        ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
        ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
        ring->space = ring->head - (ring->tail + 8);
        if (ring->space < 0)
                ring->space += ring->Size;
 
-       if (ring->head == ring->tail && dev_priv->sarea_priv)
-               dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
+       if (!dev->primary->master)
+               return;
+
+       master_priv = dev->primary->master->driver_priv;
+       if (ring->head == ring->tail && master_priv->sarea_priv)
+               master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
 }
 
 static int i915_dma_cleanup(struct drm_device * dev)
@@ -154,25 +169,13 @@ static int i915_dma_cleanup(struct drm_device * dev)
        if (I915_NEED_GFX_HWS(dev))
                i915_free_hws(dev);
 
-       dev_priv->sarea = NULL;
-       dev_priv->sarea_priv = NULL;
-
        return 0;
 }
 
 static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-
-       dev_priv->sarea = drm_getsarea(dev);
-       if (!dev_priv->sarea) {
-               DRM_ERROR("can not find sarea!\n");
-               i915_dma_cleanup(dev);
-               return -EINVAL;
-       }
-
-       dev_priv->sarea_priv = (drm_i915_sarea_t *)
-           ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 
        if (init->ring_size != 0) {
                if (dev_priv->ring.ring_obj != NULL) {
@@ -207,7 +210,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
        dev_priv->back_offset = init->back_offset;
        dev_priv->front_offset = init->front_offset;
        dev_priv->current_page = 0;
-       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+       if (master_priv->sarea_priv)
+               master_priv->sarea_priv->pf_current_page = 0;
 
        /* Allow hardware batchbuffers unless told otherwise.
         */
@@ -222,11 +226,6 @@ static int i915_dma_resume(struct drm_device * dev)
 
        DRM_DEBUG("%s\n", __func__);
 
-       if (!dev_priv->sarea) {
-               DRM_ERROR("can not find sarea!\n");
-               return -EINVAL;
-       }
-
        if (dev_priv->ring.map.handle == NULL) {
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
@@ -435,13 +434,14 @@ i915_emit_box(struct drm_device *dev,
 static void i915_emit_breadcrumb(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        RING_LOCALS;
 
        dev_priv->counter++;
        if (dev_priv->counter > 0x7FFFFFFFUL)
                dev_priv->counter = 0;
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
+       if (master_priv->sarea_priv)
+               master_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_STORE_DWORD_INDEX);
@@ -537,15 +537,17 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
 static int i915_dispatch_flip(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv =
+               dev->primary->master->driver_priv;
        RING_LOCALS;
 
-       if (!dev_priv->sarea_priv)
+       if (!master_priv->sarea_priv)
                return -EINVAL;
 
        DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
                  __func__,
                  dev_priv->current_page,
-                 dev_priv->sarea_priv->pf_current_page);
+                 master_priv->sarea_priv->pf_current_page);
 
        i915_kernel_lost_context(dev);
 
@@ -572,7 +574,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
        OUT_RING(0);
        ADVANCE_LP_RING();
 
-       dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+       master_priv->sarea_priv->last_enqueue = dev_priv->counter++;
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_STORE_DWORD_INDEX);
@@ -581,7 +583,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
        OUT_RING(0);
        ADVANCE_LP_RING();
 
-       dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
+       master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
        return 0;
 }
 
@@ -611,8 +613,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-           dev_priv->sarea_priv;
+           master_priv->sarea_priv;
        drm_i915_batchbuffer_t *batch = data;
        int ret;
 
@@ -644,8 +647,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-           dev_priv->sarea_priv;
+           master_priv->sarea_priv;
        drm_i915_cmdbuffer_t *cmdbuf = data;
        int ret;
 
@@ -774,6 +778,11 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               WARN(1, "tried to set status page when mode setting active\n");
+               return 0;
+       }
+
        printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);
 
        dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
@@ -802,6 +811,214 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
        return 0;
 }
 
+/**
+ * i915_probe_agp - get AGP bootup configuration
+ * @pdev: PCI device
+ * @aperture_size: returns AGP aperture configured size
+ * @preallocated_size: returns size of BIOS preallocated AGP space
+ *
+ * Since Intel integrated graphics are UMA, the BIOS has to set aside
+ * some RAM for the framebuffer at early boot.  This code figures out
+ * how much was set aside so we can use it for our own purposes.
+ */
+static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
+                         unsigned long *preallocated_size)
+{
+       struct pci_dev *bridge_dev;
+       u16 tmp = 0;
+       unsigned long overhead;
+
+       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+       if (!bridge_dev) {
+               DRM_ERROR("bridge device not found\n");
+               return -1;
+       }
+
+       /* Get the fb aperture size and "stolen" memory amount. */
+       pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
+       pci_dev_put(bridge_dev);
+
+       *aperture_size = 1024 * 1024;
+       *preallocated_size = 1024 * 1024;
+
+       switch (dev->pdev->device) {
+       case PCI_DEVICE_ID_INTEL_82830_CGC:
+       case PCI_DEVICE_ID_INTEL_82845G_IG:
+       case PCI_DEVICE_ID_INTEL_82855GM_IG:
+       case PCI_DEVICE_ID_INTEL_82865_IG:
+               if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
+                       *aperture_size *= 64;
+               else
+                       *aperture_size *= 128;
+               break;
+       default:
+               /* 9xx supports large sizes, just look at the length */
+               *aperture_size = pci_resource_len(dev->pdev, 2);
+               break;
+       }
+
+       /*
+        * Some of the preallocated space is taken by the GTT
+        * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
+        */
+       if (IS_G4X(dev))
+               overhead = 4096;
+       else
+               overhead = (*aperture_size / 1024) + 4096;
+
+       switch (tmp & INTEL_855_GMCH_GMS_MASK) {
+       case INTEL_855_GMCH_GMS_STOLEN_1M:
+               break; /* 1M already */
+       case INTEL_855_GMCH_GMS_STOLEN_4M:
+               *preallocated_size *= 4;
+               break;
+       case INTEL_855_GMCH_GMS_STOLEN_8M:
+               *preallocated_size *= 8;
+               break;
+       case INTEL_855_GMCH_GMS_STOLEN_16M:
+               *preallocated_size *= 16;
+               break;
+       case INTEL_855_GMCH_GMS_STOLEN_32M:
+               *preallocated_size *= 32;
+               break;
+       case INTEL_915G_GMCH_GMS_STOLEN_48M:
+               *preallocated_size *= 48;
+               break;
+       case INTEL_915G_GMCH_GMS_STOLEN_64M:
+               *preallocated_size *= 64;
+               break;
+       case INTEL_855_GMCH_GMS_DISABLED:
+               DRM_ERROR("video memory is disabled\n");
+               return -1;
+       default:
+               DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
+                       tmp & INTEL_855_GMCH_GMS_MASK);
+               return -1;
+       }
+       *preallocated_size -= overhead;
+
+       return 0;
+}
+
+static int i915_load_modeset_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long agp_size, prealloc_size;
+       int fb_bar = IS_I9XX(dev) ? 2 : 0;
+       int ret = 0;
+
+       dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL);
+       if (!dev->devname) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) &
+               0xff000000;
+
+       DRM_DEBUG("*** fb base 0x%08lx\n", dev->mode_config.fb_base);
+
+       if (IS_MOBILE(dev) || (IS_I9XX(dev) && !IS_I965G(dev) && !IS_G33(dev)))
+               dev_priv->cursor_needs_physical = true;
+       else
+               dev_priv->cursor_needs_physical = false;
+
+       ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
+       if (ret)
+               goto kfree_devname;
+
+       /* Basic memrange allocator for stolen space (aka vram) */
+       drm_mm_init(&dev_priv->vram, 0, prealloc_size);
+
+       /* Let GEM Manage from end of prealloc space to end of aperture */
+       i915_gem_do_init(dev, prealloc_size, agp_size);
+
+       ret = i915_gem_init_ringbuffer(dev);
+       if (ret)
+               goto kfree_devname;
+
+        dev_priv->mm.gtt_mapping =
+               io_mapping_create_wc(dev->agp->base,
+                                    dev->agp->agp_info.aper_size * 1024*1024);
+
+       /* Allow hardware batchbuffers unless told otherwise.
+        */
+       dev_priv->allow_batchbuffer = 1;
+
+       ret = intel_init_bios(dev);
+       if (ret)
+               DRM_INFO("failed to find VBIOS tables\n");
+
+       ret = drm_irq_install(dev);
+       if (ret)
+               goto destroy_ringbuffer;
+
+       /* FIXME: re-add hotplug support */
+#if 0
+       ret = drm_hotplug_init(dev);
+       if (ret)
+               goto destroy_ringbuffer;
+#endif
+
+       /* Always safe in the mode setting case. */
+       /* FIXME: do pre/post-mode set stuff in core KMS code */
+       dev->vblank_disable_allowed = 1;
+
+       /*
+        * Initialize the hardware status page IRQ location.
+        */
+
+       I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
+
+       intel_modeset_init(dev);
+
+       drm_helper_initial_config(dev, false);
+
+       return 0;
+
+destroy_ringbuffer:
+       i915_gem_cleanup_ringbuffer(dev);
+kfree_devname:
+       kfree(dev->devname);
+out:
+       return ret;
+}
+
+int i915_master_create(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_i915_master_private *master_priv;
+
+       master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
+       if (!master_priv)
+               return -ENOMEM;
+
+       master->driver_priv = master_priv;
+       return 0;
+}
+
+void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_i915_master_private *master_priv = master->driver_priv;
+
+       if (!master_priv)
+               return;
+
+       drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);
+
+       master->driver_priv = NULL;
+}
+
+/**
+ * i915_driver_load - setup chip and create an initial config
+ * @dev: DRM device
+ * @flags: startup flags
+ *
+ * The driver load routine has to do several things:
+ *   - drive output discovery via intel_modeset_init()
+ *   - initialize the memory manager
+ *   - allocate initial config memory
+ *   - setup the DRM framebuffer with the allocated memory
+ */
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -829,6 +1046,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        size = drm_get_resource_len(dev, mmio_bar);
 
        dev_priv->regs = ioremap(base, size);
+       if (!dev_priv->regs) {
+               DRM_ERROR("failed to map registers\n");
+               ret = -EIO;
+               goto free_priv;
+       }
 
 #ifdef CONFIG_HIGHMEM64G
        /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */
@@ -844,7 +1066,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (!I915_NEED_GFX_HWS(dev)) {
                ret = i915_init_phys_hws(dev);
                if (ret != 0)
-                       return ret;
+                       goto out_rmmap;
        }
 
        /* On the 945G/GM, the chipset reports the MSI capability on the
@@ -864,6 +1086,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_opregion_init(dev);
 
        spin_lock_init(&dev_priv->user_irq_lock);
+       dev_priv->user_irq_refcount = 0;
 
        ret = drm_vblank_init(dev, I915_NUM_PIPE);
 
@@ -872,6 +1095,20 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                return ret;
        }
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               ret = i915_load_modeset_init(dev);
+               if (ret < 0) {
+                       DRM_ERROR("failed to init modeset\n");
+                       goto out_rmmap;
+               }
+       }
+
+       return 0;
+
+out_rmmap:
+       iounmap(dev_priv->regs);
+free_priv:
+       drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER);
        return ret;
 }
 
@@ -879,16 +1116,29 @@ int i915_driver_unload(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               io_mapping_free(dev_priv->mm.gtt_mapping);
+               drm_irq_uninstall(dev);
+       }
+
        if (dev->pdev->msi_enabled)
                pci_disable_msi(dev->pdev);
 
-       i915_free_hws(dev);
-
        if (dev_priv->regs != NULL)
                iounmap(dev_priv->regs);
 
        intel_opregion_free(dev);
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               intel_modeset_cleanup(dev);
+
+               mutex_lock(&dev->struct_mutex);
+               i915_gem_cleanup_ringbuffer(dev);
+               mutex_unlock(&dev->struct_mutex);
+               drm_mm_takedown(&dev_priv->vram);
+               i915_gem_lastclose(dev);
+       }
+
        drm_free(dev->dev_private, sizeof(drm_i915_private_t),
                 DRM_MEM_DRIVER);
 
@@ -914,12 +1164,26 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
        return 0;
 }
 
+/**
+ * i915_driver_lastclose - clean up after all DRM clients have exited
+ * @dev: DRM device
+ *
+ * Take care of cleaning up after all DRM clients have exited.  In the
+ * mode setting case, we want to restore the kernel's initial mode (just
+ * in case the last client left us in a bad state).
+ *
+ * Additionally, in the non-mode setting case, we'll tear down the AGP
+ * and DMA structures, since the kernel won't be using them, and clea
+ * up any GEM state.
+ */
 void i915_driver_lastclose(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       if (!dev_priv)
+       if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
+               intelfb_restore();
                return;
+       }
 
        i915_gem_lastclose(dev);
 
@@ -932,7 +1196,8 @@ void i915_driver_lastclose(struct drm_device * dev)
 void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       i915_mem_release(dev, file_priv, dev_priv->agp_heap);
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
 void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
@@ -972,6 +1237,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0),
+       DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0),
        DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
index a80ead215282b933aacdb5cfab3b3b45f286d74a..f8b3df0926c015a24bda63d9c7ed1756801c2797 100644 (file)
 #include "i915_drv.h"
 
 #include "drm_pciids.h"
+#include <linux/console.h>
+
+static unsigned int i915_modeset = -1;
+module_param_named(modeset, i915_modeset, int, 0400);
+
+unsigned int i915_fbpercrtc = 0;
+module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 
 static struct pci_device_id pciidlist[] = {
        i915_PCI_IDS
 };
 
+#if defined(CONFIG_DRM_I915_KMS)
+MODULE_DEVICE_TABLE(pci, pciidlist);
+#endif
+
 static int i915_suspend(struct drm_device *dev, pm_message_t state)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -81,6 +92,10 @@ static int i915_resume(struct drm_device *dev)
        return 0;
 }
 
+static struct vm_operations_struct i915_gem_vm_ops = {
+       .fault = i915_gem_fault,
+};
+
 static struct drm_driver driver = {
        /* don't use mtrr's here, the Xserver or user space app should
         * deal with them for intel hardware.
@@ -107,17 +122,20 @@ static struct drm_driver driver = {
        .reclaim_buffers = drm_core_reclaim_buffers,
        .get_map_ofs = drm_core_get_map_ofs,
        .get_reg_ofs = drm_core_get_reg_ofs,
+       .master_create = i915_master_create,
+       .master_destroy = i915_master_destroy,
        .proc_init = i915_gem_proc_init,
        .proc_cleanup = i915_gem_proc_cleanup,
        .gem_init_object = i915_gem_init_object,
        .gem_free_object = i915_gem_free_object,
+       .gem_vm_ops = &i915_gem_vm_ops,
        .ioctls = i915_ioctls,
        .fops = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
                 .ioctl = drm_ioctl,
-                .mmap = drm_mmap,
+                .mmap = drm_gem_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
 #ifdef CONFIG_COMPAT
@@ -141,6 +159,28 @@ static struct drm_driver driver = {
 static int __init i915_init(void)
 {
        driver.num_ioctls = i915_max_ioctl;
+
+       /*
+        * If CONFIG_DRM_I915_KMS is set, default to KMS unless
+        * explicitly disabled with the module pararmeter.
+        *
+        * Otherwise, just follow the parameter (defaulting to off).
+        *
+        * Allow optional vga_text_mode_force boot option to override
+        * the default behavior.
+        */
+#if defined(CONFIG_DRM_I915_KMS)
+       if (i915_modeset != 0)
+               driver.driver_features |= DRIVER_MODESET;
+#endif
+       if (i915_modeset == 1)
+               driver.driver_features |= DRIVER_MODESET;
+
+#ifdef CONFIG_VGA_CONSOLE
+       if (vgacon_text_force() && i915_modeset == -1)
+               driver.driver_features &= ~DRIVER_MODESET;
+#endif
+
        return drm_init(&driver);
 }
 
index b3cc4731aa7c07b43d2d9825068f3e8a70ce34bd..4756e5cd6b5e1142781c0dfe35b5f85aeb0df886 100644 (file)
@@ -31,6 +31,7 @@
 #define _I915_DRV_H_
 
 #include "i915_reg.h"
+#include "intel_bios.h"
 #include <linux/io-mapping.h>
 
 /* General customization:
@@ -103,15 +104,23 @@ struct intel_opregion {
        int enabled;
 };
 
+struct drm_i915_master_private {
+       drm_local_map_t *sarea;
+       struct _drm_i915_sarea *sarea_priv;
+};
+#define I915_FENCE_REG_NONE -1
+
+struct drm_i915_fence_reg {
+       struct drm_gem_object *obj;
+};
+
 typedef struct drm_i915_private {
        struct drm_device *dev;
 
        int has_gem;
 
        void __iomem *regs;
-       drm_local_map_t *sarea;
 
-       drm_i915_sarea_t *sarea_priv;
        drm_i915_ring_buffer_t ring;
 
        drm_dma_handle_t *status_page_dmah;
@@ -144,8 +153,30 @@ typedef struct drm_i915_private {
        unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
        int vblank_pipe;
 
+       bool cursor_needs_physical;
+
+       struct drm_mm vram;
+
+       int irq_enabled;
+
        struct intel_opregion opregion;
 
+       /* LVDS info */
+       int backlight_duty_cycle;  /* restore backlight to this value */
+       bool panel_wants_dither;
+       struct drm_display_mode *panel_fixed_mode;
+       struct drm_display_mode *vbt_mode; /* if any */
+
+       /* Feature bits from the VBIOS */
+       unsigned int int_tv_support:1;
+       unsigned int lvds_dither:1;
+       unsigned int lvds_vbt:1;
+       unsigned int int_crt_support:1;
+
+       struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
+       int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
+       int num_fence_regs; /* 8 on pre-965, 16 otherwise */
+
        /* Register state */
        u8 saveLBB;
        u32 saveDSPACNTR;
@@ -364,6 +395,21 @@ struct drm_i915_gem_object {
         * This is the same as gtt_space->start
         */
        uint32_t gtt_offset;
+       /**
+        * Required alignment for the object
+        */
+       uint32_t gtt_alignment;
+       /**
+        * Fake offset for use by mmap(2)
+        */
+       uint64_t mmap_offset;
+
+       /**
+        * Fence register bits (if any) for this object.  Will be set
+        * as needed when mapped into the GTT.
+        * Protected by dev->struct_mutex.
+        */
+       int fence_reg;
 
        /** Boolean whether this object has a valid gtt offset. */
        int gtt_bound;
@@ -376,6 +422,7 @@ struct drm_i915_gem_object {
 
        /** Current tiling mode for the object. */
        uint32_t tiling_mode;
+       uint32_t stride;
 
        /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
        uint32_t agp_type;
@@ -385,6 +432,10 @@ struct drm_i915_gem_object {
         * flags which individual pages are valid.
         */
        uint8_t *page_cpu_valid;
+
+       /** User space pin count and filp owning the pin */
+       uint32_t user_pin_count;
+       struct drm_file *pin_filp;
 };
 
 /**
@@ -414,8 +465,19 @@ struct drm_i915_file_private {
        } mm;
 };
 
+enum intel_chip_family {
+       CHIP_I8XX = 0x01,
+       CHIP_I9XX = 0x02,
+       CHIP_I915 = 0x04,
+       CHIP_I965 = 0x08,
+};
+
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
+extern unsigned int i915_fbpercrtc;
+
+extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
+extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
 
                                /* i915_dma.c */
 extern void i915_kernel_lost_context(struct drm_device * dev);
@@ -441,6 +503,7 @@ extern int i915_irq_wait(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 void i915_user_irq_get(struct drm_device *dev);
 void i915_user_irq_put(struct drm_device *dev);
+extern void i915_enable_interrupt (struct drm_device *dev);
 
 extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(struct drm_device * dev);
@@ -487,6 +550,8 @@ int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *file_priv);
 int i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
+int i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv);
 int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
@@ -523,6 +588,16 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev);
 void i915_gem_retire_requests(struct drm_device *dev);
 void i915_gem_retire_work_handler(struct work_struct *work);
 void i915_gem_clflush_object(struct drm_gem_object *obj);
+int i915_gem_object_set_domain(struct drm_gem_object *obj,
+                              uint32_t read_domains,
+                              uint32_t write_domain);
+int i915_gem_init_ringbuffer(struct drm_device *dev);
+void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
+int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+                    unsigned long end);
+int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
+                                     int write);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
@@ -561,6 +636,10 @@ static inline void opregion_asle_intr(struct drm_device *dev) { return; }
 static inline void opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
+/* modesetting */
+extern void intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_cleanup(struct drm_device *dev);
+
 /**
  * Lock test for when it's just for synchronization of ring access.
  *
@@ -578,6 +657,13 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
 #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg))
 #define I915_READ8(reg)                readb(dev_priv->regs + (reg))
 #define I915_WRITE8(reg, val)  writeb(val, dev_priv->regs + (reg))
+#ifdef writeq
+#define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg))
+#else
+#define I915_WRITE64(reg, val) (writel(val, dev_priv->regs + (reg)), \
+                                writel(upper_32_bits(val), dev_priv->regs + \
+                                       (reg) + 4))
+#endif
 
 #define I915_VERBOSE 0
 
@@ -660,7 +746,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \
                     (dev)->pci_device == 0x2E12 || \
-                    (dev)->pci_device == 0x2E22)
+                    (dev)->pci_device == 0x2E22 || \
+                    IS_GM45(dev))
 
 #define IS_G33(dev)    ((dev)->pci_device == 0x29C2 || \
                        (dev)->pci_device == 0x29B2 ||  \
index 24fe8c10b4b22c6bac1cfa17d79d55f02dd59179..cc2ca5561feb5add0ebac9bd6d3a7d58e4008c4c 100644 (file)
@@ -30,6 +30,7 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 #include <linux/swap.h>
+#include <linux/pci.h>
 
 #define I915_GEM_GPU_DOMAINS   (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
 
@@ -40,8 +41,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
 static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
-static int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
-                                            int write);
 static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
                                             int write);
 static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
@@ -51,34 +50,43 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o
 static int i915_gem_object_get_page_list(struct drm_gem_object *obj);
 static void i915_gem_object_free_page_list(struct drm_gem_object *obj);
 static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
+                                          unsigned alignment);
+static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
+static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
+static int i915_gem_evict_something(struct drm_device *dev);
+
+int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+                    unsigned long end)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
-static void
-i915_gem_cleanup_ringbuffer(struct drm_device *dev);
+       if (start >= end ||
+           (start & (PAGE_SIZE - 1)) != 0 ||
+           (end & (PAGE_SIZE - 1)) != 0) {
+               return -EINVAL;
+       }
+
+       drm_mm_init(&dev_priv->mm.gtt_space, start,
+                   end - start);
+
+       dev->gtt_total = (uint32_t) (end - start);
+
+       return 0;
+}
 
 int
 i915_gem_init_ioctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_gem_init *args = data;
+       int ret;
 
        mutex_lock(&dev->struct_mutex);
-
-       if (args->gtt_start >= args->gtt_end ||
-           (args->gtt_start & (PAGE_SIZE - 1)) != 0 ||
-           (args->gtt_end & (PAGE_SIZE - 1)) != 0) {
-               mutex_unlock(&dev->struct_mutex);
-               return -EINVAL;
-       }
-
-       drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start,
-           args->gtt_end - args->gtt_start);
-
-       dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start);
-
+       ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end);
        mutex_unlock(&dev->struct_mutex);
 
-       return 0;
+       return ret;
 }
 
 int
@@ -529,6 +537,252 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
        return 0;
 }
 
+/**
+ * i915_gem_fault - fault a page into the GTT
+ * vma: VMA in question
+ * vmf: fault info
+ *
+ * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped
+ * from userspace.  The fault handler takes care of binding the object to
+ * the GTT (if needed), allocating and programming a fence register (again,
+ * only if needed based on whether the old reg is still valid or the object
+ * is tiled) and inserting a new PTE into the faulting process.
+ *
+ * Note that the faulting process may involve evicting existing objects
+ * from the GTT and/or fence registers to make room.  So performance may
+ * suffer if the GTT working set is large or there are few fence registers
+ * left.
+ */
+int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct drm_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       pgoff_t page_offset;
+       unsigned long pfn;
+       int ret = 0;
+
+       /* We don't use vmf->pgoff since that has the fake offset */
+       page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
+               PAGE_SHIFT;
+
+       /* Now bind it into the GTT if needed */
+       mutex_lock(&dev->struct_mutex);
+       if (!obj_priv->gtt_space) {
+               ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment);
+               if (ret) {
+                       mutex_unlock(&dev->struct_mutex);
+                       return VM_FAULT_SIGBUS;
+               }
+               list_add(&obj_priv->list, &dev_priv->mm.inactive_list);
+       }
+
+       /* Need a new fence register? */
+       if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
+           obj_priv->tiling_mode != I915_TILING_NONE)
+               i915_gem_object_get_fence_reg(obj);
+
+       pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
+               page_offset;
+
+       /* Finally, remap it using the new GTT offset */
+       ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       switch (ret) {
+       case -ENOMEM:
+       case -EAGAIN:
+               return VM_FAULT_OOM;
+       case -EFAULT:
+       case -EBUSY:
+               DRM_ERROR("can't insert pfn??  fault or busy...\n");
+               return VM_FAULT_SIGBUS;
+       default:
+               return VM_FAULT_NOPAGE;
+       }
+}
+
+/**
+ * i915_gem_create_mmap_offset - create a fake mmap offset for an object
+ * @obj: obj in question
+ *
+ * GEM memory mapping works by handing back to userspace a fake mmap offset
+ * it can use in a subsequent mmap(2) call.  The DRM core code then looks
+ * up the object based on the offset and sets up the various memory mapping
+ * structures.
+ *
+ * This routine allocates and attaches a fake offset for @obj.
+ */
+static int
+i915_gem_create_mmap_offset(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_gem_mm *mm = dev->mm_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       struct drm_map_list *list;
+       struct drm_map *map;
+       int ret = 0;
+
+       /* Set the object up for mmap'ing */
+       list = &obj->map_list;
+       list->map = drm_calloc(1, sizeof(struct drm_map_list),
+                              DRM_MEM_DRIVER);
+       if (!list->map)
+               return -ENOMEM;
+
+       map = list->map;
+       map->type = _DRM_GEM;
+       map->size = obj->size;
+       map->handle = obj;
+
+       /* Get a DRM GEM mmap offset allocated... */
+       list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
+                                                   obj->size / PAGE_SIZE, 0, 0);
+       if (!list->file_offset_node) {
+               DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
+               ret = -ENOMEM;
+               goto out_free_list;
+       }
+
+       list->file_offset_node = drm_mm_get_block(list->file_offset_node,
+                                                 obj->size / PAGE_SIZE, 0);
+       if (!list->file_offset_node) {
+               ret = -ENOMEM;
+               goto out_free_list;
+       }
+
+       list->hash.key = list->file_offset_node->start;
+       if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+               DRM_ERROR("failed to add to map hash\n");
+               goto out_free_mm;
+       }
+
+       /* By now we should be all set, any drm_mmap request on the offset
+        * below will get to our mmap & fault handler */
+       obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT;
+
+       return 0;
+
+out_free_mm:
+       drm_mm_put_block(list->file_offset_node);
+out_free_list:
+       drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER);
+
+       return ret;
+}
+
+/**
+ * i915_gem_get_gtt_alignment - return required GTT alignment for an object
+ * @obj: object to check
+ *
+ * Return the required GTT alignment for an object, taking into account
+ * potential fence register mapping if needed.
+ */
+static uint32_t
+i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int start, i;
+
+       /*
+        * Minimum alignment is 4k (GTT page size), but might be greater
+        * if a fence register is needed for the object.
+        */
+       if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE)
+               return 4096;
+
+       /*
+        * Previous chips need to be aligned to the size of the smallest
+        * fence register that can contain the object.
+        */
+       if (IS_I9XX(dev))
+               start = 1024*1024;
+       else
+               start = 512*1024;
+
+       for (i = start; i < obj->size; i <<= 1)
+               ;
+
+       return i;
+}
+
+/**
+ * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
+ * @dev: DRM device
+ * @data: GTT mapping ioctl data
+ * @file_priv: GEM object info
+ *
+ * Simply returns the fake offset to userspace so it can mmap it.
+ * The mmap call will end up in drm_gem_mmap(), which will set things
+ * up so we can get faults in the handler above.
+ *
+ * The fault handler will take care of binding the object into the GTT
+ * (since it may have been evicted to make room for something), allocating
+ * a fence register, and mapping the appropriate aperture address into
+ * userspace.
+ */
+int
+i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *file_priv)
+{
+       struct drm_i915_gem_mmap_gtt *args = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+       int ret;
+
+       if (!(dev->driver->driver_features & DRIVER_GEM))
+               return -ENODEV;
+
+       obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+       if (obj == NULL)
+               return -EBADF;
+
+       mutex_lock(&dev->struct_mutex);
+
+       obj_priv = obj->driver_private;
+
+       if (!obj_priv->mmap_offset) {
+               ret = i915_gem_create_mmap_offset(obj);
+               if (ret)
+                       return ret;
+       }
+
+       args->offset = obj_priv->mmap_offset;
+
+       obj_priv->gtt_alignment = i915_gem_get_gtt_alignment(obj);
+
+       /* Make sure the alignment is correct for fence regs etc */
+       if (obj_priv->agp_mem &&
+           (obj_priv->gtt_offset & (obj_priv->gtt_alignment - 1))) {
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
+       }
+
+       /*
+        * Pull it into the GTT so that we have a page list (makes the
+        * initial fault faster and any subsequent flushing possible).
+        */
+       if (!obj_priv->agp_mem) {
+               ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment);
+               if (ret) {
+                       drm_gem_object_unreference(obj);
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
+               }
+               list_add(&obj_priv->list, &dev_priv->mm.inactive_list);
+       }
+
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
 static void
 i915_gem_object_free_page_list(struct drm_gem_object *obj)
 {
@@ -726,6 +980,7 @@ i915_gem_retire_request(struct drm_device *dev,
                 */
                if (obj_priv->last_rendering_seqno != request->seqno)
                        return;
+
 #if WATCH_LRU
                DRM_INFO("%s: retire %d moves to inactive list %p\n",
                         __func__, request->seqno, obj);
@@ -956,6 +1211,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       loff_t offset;
        int ret = 0;
 
 #if WATCH_BUF
@@ -991,6 +1247,14 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
 
        BUG_ON(obj_priv->active);
 
+       /* blow away mappings if mapped through GTT */
+       offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT;
+       if (dev->dev_mapping)
+               unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1);
+
+       if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
+               i915_gem_clear_fence_reg(obj);
+
        i915_gem_object_free_page_list(obj);
 
        if (obj_priv->gtt_space) {
@@ -1149,6 +1413,204 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj)
        return 0;
 }
 
+static void i965_write_fence_reg(struct drm_i915_fence_reg *reg)
+{
+       struct drm_gem_object *obj = reg->obj;
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int regnum = obj_priv->fence_reg;
+       uint64_t val;
+
+       val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) &
+                   0xfffff000) << 32;
+       val |= obj_priv->gtt_offset & 0xfffff000;
+       val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
+       if (obj_priv->tiling_mode == I915_TILING_Y)
+               val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+       val |= I965_FENCE_REG_VALID;
+
+       I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val);
+}
+
+static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
+{
+       struct drm_gem_object *obj = reg->obj;
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int regnum = obj_priv->fence_reg;
+       uint32_t val;
+       uint32_t pitch_val;
+
+       if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
+           (obj_priv->gtt_offset & (obj->size - 1))) {
+               WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__);
+               return;
+       }
+
+       if (obj_priv->tiling_mode == I915_TILING_Y && (IS_I945G(dev) ||
+                                                      IS_I945GM(dev) ||
+                                                      IS_G33(dev)))
+               pitch_val = (obj_priv->stride / 128) - 1;
+       else
+               pitch_val = (obj_priv->stride / 512) - 1;
+
+       val = obj_priv->gtt_offset;
+       if (obj_priv->tiling_mode == I915_TILING_Y)
+               val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+       val |= I915_FENCE_SIZE_BITS(obj->size);
+       val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+       val |= I830_FENCE_REG_VALID;
+
+       I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
+}
+
+static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
+{
+       struct drm_gem_object *obj = reg->obj;
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       int regnum = obj_priv->fence_reg;
+       uint32_t val;
+       uint32_t pitch_val;
+
+       if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
+           (obj_priv->gtt_offset & (obj->size - 1))) {
+               WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__);
+               return;
+       }
+
+       pitch_val = (obj_priv->stride / 128) - 1;
+
+       val = obj_priv->gtt_offset;
+       if (obj_priv->tiling_mode == I915_TILING_Y)
+               val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+       val |= I830_FENCE_SIZE_BITS(obj->size);
+       val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+       val |= I830_FENCE_REG_VALID;
+
+       I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
+
+}
+
+/**
+ * i915_gem_object_get_fence_reg - set up a fence reg for an object
+ * @obj: object to map through a fence reg
+ *
+ * When mapping objects through the GTT, userspace wants to be able to write
+ * to them without having to worry about swizzling if the object is tiled.
+ *
+ * This function walks the fence regs looking for a free one for @obj,
+ * stealing one if it can't find any.
+ *
+ * It then sets up the reg based on the object's properties: address, pitch
+ * and tiling format.
+ */
+static void
+i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       struct drm_i915_fence_reg *reg = NULL;
+       int i, ret;
+
+       switch (obj_priv->tiling_mode) {
+       case I915_TILING_NONE:
+               WARN(1, "allocating a fence for non-tiled object?\n");
+               break;
+       case I915_TILING_X:
+               WARN(obj_priv->stride & (512 - 1),
+                    "object is X tiled but has non-512B pitch\n");
+               break;
+       case I915_TILING_Y:
+               WARN(obj_priv->stride & (128 - 1),
+                    "object is Y tiled but has non-128B pitch\n");
+               break;
+       }
+
+       /* First try to find a free reg */
+       for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
+               reg = &dev_priv->fence_regs[i];
+               if (!reg->obj)
+                       break;
+       }
+
+       /* None available, try to steal one or wait for a user to finish */
+       if (i == dev_priv->num_fence_regs) {
+               struct drm_i915_gem_object *old_obj_priv = NULL;
+               loff_t offset;
+
+try_again:
+               /* Could try to use LRU here instead... */
+               for (i = dev_priv->fence_reg_start;
+                    i < dev_priv->num_fence_regs; i++) {
+                       reg = &dev_priv->fence_regs[i];
+                       old_obj_priv = reg->obj->driver_private;
+                       if (!old_obj_priv->pin_count)
+                               break;
+               }
+
+               /*
+                * Now things get ugly... we have to wait for one of the
+                * objects to finish before trying again.
+                */
+               if (i == dev_priv->num_fence_regs) {
+                       ret = i915_gem_object_wait_rendering(reg->obj);
+                       if (ret) {
+                               WARN(ret, "wait_rendering failed: %d\n", ret);
+                               return;
+                       }
+                       goto try_again;
+               }
+
+               /*
+                * Zap this virtual mapping so we can set up a fence again
+                * for this object next time we need it.
+                */
+               offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT;
+               if (dev->dev_mapping)
+                       unmap_mapping_range(dev->dev_mapping, offset,
+                                           reg->obj->size, 1);
+               old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
+       }
+
+       obj_priv->fence_reg = i;
+       reg->obj = obj;
+
+       if (IS_I965G(dev))
+               i965_write_fence_reg(reg);
+       else if (IS_I9XX(dev))
+               i915_write_fence_reg(reg);
+       else
+               i830_write_fence_reg(reg);
+}
+
+/**
+ * i915_gem_clear_fence_reg - clear out fence register info
+ * @obj: object to clear
+ *
+ * Zeroes out the fence register itself and clears out the associated
+ * data structures in dev_priv and obj_priv.
+ */
+static void
+i915_gem_clear_fence_reg(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+
+       if (IS_I965G(dev))
+               I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
+       else
+               I915_WRITE(FENCE_REG_830_0 + (obj_priv->fence_reg * 4), 0);
+
+       dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL;
+       obj_priv->fence_reg = I915_FENCE_REG_NONE;
+}
+
 /**
  * Finds free space in the GTT aperture and binds the object there.
  */
@@ -1307,7 +1769,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj)
  * This function returns when the move is complete, including waiting on
  * flushes to occur.
  */
-static int
+int
 i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
 {
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
@@ -2029,13 +2491,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 
                /* error other than GTT full, or we've already tried again */
                if (ret != -ENOMEM || pin_tries >= 1) {
-                       DRM_ERROR("Failed to pin buffers %d\n", ret);
+                       if (ret != -ERESTARTSYS)
+                               DRM_ERROR("Failed to pin buffers %d\n", ret);
                        goto err;
                }
 
                /* unpin all of our buffers */
                for (i = 0; i < pinned; i++)
                        i915_gem_object_unpin(object_list[i]);
+               pinned = 0;
 
                /* evict everyone we can from the aperture */
                ret = i915_gem_evict_everything(dev);
@@ -2149,13 +2613,12 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                          "back to user (%d)\n",
                           args->buffer_count, ret);
 err:
-       if (object_list != NULL) {
-               for (i = 0; i < pinned; i++)
-                       i915_gem_object_unpin(object_list[i]);
+       for (i = 0; i < pinned; i++)
+               i915_gem_object_unpin(object_list[i]);
+
+       for (i = 0; i < args->buffer_count; i++)
+               drm_gem_object_unreference(object_list[i]);
 
-               for (i = 0; i < args->buffer_count; i++)
-                       drm_gem_object_unreference(object_list[i]);
-       }
        mutex_unlock(&dev->struct_mutex);
 
 pre_mutex_err:
@@ -2178,7 +2641,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
        if (obj_priv->gtt_space == NULL) {
                ret = i915_gem_object_bind_to_gtt(obj, alignment);
                if (ret != 0) {
-                       DRM_ERROR("Failure to bind: %d", ret);
+                       if (ret != -ERESTARTSYS)
+                               DRM_ERROR("Failure to bind: %d", ret);
                        return ret;
                }
        }
@@ -2249,11 +2713,22 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        }
        obj_priv = obj->driver_private;
 
-       ret = i915_gem_object_pin(obj, args->alignment);
-       if (ret != 0) {
-               drm_gem_object_unreference(obj);
+       if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
+               DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
+                         args->handle);
                mutex_unlock(&dev->struct_mutex);
-               return ret;
+               return -EINVAL;
+       }
+
+       obj_priv->user_pin_count++;
+       obj_priv->pin_filp = file_priv;
+       if (obj_priv->user_pin_count == 1) {
+               ret = i915_gem_object_pin(obj, args->alignment);
+               if (ret != 0) {
+                       drm_gem_object_unreference(obj);
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
+               }
        }
 
        /* XXX - flush the CPU caches for pinned objects
@@ -2273,6 +2748,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_pin *args = data;
        struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
 
        mutex_lock(&dev->struct_mutex);
 
@@ -2284,7 +2760,19 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
                return -EBADF;
        }
 
-       i915_gem_object_unpin(obj);
+       obj_priv = obj->driver_private;
+       if (obj_priv->pin_filp != file_priv) {
+               DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
+                         args->handle);
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
+       }
+       obj_priv->user_pin_count--;
+       if (obj_priv->user_pin_count == 0) {
+               obj_priv->pin_filp = NULL;
+               i915_gem_object_unpin(obj);
+       }
 
        drm_gem_object_unreference(obj);
        mutex_unlock(&dev->struct_mutex);
@@ -2351,12 +2839,18 @@ int i915_gem_init_object(struct drm_gem_object *obj)
 
        obj->driver_private = obj_priv;
        obj_priv->obj = obj;
+       obj_priv->fence_reg = I915_FENCE_REG_NONE;
        INIT_LIST_HEAD(&obj_priv->list);
+
        return 0;
 }
 
 void i915_gem_free_object(struct drm_gem_object *obj)
 {
+       struct drm_device *dev = obj->dev;
+       struct drm_gem_mm *mm = dev->mm_private;
+       struct drm_map_list *list;
+       struct drm_map *map;
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
 
        while (obj_priv->pin_count > 0)
@@ -2364,6 +2858,20 @@ void i915_gem_free_object(struct drm_gem_object *obj)
 
        i915_gem_object_unbind(obj);
 
+       list = &obj->map_list;
+       drm_ht_remove_item(&mm->offset_hash, &list->hash);
+
+       if (list->file_offset_node) {
+               drm_mm_put_block(list->file_offset_node);
+               list->file_offset_node = NULL;
+       }
+
+       map = list->map;
+       if (map) {
+               drm_free(map, sizeof(*map), DRM_MEM_DRIVER);
+               list->map = NULL;
+       }
+
        drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
        drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
 }
@@ -2432,8 +2940,7 @@ i915_gem_idle(struct drm_device *dev)
         */
        i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT),
                       ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT));
-       seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU |
-                                       I915_GEM_DOMAIN_GTT));
+       seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU);
 
        if (seqno == 0) {
                mutex_unlock(&dev->struct_mutex);
@@ -2560,12 +3067,13 @@ i915_gem_init_hws(struct drm_device *dev)
        return 0;
 }
 
-static int
+int
 i915_gem_init_ringbuffer(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
        struct drm_i915_gem_object *obj_priv;
+       drm_i915_ring_buffer_t *ring = &dev_priv->ring;
        int ret;
        u32 head;
 
@@ -2587,24 +3095,24 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        }
 
        /* Set up the kernel mapping for the ring. */
-       dev_priv->ring.Size = obj->size;
-       dev_priv->ring.tail_mask = obj->size - 1;
+       ring->Size = obj->size;
+       ring->tail_mask = obj->size - 1;
 
-       dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset;
-       dev_priv->ring.map.size = obj->size;
-       dev_priv->ring.map.type = 0;
-       dev_priv->ring.map.flags = 0;
-       dev_priv->ring.map.mtrr = 0;
+       ring->map.offset = dev->agp->base + obj_priv->gtt_offset;
+       ring->map.size = obj->size;
+       ring->map.type = 0;
+       ring->map.flags = 0;
+       ring->map.mtrr = 0;
 
-       drm_core_ioremap_wc(&dev_priv->ring.map, dev);
-       if (dev_priv->ring.map.handle == NULL) {
+       drm_core_ioremap_wc(&ring->map, dev);
+       if (ring->map.handle == NULL) {
                DRM_ERROR("Failed to map ringbuffer.\n");
                memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
                drm_gem_object_unreference(obj);
                return -EINVAL;
        }
-       dev_priv->ring.ring_obj = obj;
-       dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+       ring->ring_obj = obj;
+       ring->virtual_start = ring->map.handle;
 
        /* Stop the ring if it's running. */
        I915_WRITE(PRB0_CTL, 0);
@@ -2652,12 +3160,20 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        }
 
        /* Update our cache of the ring state */
-       i915_kernel_lost_context(dev);
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               i915_kernel_lost_context(dev);
+       else {
+               ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
+               ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
+               ring->space = ring->head - (ring->tail + 8);
+               if (ring->space < 0)
+                       ring->space += ring->Size;
+       }
 
        return 0;
 }
 
-static void
+void
 i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -2695,6 +3211,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+
        if (dev_priv->mm.wedged) {
                DRM_ERROR("Reenabling wedged hardware, good luck\n");
                dev_priv->mm.wedged = 0;
@@ -2728,6 +3247,9 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+
        ret = i915_gem_idle(dev);
        drm_irq_uninstall(dev);
 
@@ -2758,5 +3280,13 @@ i915_gem_load(struct drm_device *dev)
                          i915_gem_retire_work_handler);
        dev_priv->mm.next_gem_seqno = 1;
 
+       /* Old X drivers will take 0-2 for front, back, depth buffers */
+       dev_priv->fence_reg_start = 3;
+
+       if (IS_I965G(dev))
+               dev_priv->num_fence_regs = 16;
+       else
+               dev_priv->num_fence_regs = 8;
+
        i915_gem_detect_bit_6_swizzle(dev);
 }
index e8d5abe1250ee14404bf8f9da972e34fd74ff6f0..4d1b9de0cd8b11ef176cb766a2f07fdda5c8b84f 100644 (file)
@@ -250,6 +250,39 @@ static int i915_interrupt_info(char *buf, char **start, off_t offset,
        return len - offset;
 }
 
+static int i915_hws_info(char *buf, char **start, off_t offset,
+                        int request, int *eof, void *data)
+{
+       struct drm_minor *minor = (struct drm_minor *) data;
+       struct drm_device *dev = minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int len = 0, i;
+       volatile u32 *hws;
+
+       if (offset > DRM_PROC_LIMIT) {
+               *eof = 1;
+               return 0;
+       }
+
+       hws = (volatile u32 *)dev_priv->hw_status_page;
+       if (hws == NULL) {
+               *eof = 1;
+               return 0;
+       }
+
+       *start = &buf[offset];
+       *eof = 0;
+       for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) {
+               DRM_PROC_PRINT("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                              i * 4,
+                              hws[i], hws[i + 1], hws[i + 2], hws[i + 3]);
+       }
+       if (len > request + offset)
+               return request;
+       *eof = 1;
+       return len - offset;
+}
+
 static struct drm_proc_list {
        /** file name */
        const char *name;
@@ -262,6 +295,7 @@ static struct drm_proc_list {
        {"i915_gem_request", i915_gem_request_info},
        {"i915_gem_seqno", i915_gem_seqno_info},
        {"i915_gem_interrupt", i915_interrupt_info},
+       {"i915_gem_hws", i915_hws_info},
 };
 
 #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
index a8cb69469c641ff28f4d57df20b51d0dd5772f7c..241f39b7f460251e0570c1e21ac9b3cccb53b8fc 100644 (file)
@@ -208,6 +208,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                }
        }
        obj_priv->tiling_mode = args->tiling_mode;
+       obj_priv->stride = args->stride;
 
        mutex_unlock(&dev->struct_mutex);
 
index 69b9a42da95ed720e85841c00ab7580fdff94830..0cadafbef411ba094d020d1323f66f136ba0d1bd 100644 (file)
@@ -30,6 +30,7 @@
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #define MAX_NOPID ((u32)~0)
 
 #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
                                    I915_INTERRUPT_ENABLE_VAR)
 
+#define I915_PIPE_VBLANK_STATUS        (PIPE_START_VBLANK_INTERRUPT_STATUS |\
+                                PIPE_VBLANK_INTERRUPT_STATUS)
+
+#define I915_PIPE_VBLANK_ENABLE        (PIPE_START_VBLANK_INTERRUPT_ENABLE |\
+                                PIPE_VBLANK_INTERRUPT_ENABLE)
+
+#define DRM_I915_VBLANK_PIPE_ALL       (DRM_I915_VBLANK_PIPE_A | \
+                                        DRM_I915_VBLANK_PIPE_B)
+
 void
 i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
@@ -168,6 +178,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_master_private *master_priv;
        u32 iir, new_iir;
        u32 pipea_stats, pipeb_stats;
        u32 vblank_status;
@@ -200,6 +211,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
                pipea_stats = I915_READ(PIPEASTAT);
                pipeb_stats = I915_READ(PIPEBSTAT);
+
                /*
                 * Clear the PIPE(A|B)STAT regs before the IIR
                 */
@@ -222,9 +234,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                I915_WRITE(IIR, iir);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
-               if (dev_priv->sarea_priv)
-                       dev_priv->sarea_priv->last_dispatch =
-                               READ_BREADCRUMB(dev_priv);
+               if (dev->primary->master) {
+                       master_priv = dev->primary->master->driver_priv;
+                       if (master_priv->sarea_priv)
+                               master_priv->sarea_priv->last_dispatch =
+                                       READ_BREADCRUMB(dev_priv);
+               }
 
                if (iir & I915_USER_INTERRUPT) {
                        dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
@@ -269,6 +284,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 static int i915_emit_irq(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        RING_LOCALS;
 
        i915_kernel_lost_context(dev);
@@ -278,8 +294,8 @@ static int i915_emit_irq(struct drm_device * dev)
        dev_priv->counter++;
        if (dev_priv->counter > 0x7FFFFFFFUL)
                dev_priv->counter = 1;
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
+       if (master_priv->sarea_priv)
+               master_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
        BEGIN_LP_RING(4);
        OUT_RING(MI_STORE_DWORD_INDEX);
@@ -317,21 +333,20 @@ void i915_user_irq_put(struct drm_device *dev)
 static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        int ret = 0;
 
        DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
                  READ_BREADCRUMB(dev_priv));
 
        if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
-               if (dev_priv->sarea_priv) {
-                       dev_priv->sarea_priv->last_dispatch =
-                               READ_BREADCRUMB(dev_priv);
-               }
+               if (master_priv->sarea_priv)
+                       master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
                return 0;
        }
 
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+       if (master_priv->sarea_priv)
+               master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
        i915_user_irq_get(dev);
        DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
@@ -343,10 +358,6 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
                          READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
        }
 
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_dispatch =
-                       READ_BREADCRUMB(dev_priv);
-
        return ret;
 }
 
@@ -427,6 +438,14 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
        spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
+void i915_enable_interrupt (struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       opregion_enable_asle(dev);
+       dev_priv->irq_enabled = 1;
+}
+
+
 /* Set the vblank monitor pipe
  */
 int i915_vblank_pipe_set(struct drm_device *dev, void *data,
@@ -487,6 +506,8 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+       atomic_set(&dev_priv->irq_received, 0);
+
        I915_WRITE(HWSTAM, 0xeffe);
        I915_WRITE(PIPEASTAT, 0);
        I915_WRITE(PIPEBSTAT, 0);
index 6126a60dc9cb19ceb335b9e335a04ecfe6d25559..96e271986d2a70197804c898e9d07a86dad85070 100644 (file)
@@ -46,7 +46,8 @@
 static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+       drm_i915_sarea_t *sarea_priv = master_priv->sarea_priv;
        struct drm_tex_region *list;
        unsigned shift, nr;
        unsigned start;
index 13ae731a33dba577b9a7326a9fe22daf8c1baf1c..ff012835a3863400cd54adfcbc392c4e59ea2d9a 100644 (file)
@@ -257,8 +257,8 @@ void opregion_enable_asle(struct drm_device *dev)
 
 static struct intel_opregion *system_opregion;
 
-int intel_opregion_video_event(struct notifier_block *nb, unsigned long val,
-                              void *data)
+static int intel_opregion_video_event(struct notifier_block *nb,
+                                     unsigned long val, void *data)
 {
        /* The only video events relevant to opregion are 0x80. These indicate
           either a docking event, lid switch or display switch request. In
index 9d24aaeb8a453d76e2d23e2223af3bfc527a74fa..47e6bafeb743d759416afaacc718bf3cae5c03db 100644 (file)
 #define   DISPLAY_PLANE_B           (1<<20)
 
 /*
- * Instruction and interrupt control regs
+ * Fence registers
  */
+#define FENCE_REG_830_0                        0x2000
+#define   I830_FENCE_START_MASK                0x07f80000
+#define   I830_FENCE_TILING_Y_SHIFT    12
+#define   I830_FENCE_SIZE_BITS(size)   ((get_order(size >> 19) - 1) << 8)
+#define   I830_FENCE_PITCH_SHIFT       4
+#define   I830_FENCE_REG_VALID         (1<<0)
+
+#define   I915_FENCE_START_MASK                0x0ff00000
+#define   I915_FENCE_SIZE_BITS(size)   ((get_order(size >> 20) - 1) << 8)
 
+#define FENCE_REG_965_0                        0x03000
+#define   I965_FENCE_PITCH_SHIFT       2
+#define   I965_FENCE_TILING_Y_SHIFT    1
+#define   I965_FENCE_REG_VALID         (1<<0)
+
+/*
+ * Instruction and interrupt control regs
+ */
 #define PRB0_TAIL      0x02030
 #define PRB0_HEAD      0x02034
 #define PRB0_START     0x02038
 #define   CM0_RC_OP_FLUSH_DISABLE (1<<0)
 #define GFX_FLSH_CNTL  0x02170 /* 915+ only */
 
+
 /*
  * Framebuffer compression (915+ only)
  */
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
new file mode 100644 (file)
index 0000000..4ca82a0
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright Â© 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_bios.h"
+
+
+static void *
+find_section(struct bdb_header *bdb, int section_id)
+{
+       u8 *base = (u8 *)bdb;
+       int index = 0;
+       u16 total, current_size;
+       u8 current_id;
+
+       /* skip to first section */
+       index += bdb->header_size;
+       total = bdb->bdb_size;
+
+       /* walk the sections looking for section_id */
+       while (index < total) {
+               current_id = *(base + index);
+               index++;
+               current_size = *((u16 *)(base + index));
+               index += 2;
+               if (current_id == section_id)
+                       return base + index;
+               index += current_size;
+       }
+
+       return NULL;
+}
+
+/* Try to find panel data */
+static void
+parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+       struct bdb_lvds_options *lvds_options;
+       struct bdb_lvds_lfp_data *lvds_lfp_data;
+       struct bdb_lvds_lfp_data_entry *entry;
+       struct lvds_dvo_timing *dvo_timing;
+       struct drm_display_mode *panel_fixed_mode;
+
+       /* Defaults if we can't find VBT info */
+       dev_priv->lvds_dither = 0;
+       dev_priv->lvds_vbt = 0;
+
+       lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
+       if (!lvds_options)
+               return;
+
+       dev_priv->lvds_dither = lvds_options->pixel_dither;
+       if (lvds_options->panel_type == 0xff)
+               return;
+
+       lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
+       if (!lvds_lfp_data)
+               return;
+
+       dev_priv->lvds_vbt = 1;
+
+       entry = &lvds_lfp_data->data[lvds_options->panel_type];
+       dvo_timing = &entry->dvo_timing;
+
+       panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode),
+                                     DRM_MEM_DRIVER);
+
+       panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
+               dvo_timing->hactive_lo;
+       panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
+               ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
+       panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
+               dvo_timing->hsync_pulse_width;
+       panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
+               ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
+
+       panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
+               dvo_timing->vactive_lo;
+       panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
+               dvo_timing->vsync_off;
+       panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
+               dvo_timing->vsync_pulse_width;
+       panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
+               ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
+       panel_fixed_mode->clock = dvo_timing->clock * 10;
+       panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
+
+       drm_mode_set_name(panel_fixed_mode);
+
+       dev_priv->vbt_mode = panel_fixed_mode;
+
+       DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
+       drm_mode_debug_printmodeline(panel_fixed_mode);
+
+       return;
+}
+
+static void
+parse_general_features(struct drm_i915_private *dev_priv,
+                      struct bdb_header *bdb)
+{
+       struct bdb_general_features *general;
+
+       /* Set sensible defaults in case we can't find the general block */
+       dev_priv->int_tv_support = 1;
+       dev_priv->int_crt_support = 1;
+
+       general = find_section(bdb, BDB_GENERAL_FEATURES);
+       if (general) {
+               dev_priv->int_tv_support = general->int_tv_support;
+               dev_priv->int_crt_support = general->int_crt_support;
+       }
+}
+
+/**
+ * intel_init_bios - initialize VBIOS settings & find VBT
+ * @dev: DRM device
+ *
+ * Loads the Video BIOS and checks that the VBT exists.  Sets scratch registers
+ * to appropriate values.
+ *
+ * VBT existence is a sanity check that is relied on by other i830_bios.c code.
+ * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
+ * feed an updated VBT back through that, compared to what we'll fetch using
+ * this method of groping around in the BIOS data.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+bool
+intel_init_bios(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct pci_dev *pdev = dev->pdev;
+       struct vbt_header *vbt = NULL;
+       struct bdb_header *bdb;
+       u8 __iomem *bios;
+       size_t size;
+       int i;
+
+       bios = pci_map_rom(pdev, &size);
+       if (!bios)
+               return -1;
+
+       /* Scour memory looking for the VBT signature */
+       for (i = 0; i + 4 < size; i++) {
+               if (!memcmp(bios + i, "$VBT", 4)) {
+                       vbt = (struct vbt_header *)(bios + i);
+                       break;
+               }
+       }
+
+       if (!vbt) {
+               DRM_ERROR("VBT signature missing\n");
+               pci_unmap_rom(pdev, bios);
+               return -1;
+       }
+
+       bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+
+       /* Grab useful general definitions */
+       parse_general_features(dev_priv, bdb);
+       parse_panel_data(dev_priv, bdb);
+
+       pci_unmap_rom(pdev, bios);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
new file mode 100644 (file)
index 0000000..5ea715a
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Copyright Â© 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+#ifndef _I830_BIOS_H_
+#define _I830_BIOS_H_
+
+#include "drmP.h"
+
+struct vbt_header {
+       u8 signature[20];               /**< Always starts with 'VBT$' */
+       u16 version;                    /**< decimal */
+       u16 header_size;                /**< in bytes */
+       u16 vbt_size;                   /**< in bytes */
+       u8 vbt_checksum;
+       u8 reserved0;
+       u32 bdb_offset;                 /**< from beginning of VBT */
+       u32 aim_offset[4];              /**< from beginning of VBT */
+} __attribute__((packed));
+
+struct bdb_header {
+       u8 signature[16];               /**< Always 'BIOS_DATA_BLOCK' */
+       u16 version;                    /**< decimal */
+       u16 header_size;                /**< in bytes */
+       u16 bdb_size;                   /**< in bytes */
+};
+
+/* strictly speaking, this is a "skip" block, but it has interesting info */
+struct vbios_data {
+       u8 type; /* 0 == desktop, 1 == mobile */
+       u8 relstage;
+       u8 chipset;
+       u8 lvds_present:1;
+       u8 tv_present:1;
+       u8 rsvd2:6; /* finish byte */
+       u8 rsvd3[4];
+       u8 signon[155];
+       u8 copyright[61];
+       u16 code_segment;
+       u8 dos_boot_mode;
+       u8 bandwidth_percent;
+       u8 rsvd4; /* popup memory size */
+       u8 resize_pci_bios;
+       u8 rsvd5; /* is crt already on ddc2 */
+} __attribute__((packed));
+
+/*
+ * There are several types of BIOS data blocks (BDBs), each block has
+ * an ID and size in the first 3 bytes (ID in first, size in next 2).
+ * Known types are listed below.
+ */
+#define BDB_GENERAL_FEATURES     1
+#define BDB_GENERAL_DEFINITIONS          2
+#define BDB_OLD_TOGGLE_LIST      3
+#define BDB_MODE_SUPPORT_LIST    4
+#define BDB_GENERIC_MODE_TABLE   5
+#define BDB_EXT_MMIO_REGS        6
+#define BDB_SWF_IO               7
+#define BDB_SWF_MMIO             8
+#define BDB_DOT_CLOCK_TABLE      9
+#define BDB_MODE_REMOVAL_TABLE  10
+#define BDB_CHILD_DEVICE_TABLE  11
+#define BDB_DRIVER_FEATURES     12
+#define BDB_DRIVER_PERSISTENCE  13
+#define BDB_EXT_TABLE_PTRS      14
+#define BDB_DOT_CLOCK_OVERRIDE  15
+#define BDB_DISPLAY_SELECT      16
+/* 17 rsvd */
+#define BDB_DRIVER_ROTATION     18
+#define BDB_DISPLAY_REMOVE      19
+#define BDB_OEM_CUSTOM          20
+#define BDB_EFP_LIST            21 /* workarounds for VGA hsync/vsync */
+#define BDB_SDVO_LVDS_OPTIONS   22
+#define BDB_SDVO_PANEL_DTDS     23
+#define BDB_SDVO_LVDS_PNP_IDS   24
+#define BDB_SDVO_LVDS_POWER_SEQ         25
+#define BDB_TV_OPTIONS          26
+#define BDB_LVDS_OPTIONS        40
+#define BDB_LVDS_LFP_DATA_PTRS  41
+#define BDB_LVDS_LFP_DATA       42
+#define BDB_LVDS_BACKLIGHT      43
+#define BDB_LVDS_POWER          44
+#define BDB_SKIP               254 /* VBIOS private block, ignore */
+
+struct bdb_general_features {
+        /* bits 1 */
+       u8 panel_fitting:2;
+       u8 flexaim:1;
+       u8 msg_enable:1;
+       u8 clear_screen:3;
+       u8 color_flip:1;
+
+        /* bits 2 */
+       u8 download_ext_vbt:1;
+       u8 enable_ssc:1;
+       u8 ssc_freq:1;
+       u8 enable_lfp_on_override:1;
+       u8 disable_ssc_ddt:1;
+       u8 rsvd8:3; /* finish byte */
+
+        /* bits 3 */
+       u8 disable_smooth_vision:1;
+       u8 single_dvi:1;
+       u8 rsvd9:6; /* finish byte */
+
+        /* bits 4 */
+       u8 legacy_monitor_detect;
+
+        /* bits 5 */
+       u8 int_crt_support:1;
+       u8 int_tv_support:1;
+       u8 rsvd11:6; /* finish byte */
+} __attribute__((packed));
+
+struct bdb_general_definitions {
+       /* DDC GPIO */
+       u8 crt_ddc_gmbus_pin;
+
+       /* DPMS bits */
+       u8 dpms_acpi:1;
+       u8 skip_boot_crt_detect:1;
+       u8 dpms_aim:1;
+       u8 rsvd1:5; /* finish byte */
+
+       /* boot device bits */
+       u8 boot_display[2];
+       u8 child_dev_size;
+
+       /* device info */
+       u8 tv_or_lvds_info[33];
+       u8 dev1[33];
+       u8 dev2[33];
+       u8 dev3[33];
+       u8 dev4[33];
+       /* may be another device block here on some platforms */
+};
+
+struct bdb_lvds_options {
+       u8 panel_type;
+       u8 rsvd1;
+       /* LVDS capabilities, stored in a dword */
+       u8 rsvd2:1;
+       u8 lvds_edid:1;
+       u8 pixel_dither:1;
+       u8 pfit_ratio_auto:1;
+       u8 pfit_gfx_mode_enhanced:1;
+       u8 pfit_text_mode_enhanced:1;
+       u8 pfit_mode:2;
+       u8 rsvd4;
+} __attribute__((packed));
+
+/* LFP pointer table contains entries to the struct below */
+struct bdb_lvds_lfp_data_ptr {
+       u16 fp_timing_offset; /* offsets are from start of bdb */
+       u8 fp_table_size;
+       u16 dvo_timing_offset;
+       u8 dvo_table_size;
+       u16 panel_pnp_id_offset;
+       u8 pnp_table_size;
+} __attribute__((packed));
+
+struct bdb_lvds_lfp_data_ptrs {
+       u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
+       struct bdb_lvds_lfp_data_ptr ptr[16];
+} __attribute__((packed));
+
+/* LFP data has 3 blocks per entry */
+struct lvds_fp_timing {
+       u16 x_res;
+       u16 y_res;
+       u32 lvds_reg;
+       u32 lvds_reg_val;
+       u32 pp_on_reg;
+       u32 pp_on_reg_val;
+       u32 pp_off_reg;
+       u32 pp_off_reg_val;
+       u32 pp_cycle_reg;
+       u32 pp_cycle_reg_val;
+       u32 pfit_reg;
+       u32 pfit_reg_val;
+       u16 terminator;
+} __attribute__((packed));
+
+struct lvds_dvo_timing {
+       u16 clock;              /**< In 10khz */
+       u8 hactive_lo;
+       u8 hblank_lo;
+       u8 hblank_hi:4;
+       u8 hactive_hi:4;
+       u8 vactive_lo;
+       u8 vblank_lo;
+       u8 vblank_hi:4;
+       u8 vactive_hi:4;
+       u8 hsync_off_lo;
+       u8 hsync_pulse_width;
+       u8 vsync_pulse_width:4;
+       u8 vsync_off:4;
+       u8 rsvd0:6;
+       u8 hsync_off_hi:2;
+       u8 h_image;
+       u8 v_image;
+       u8 max_hv;
+       u8 h_border;
+       u8 v_border;
+       u8 rsvd1:3;
+       u8 digital:2;
+       u8 vsync_positive:1;
+       u8 hsync_positive:1;
+       u8 rsvd2:1;
+} __attribute__((packed));
+
+struct lvds_pnp_id {
+       u16 mfg_name;
+       u16 product_code;
+       u32 serial;
+       u8 mfg_week;
+       u8 mfg_year;
+} __attribute__((packed));
+
+struct bdb_lvds_lfp_data_entry {
+       struct lvds_fp_timing fp_timing;
+       struct lvds_dvo_timing dvo_timing;
+       struct lvds_pnp_id pnp_id;
+} __attribute__((packed));
+
+struct bdb_lvds_lfp_data {
+       struct bdb_lvds_lfp_data_entry data[16];
+} __attribute__((packed));
+
+struct aimdb_header {
+       char signature[16];
+       char oem_device[20];
+       u16 aimdb_version;
+       u16 aimdb_header_size;
+       u16 aimdb_size;
+} __attribute__((packed));
+
+struct aimdb_block {
+       u8 aimdb_id;
+       u16 aimdb_size;
+} __attribute__((packed));
+
+struct vch_panel_data {
+       u16 fp_timing_offset;
+       u8 fp_timing_size;
+       u16 dvo_timing_offset;
+       u8 dvo_timing_size;
+       u16 text_fitting_offset;
+       u8 text_fitting_size;
+       u16 graphics_fitting_offset;
+       u8 graphics_fitting_size;
+} __attribute__((packed));
+
+struct vch_bdb_22 {
+       struct aimdb_block aimdb_block;
+       struct vch_panel_data panels[16];
+} __attribute__((packed));
+
+bool intel_init_bios(struct drm_device *dev);
+
+/*
+ * Driver<->VBIOS interaction occurs through scratch bits in
+ * GR18 & SWF*.
+ */
+
+/* GR18 bits are set on display switch and hotkey events */
+#define GR18_DRIVER_SWITCH_EN  (1<<7) /* 0: VBIOS control, 1: driver control */
+#define GR18_HOTKEY_MASK       0x78 /* See also SWF4 15:0 */
+#define   GR18_HK_NONE         (0x0<<3)
+#define   GR18_HK_LFP_STRETCH  (0x1<<3)
+#define   GR18_HK_TOGGLE_DISP  (0x2<<3)
+#define   GR18_HK_DISP_SWITCH  (0x4<<3) /* see SWF14 15:0 for what to enable */
+#define   GR18_HK_POPUP_DISABLED (0x6<<3)
+#define   GR18_HK_POPUP_ENABLED        (0x7<<3)
+#define   GR18_HK_PFIT         (0x8<<3)
+#define   GR18_HK_APM_CHANGE   (0xa<<3)
+#define   GR18_HK_MULTIPLE     (0xc<<3)
+#define GR18_USER_INT_EN       (1<<2)
+#define GR18_A0000_FLUSH_EN    (1<<1)
+#define GR18_SMM_EN            (1<<0)
+
+/* Set by driver, cleared by VBIOS */
+#define SWF00_YRES_SHIFT       16
+#define SWF00_XRES_SHIFT       0
+#define SWF00_RES_MASK         0xffff
+
+/* Set by VBIOS at boot time and driver at runtime */
+#define SWF01_TV2_FORMAT_SHIFT 8
+#define SWF01_TV1_FORMAT_SHIFT 0
+#define SWF01_TV_FORMAT_MASK   0xffff
+
+#define SWF10_VBIOS_BLC_I2C_EN (1<<29)
+#define SWF10_GTT_OVERRIDE_EN  (1<<28)
+#define SWF10_LFP_DPMS_OVR     (1<<27) /* override DPMS on display switch */
+#define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24)
+#define   SWF10_OLD_TOGGLE     0x0
+#define   SWF10_TOGGLE_LIST_1  0x1
+#define   SWF10_TOGGLE_LIST_2  0x2
+#define   SWF10_TOGGLE_LIST_3  0x3
+#define   SWF10_TOGGLE_LIST_4  0x4
+#define SWF10_PANNING_EN       (1<<23)
+#define SWF10_DRIVER_LOADED    (1<<22)
+#define SWF10_EXTENDED_DESKTOP (1<<21)
+#define SWF10_EXCLUSIVE_MODE   (1<<20)
+#define SWF10_OVERLAY_EN       (1<<19)
+#define SWF10_PLANEB_HOLDOFF   (1<<18)
+#define SWF10_PLANEA_HOLDOFF   (1<<17)
+#define SWF10_VGA_HOLDOFF      (1<<16)
+#define SWF10_ACTIVE_DISP_MASK 0xffff
+#define   SWF10_PIPEB_LFP2     (1<<15)
+#define   SWF10_PIPEB_EFP2     (1<<14)
+#define   SWF10_PIPEB_TV2      (1<<13)
+#define   SWF10_PIPEB_CRT2     (1<<12)
+#define   SWF10_PIPEB_LFP      (1<<11)
+#define   SWF10_PIPEB_EFP      (1<<10)
+#define   SWF10_PIPEB_TV       (1<<9)
+#define   SWF10_PIPEB_CRT      (1<<8)
+#define   SWF10_PIPEA_LFP2     (1<<7)
+#define   SWF10_PIPEA_EFP2     (1<<6)
+#define   SWF10_PIPEA_TV2      (1<<5)
+#define   SWF10_PIPEA_CRT2     (1<<4)
+#define   SWF10_PIPEA_LFP      (1<<3)
+#define   SWF10_PIPEA_EFP      (1<<2)
+#define   SWF10_PIPEA_TV       (1<<1)
+#define   SWF10_PIPEA_CRT      (1<<0)
+
+#define SWF11_MEMORY_SIZE_SHIFT        16
+#define SWF11_SV_TEST_EN       (1<<15)
+#define SWF11_IS_AGP           (1<<14)
+#define SWF11_DISPLAY_HOLDOFF  (1<<13)
+#define SWF11_DPMS_REDUCED     (1<<12)
+#define SWF11_IS_VBE_MODE      (1<<11)
+#define SWF11_PIPEB_ACCESS     (1<<10) /* 0 here means pipe a */
+#define SWF11_DPMS_MASK                0x07
+#define   SWF11_DPMS_OFF       (1<<2)
+#define   SWF11_DPMS_SUSPEND   (1<<1)
+#define   SWF11_DPMS_STANDBY   (1<<0)
+#define   SWF11_DPMS_ON                0
+
+#define SWF14_GFX_PFIT_EN      (1<<31)
+#define SWF14_TEXT_PFIT_EN     (1<<30)
+#define SWF14_LID_STATUS_CLOSED        (1<<29) /* 0 here means open */
+#define SWF14_POPUP_EN         (1<<28)
+#define SWF14_DISPLAY_HOLDOFF  (1<<27)
+#define SWF14_DISP_DETECT_EN   (1<<26)
+#define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */
+#define SWF14_DRIVER_STATUS    (1<<24)
+#define SWF14_OS_TYPE_WIN9X    (1<<23)
+#define SWF14_OS_TYPE_WINNT    (1<<22)
+/* 21:19 rsvd */
+#define SWF14_PM_TYPE_MASK     0x00070000
+#define   SWF14_PM_ACPI_VIDEO  (0x4 << 16)
+#define   SWF14_PM_ACPI                (0x3 << 16)
+#define   SWF14_PM_APM_12      (0x2 << 16)
+#define   SWF14_PM_APM_11      (0x1 << 16)
+#define SWF14_HK_REQUEST_MASK  0x0000ffff /* see GR18 6:3 for event type */
+          /* if GR18 indicates a display switch */
+#define   SWF14_DS_PIPEB_LFP2_EN (1<<15)
+#define   SWF14_DS_PIPEB_EFP2_EN (1<<14)
+#define   SWF14_DS_PIPEB_TV2_EN  (1<<13)
+#define   SWF14_DS_PIPEB_CRT2_EN (1<<12)
+#define   SWF14_DS_PIPEB_LFP_EN  (1<<11)
+#define   SWF14_DS_PIPEB_EFP_EN  (1<<10)
+#define   SWF14_DS_PIPEB_TV_EN   (1<<9)
+#define   SWF14_DS_PIPEB_CRT_EN  (1<<8)
+#define   SWF14_DS_PIPEA_LFP2_EN (1<<7)
+#define   SWF14_DS_PIPEA_EFP2_EN (1<<6)
+#define   SWF14_DS_PIPEA_TV2_EN  (1<<5)
+#define   SWF14_DS_PIPEA_CRT2_EN (1<<4)
+#define   SWF14_DS_PIPEA_LFP_EN  (1<<3)
+#define   SWF14_DS_PIPEA_EFP_EN  (1<<2)
+#define   SWF14_DS_PIPEA_TV_EN   (1<<1)
+#define   SWF14_DS_PIPEA_CRT_EN  (1<<0)
+          /* if GR18 indicates a panel fitting request */
+#define   SWF14_PFIT_EN                (1<<0) /* 0 means disable */
+          /* if GR18 indicates an APM change request */
+#define   SWF14_APM_HIBERNATE  0x4
+#define   SWF14_APM_SUSPEND    0x3
+#define   SWF14_APM_STANDBY    0x1
+#define   SWF14_APM_RESTORE    0x0
+
+#endif /* _I830_BIOS_H_ */
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
new file mode 100644 (file)
index 0000000..dcaed34
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 temp;
+
+       temp = I915_READ(ADPA);
+       temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
+       temp &= ~ADPA_DAC_ENABLE;
+
+       switch(mode) {
+       case DRM_MODE_DPMS_ON:
+               temp |= ADPA_DAC_ENABLE;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+               temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
+               break;
+       case DRM_MODE_DPMS_SUSPEND:
+               temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
+               break;
+       case DRM_MODE_DPMS_OFF:
+               temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
+               break;
+       }
+
+       I915_WRITE(ADPA, temp);
+}
+
+static int intel_crt_mode_valid(struct drm_connector *connector,
+                               struct drm_display_mode *mode)
+{
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (mode->clock > 400000 || mode->clock < 25000)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static bool intel_crt_mode_fixup(struct drm_encoder *encoder,
+                                struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void intel_crt_mode_set(struct drm_encoder *encoder,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+
+       struct drm_device *dev = encoder->dev;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int dpll_md_reg;
+       u32 adpa, dpll_md;
+
+       if (intel_crtc->pipe == 0)
+               dpll_md_reg = DPLL_A_MD;
+       else
+               dpll_md_reg = DPLL_B_MD;
+
+       /*
+        * Disable separate mode multiplier used when cloning SDVO to CRT
+        * XXX this needs to be adjusted when we really are cloning
+        */
+       if (IS_I965G(dev)) {
+               dpll_md = I915_READ(dpll_md_reg);
+               I915_WRITE(dpll_md_reg,
+                          dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
+       }
+
+       adpa = 0;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               adpa |= ADPA_HSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               adpa |= ADPA_VSYNC_ACTIVE_HIGH;
+
+       if (intel_crtc->pipe == 0)
+               adpa |= ADPA_PIPE_A_SELECT;
+       else
+               adpa |= ADPA_PIPE_B_SELECT;
+
+       I915_WRITE(ADPA, adpa);
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
+ *
+ * Not for i915G/i915GM
+ *
+ * \return true if CRT is connected.
+ * \return false if CRT is disconnected.
+ */
+static bool intel_crt_detect_hotplug(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 temp;
+
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       temp = I915_READ(PORT_HOTPLUG_EN);
+
+       I915_WRITE(PORT_HOTPLUG_EN,
+                  temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
+
+       do {
+               if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT))
+                       break;
+               msleep(1);
+       } while (time_after(timeout, jiffies));
+
+       if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
+           CRT_HOTPLUG_MONITOR_COLOR)
+               return true;
+
+       return false;
+}
+
+static bool intel_crt_detect_ddc(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       /* CRT should always be at 0, but check anyway */
+       if (intel_output->type != INTEL_OUTPUT_ANALOG)
+               return false;
+
+       return intel_ddc_probe(intel_output);
+}
+
+static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+
+       if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
+               if (intel_crt_detect_hotplug(connector))
+                       return connector_status_connected;
+               else
+                       return connector_status_disconnected;
+       }
+
+       if (intel_crt_detect_ddc(connector))
+               return connector_status_connected;
+
+       /* TODO use load detect */
+       return connector_status_unknown;
+}
+
+static void intel_crt_destroy(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       intel_i2c_destroy(intel_output->ddc_bus);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+static int intel_crt_get_modes(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       return intel_ddc_get_modes(intel_output);
+}
+
+static int intel_crt_set_property(struct drm_connector *connector,
+                                 struct drm_property *property,
+                                 uint64_t value)
+{
+       struct drm_device *dev = connector->dev;
+
+       if (property == dev->mode_config.dpms_property && connector->encoder)
+               intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf));
+
+       return 0;
+}
+
+/*
+ * Routines for controlling stuff on the analog port
+ */
+
+static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
+       .dpms = intel_crt_dpms,
+       .mode_fixup = intel_crt_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .commit = intel_encoder_commit,
+       .mode_set = intel_crt_mode_set,
+};
+
+static const struct drm_connector_funcs intel_crt_connector_funcs = {
+       .detect = intel_crt_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = intel_crt_destroy,
+       .set_property = intel_crt_set_property,
+};
+
+static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
+       .mode_valid = intel_crt_mode_valid,
+       .get_modes = intel_crt_get_modes,
+       .best_encoder = intel_best_encoder,
+};
+
+static void intel_crt_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_crt_enc_funcs = {
+       .destroy = intel_crt_enc_destroy,
+};
+
+void intel_crt_init(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+
+       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output)
+               return;
+
+       connector = &intel_output->base;
+       drm_connector_init(dev, &intel_output->base,
+                          &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs,
+                        DRM_MODE_ENCODER_DAC);
+
+       drm_mode_connector_attach_encoder(&intel_output->base,
+                                         &intel_output->enc);
+
+       /* Set up the DDC bus. */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
+       if (!intel_output->ddc_bus) {
+               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
+                          "failed.\n");
+               return;
+       }
+
+       intel_output->type = INTEL_OUTPUT_ANALOG;
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs);
+       drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
+
+       drm_sysfs_connector_add(connector);
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
new file mode 100644 (file)
index 0000000..e5c1c80
--- /dev/null
@@ -0,0 +1,1618 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+#include "drm_crtc_helper.h"
+
+bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
+
+typedef struct {
+    /* given values */
+    int n;
+    int m1, m2;
+    int p1, p2;
+    /* derived values */
+    int        dot;
+    int        vco;
+    int        m;
+    int        p;
+} intel_clock_t;
+
+typedef struct {
+    int        min, max;
+} intel_range_t;
+
+typedef struct {
+    int        dot_limit;
+    int        p2_slow, p2_fast;
+} intel_p2_t;
+
+#define INTEL_P2_NUM                 2
+
+typedef struct {
+    intel_range_t   dot, vco, n, m, m1, m2, p, p1;
+    intel_p2_t     p2;
+} intel_limit_t;
+
+#define I8XX_DOT_MIN             25000
+#define I8XX_DOT_MAX            350000
+#define I8XX_VCO_MIN            930000
+#define I8XX_VCO_MAX           1400000
+#define I8XX_N_MIN                   3
+#define I8XX_N_MAX                  16
+#define I8XX_M_MIN                  96
+#define I8XX_M_MAX                 140
+#define I8XX_M1_MIN                 18
+#define I8XX_M1_MAX                 26
+#define I8XX_M2_MIN                  6
+#define I8XX_M2_MAX                 16
+#define I8XX_P_MIN                   4
+#define I8XX_P_MAX                 128
+#define I8XX_P1_MIN                  2
+#define I8XX_P1_MAX                 33
+#define I8XX_P1_LVDS_MIN             1
+#define I8XX_P1_LVDS_MAX             6
+#define I8XX_P2_SLOW                 4
+#define I8XX_P2_FAST                 2
+#define I8XX_P2_LVDS_SLOW            14
+#define I8XX_P2_LVDS_FAST            14 /* No fast option */
+#define I8XX_P2_SLOW_LIMIT      165000
+
+#define I9XX_DOT_MIN             20000
+#define I9XX_DOT_MAX            400000
+#define I9XX_VCO_MIN           1400000
+#define I9XX_VCO_MAX           2800000
+#define I9XX_N_MIN                   3
+#define I9XX_N_MAX                   8
+#define I9XX_M_MIN                  70
+#define I9XX_M_MAX                 120
+#define I9XX_M1_MIN                 10
+#define I9XX_M1_MAX                 20
+#define I9XX_M2_MIN                  5
+#define I9XX_M2_MAX                  9
+#define I9XX_P_SDVO_DAC_MIN          5
+#define I9XX_P_SDVO_DAC_MAX         80
+#define I9XX_P_LVDS_MIN                      7
+#define I9XX_P_LVDS_MAX                     98
+#define I9XX_P1_MIN                  1
+#define I9XX_P1_MAX                  8
+#define I9XX_P2_SDVO_DAC_SLOW               10
+#define I9XX_P2_SDVO_DAC_FAST                5
+#define I9XX_P2_SDVO_DAC_SLOW_LIMIT     200000
+#define I9XX_P2_LVDS_SLOW                   14
+#define I9XX_P2_LVDS_FAST                    7
+#define I9XX_P2_LVDS_SLOW_LIMIT                 112000
+
+#define INTEL_LIMIT_I8XX_DVO_DAC    0
+#define INTEL_LIMIT_I8XX_LVDS      1
+#define INTEL_LIMIT_I9XX_SDVO_DAC   2
+#define INTEL_LIMIT_I9XX_LVDS      3
+
+static const intel_limit_t intel_limits[] = {
+    { /* INTEL_LIMIT_I8XX_DVO_DAC */
+        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
+        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
+        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
+        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
+        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
+        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
+        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
+        .p1  = { .min = I8XX_P1_MIN,           .max = I8XX_P1_MAX },
+       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
+                .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
+    },
+    { /* INTEL_LIMIT_I8XX_LVDS */
+        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
+        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
+        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
+        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
+        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
+        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
+        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
+        .p1  = { .min = I8XX_P1_LVDS_MIN,      .max = I8XX_P1_LVDS_MAX },
+       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
+                .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
+    },
+    { /* INTEL_LIMIT_I9XX_SDVO_DAC */
+        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
+        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
+        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
+        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
+        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
+        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
+        .p   = { .min = I9XX_P_SDVO_DAC_MIN,   .max = I9XX_P_SDVO_DAC_MAX },
+        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
+       .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
+                .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+    },
+    { /* INTEL_LIMIT_I9XX_LVDS */
+        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
+        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
+        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
+        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
+        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
+        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
+        .p   = { .min = I9XX_P_LVDS_MIN,       .max = I9XX_P_LVDS_MAX },
+        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
+       /* The single-channel range is 25-112Mhz, and dual-channel
+        * is 80-224Mhz.  Prefer single channel as much as possible.
+        */
+       .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
+                .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
+    },
+};
+
+static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       const intel_limit_t *limit;
+
+       if (IS_I9XX(dev)) {
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+                       limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
+               else
+                       limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+       } else {
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+                       limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
+               else
+                       limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC];
+       }
+       return limit;
+}
+
+/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
+
+static void i8xx_clock(int refclk, intel_clock_t *clock)
+{
+       clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
+       clock->p = clock->p1 * clock->p2;
+       clock->vco = refclk * clock->m / (clock->n + 2);
+       clock->dot = clock->vco / clock->p;
+}
+
+/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
+
+static void i9xx_clock(int refclk, intel_clock_t *clock)
+{
+       clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
+       clock->p = clock->p1 * clock->p2;
+       clock->vco = refclk * clock->m / (clock->n + 2);
+       clock->dot = clock->vco / clock->p;
+}
+
+static void intel_clock(struct drm_device *dev, int refclk,
+                       intel_clock_t *clock)
+{
+       if (IS_I9XX(dev))
+               i9xx_clock (refclk, clock);
+       else
+               i8xx_clock (refclk, clock);
+}
+
+/**
+ * Returns whether any output on the specified pipe is of the specified type
+ */
+bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+{
+    struct drm_device *dev = crtc->dev;
+    struct drm_mode_config *mode_config = &dev->mode_config;
+    struct drm_connector *l_entry;
+
+    list_for_each_entry(l_entry, &mode_config->connector_list, head) {
+           if (l_entry->encoder &&
+               l_entry->encoder->crtc == crtc) {
+                   struct intel_output *intel_output = to_intel_output(l_entry);
+                   if (intel_output->type == type)
+                           return true;
+           }
+    }
+    return false;
+}
+
+#define INTELPllInvalid(s)   { /* ErrorF (s) */; return false; }
+/**
+ * Returns whether the given set of divisors are valid for a given refclk with
+ * the given connectors.
+ */
+
+static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
+{
+       const intel_limit_t *limit = intel_limit (crtc);
+
+       if (clock->p1  < limit->p1.min  || limit->p1.max  < clock->p1)
+               INTELPllInvalid ("p1 out of range\n");
+       if (clock->p   < limit->p.min   || limit->p.max   < clock->p)
+               INTELPllInvalid ("p out of range\n");
+       if (clock->m2  < limit->m2.min  || limit->m2.max  < clock->m2)
+               INTELPllInvalid ("m2 out of range\n");
+       if (clock->m1  < limit->m1.min  || limit->m1.max  < clock->m1)
+               INTELPllInvalid ("m1 out of range\n");
+       if (clock->m1 <= clock->m2)
+               INTELPllInvalid ("m1 <= m2\n");
+       if (clock->m   < limit->m.min   || limit->m.max   < clock->m)
+               INTELPllInvalid ("m out of range\n");
+       if (clock->n   < limit->n.min   || limit->n.max   < clock->n)
+               INTELPllInvalid ("n out of range\n");
+       if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
+               INTELPllInvalid ("vco out of range\n");
+       /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
+        * connector, etc., rather than just a single range.
+        */
+       if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
+               INTELPllInvalid ("dot out of range\n");
+
+       return true;
+}
+
+/**
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
+                               int refclk, intel_clock_t *best_clock)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       intel_clock_t clock;
+       const intel_limit_t *limit = intel_limit(crtc);
+       int err = target;
+
+       if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+           (I915_READ(LVDS) & LVDS_PORT_EN) != 0) {
+               /*
+                * For LVDS, if the panel is on, just rely on its current
+                * settings for dual-channel.  We haven't figured out how to
+                * reliably set up different single/dual channel state, if we
+                * even can.
+                */
+               if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
+                   LVDS_CLKB_POWER_UP)
+                       clock.p2 = limit->p2.p2_fast;
+               else
+                       clock.p2 = limit->p2.p2_slow;
+       } else {
+               if (target < limit->p2.dot_limit)
+                       clock.p2 = limit->p2.p2_slow;
+               else
+                       clock.p2 = limit->p2.p2_fast;
+       }
+
+       memset (best_clock, 0, sizeof (*best_clock));
+
+       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
+               for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 &&
+                            clock.m2 <= limit->m2.max; clock.m2++) {
+                       for (clock.n = limit->n.min; clock.n <= limit->n.max;
+                            clock.n++) {
+                               for (clock.p1 = limit->p1.min;
+                                    clock.p1 <= limit->p1.max; clock.p1++) {
+                                       int this_err;
+
+                                       intel_clock(dev, refclk, &clock);
+
+                                       if (!intel_PLL_is_valid(crtc, &clock))
+                                               continue;
+
+                                       this_err = abs(clock.dot - target);
+                                       if (this_err < err) {
+                                               *best_clock = clock;
+                                               err = this_err;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return (err != target);
+}
+
+void
+intel_wait_for_vblank(struct drm_device *dev)
+{
+       /* Wait for 20ms, i.e. one cycle at 50hz. */
+       udelay(20000);
+}
+
+static void
+intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
+                   struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_framebuffer *intel_fb;
+       struct drm_i915_gem_object *obj_priv;
+       struct drm_gem_object *obj;
+       int pipe = intel_crtc->pipe;
+       unsigned long Start, Offset;
+       int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR);
+       int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
+       int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
+       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+       u32 dspcntr, alignment;
+
+       /* no fb bound */
+       if (!crtc->fb) {
+               DRM_DEBUG("No FB bound\n");
+               return;
+       }
+
+       intel_fb = to_intel_framebuffer(crtc->fb);
+       obj = intel_fb->obj;
+       obj_priv = obj->driver_private;
+
+       switch (obj_priv->tiling_mode) {
+       case I915_TILING_NONE:
+               alignment = 64 * 1024;
+               break;
+       case I915_TILING_X:
+               if (IS_I9XX(dev))
+                       alignment = 1024 * 1024;
+               else
+                       alignment = 512 * 1024;
+               break;
+       case I915_TILING_Y:
+               /* FIXME: Is this true? */
+               DRM_ERROR("Y tiled not allowed for scan out buffers\n");
+               return;
+       default:
+               BUG();
+       }
+
+       if (i915_gem_object_pin(intel_fb->obj, alignment))
+               return;
+
+       i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
+
+       Start = obj_priv->gtt_offset;
+       Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
+
+       I915_WRITE(dspstride, crtc->fb->pitch);
+
+       dspcntr = I915_READ(dspcntr_reg);
+       switch (crtc->fb->bits_per_pixel) {
+       case 8:
+               dspcntr |= DISPPLANE_8BPP;
+               break;
+       case 16:
+               if (crtc->fb->depth == 15)
+                       dspcntr |= DISPPLANE_15_16BPP;
+               else
+                       dspcntr |= DISPPLANE_16BPP;
+               break;
+       case 24:
+       case 32:
+               dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+               break;
+       default:
+               DRM_ERROR("Unknown color depth\n");
+               return;
+       }
+       I915_WRITE(dspcntr_reg, dspcntr);
+
+       DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+       if (IS_I965G(dev)) {
+               I915_WRITE(dspbase, Offset);
+               I915_READ(dspbase);
+               I915_WRITE(dspsurf, Start);
+               I915_READ(dspsurf);
+       } else {
+               I915_WRITE(dspbase, Start + Offset);
+               I915_READ(dspbase);
+       }
+
+       intel_wait_for_vblank(dev);
+
+       if (old_fb) {
+               intel_fb = to_intel_framebuffer(old_fb);
+               i915_gem_object_unpin(intel_fb->obj);
+       }
+
+       if (!dev->primary->master)
+               return;
+
+       master_priv = dev->primary->master->driver_priv;
+       if (!master_priv->sarea_priv)
+               return;
+
+       switch (pipe) {
+       case 0:
+               master_priv->sarea_priv->pipeA_x = x;
+               master_priv->sarea_priv->pipeA_y = y;
+               break;
+       case 1:
+               master_priv->sarea_priv->pipeB_x = x;
+               master_priv->sarea_priv->pipeB_y = y;
+               break;
+       default:
+               DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
+               break;
+       }
+}
+
+
+
+/**
+ * Sets the power management mode of the pipe and plane.
+ *
+ * This code should probably grow support for turning the cursor off and back
+ * on appropriately at the same time as we're turning the pipe off/on.
+ */
+static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_master_private *master_priv;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+       int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR;
+       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       u32 temp;
+       bool enabled;
+
+       /* XXX: When our outputs are all unaware of DPMS modes other than off
+        * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+        */
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+               /* Enable the DPLL */
+               temp = I915_READ(dpll_reg);
+               if ((temp & DPLL_VCO_ENABLE) == 0) {
+                       I915_WRITE(dpll_reg, temp);
+                       I915_READ(dpll_reg);
+                       /* Wait for the clocks to stabilize. */
+                       udelay(150);
+                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
+                       I915_READ(dpll_reg);
+                       /* Wait for the clocks to stabilize. */
+                       udelay(150);
+                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
+                       I915_READ(dpll_reg);
+                       /* Wait for the clocks to stabilize. */
+                       udelay(150);
+               }
+
+               /* Enable the pipe */
+               temp = I915_READ(pipeconf_reg);
+               if ((temp & PIPEACONF_ENABLE) == 0)
+                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+
+               /* Enable the plane */
+               temp = I915_READ(dspcntr_reg);
+               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+                       /* Flush the plane changes */
+                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+               }
+
+               intel_crtc_load_lut(crtc);
+
+               /* Give the overlay scaler a chance to enable if it's on this pipe */
+               //intel_crtc_dpms_video(crtc, true); TODO
+       break;
+       case DRM_MODE_DPMS_OFF:
+               /* Give the overlay scaler a chance to disable if it's on this pipe */
+               //intel_crtc_dpms_video(crtc, FALSE); TODO
+
+               /* Disable the VGA plane that we never use */
+               I915_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+
+               /* Disable display plane */
+               temp = I915_READ(dspcntr_reg);
+               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+                       /* Flush the plane changes */
+                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+                       I915_READ(dspbase_reg);
+               }
+
+               if (!IS_I9XX(dev)) {
+                       /* Wait for vblank for the disable to take effect */
+                       intel_wait_for_vblank(dev);
+               }
+
+               /* Next, disable display pipes */
+               temp = I915_READ(pipeconf_reg);
+               if ((temp & PIPEACONF_ENABLE) != 0) {
+                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+                       I915_READ(pipeconf_reg);
+               }
+
+               /* Wait for vblank for the disable to take effect. */
+               intel_wait_for_vblank(dev);
+
+               temp = I915_READ(dpll_reg);
+               if ((temp & DPLL_VCO_ENABLE) != 0) {
+                       I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
+                       I915_READ(dpll_reg);
+               }
+
+               /* Wait for the clocks to turn off. */
+               udelay(150);
+               break;
+       }
+
+       if (!dev->primary->master)
+               return;
+
+       master_priv = dev->primary->master->driver_priv;
+       if (!master_priv->sarea_priv)
+               return;
+
+       enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF;
+
+       switch (pipe) {
+       case 0:
+               master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0;
+               master_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0;
+               break;
+       case 1:
+               master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0;
+               master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0;
+               break;
+       default:
+               DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
+               break;
+       }
+
+       intel_crtc->dpms_mode = mode;
+}
+
+static void intel_crtc_prepare (struct drm_crtc *crtc)
+{
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void intel_crtc_commit (struct drm_crtc *crtc)
+{
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+void intel_encoder_prepare (struct drm_encoder *encoder)
+{
+       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+       /* lvds has its own version of prepare see intel_lvds_prepare */
+       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+void intel_encoder_commit (struct drm_encoder *encoder)
+{
+       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+       /* lvds has its own version of commit see intel_lvds_commit */
+       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+
+/** Returns the core display clock speed for i830 - i945 */
+static int intel_get_core_clock_speed(struct drm_device *dev)
+{
+
+       /* Core clock values taken from the published datasheets.
+        * The 830 may go up to 166 Mhz, which we should check.
+        */
+       if (IS_I945G(dev))
+               return 400000;
+       else if (IS_I915G(dev))
+               return 333000;
+       else if (IS_I945GM(dev) || IS_845G(dev))
+               return 200000;
+       else if (IS_I915GM(dev)) {
+               u16 gcfgc = 0;
+
+               pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
+
+               if (gcfgc & GC_LOW_FREQUENCY_ENABLE)
+                       return 133000;
+               else {
+                       switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
+                       case GC_DISPLAY_CLOCK_333_MHZ:
+                               return 333000;
+                       default:
+                       case GC_DISPLAY_CLOCK_190_200_MHZ:
+                               return 190000;
+                       }
+               }
+       } else if (IS_I865G(dev))
+               return 266000;
+       else if (IS_I855(dev)) {
+               u16 hpllcc = 0;
+               /* Assume that the hardware is in the high speed state.  This
+                * should be the default.
+                */
+               switch (hpllcc & GC_CLOCK_CONTROL_MASK) {
+               case GC_CLOCK_133_200:
+               case GC_CLOCK_100_200:
+                       return 200000;
+               case GC_CLOCK_166_250:
+                       return 250000;
+               case GC_CLOCK_100_133:
+                       return 133000;
+               }
+       } else /* 852, 830 */
+               return 133000;
+
+       return 0; /* Silence gcc warning */
+}
+
+
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int intel_panel_fitter_pipe (struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32  pfit_control;
+
+       /* i830 doesn't have a panel fitter */
+       if (IS_I830(dev))
+               return -1;
+
+       pfit_control = I915_READ(PFIT_CONTROL);
+
+       /* See if the panel fitter is in use */
+       if ((pfit_control & PFIT_ENABLE) == 0)
+               return -1;
+
+       /* 965 can place panel fitter on either pipe */
+       if (IS_I965G(dev))
+               return (pfit_control >> 29) & 0x3;
+
+       /* older chips can only use pipe 1 */
+       return 1;
+}
+
+static void intel_crtc_mode_set(struct drm_crtc *crtc,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode,
+                               int x, int y,
+                               struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int fp_reg = (pipe == 0) ? FPA0 : FPB0;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
+       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
+       int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
+       int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
+       int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
+       int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
+       int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
+       int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
+       int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
+       int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+       int refclk;
+       intel_clock_t clock;
+       u32 dpll = 0, fp = 0, dspcntr, pipeconf;
+       bool ok, is_sdvo = false, is_dvo = false;
+       bool is_crt = false, is_lvds = false, is_tv = false;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_connector *connector;
+
+       drm_vblank_pre_modeset(dev, pipe);
+
+       list_for_each_entry(connector, &mode_config->connector_list, head) {
+               struct intel_output *intel_output = to_intel_output(connector);
+
+               if (!connector->encoder || connector->encoder->crtc != crtc)
+                       continue;
+
+               switch (intel_output->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+                       is_sdvo = true;
+                       break;
+               case INTEL_OUTPUT_DVO:
+                       is_dvo = true;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = true;
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       is_crt = true;
+                       break;
+               }
+       }
+
+       if (IS_I9XX(dev)) {
+               refclk = 96000;
+       } else {
+               refclk = 48000;
+       }
+
+       ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return;
+       }
+
+       fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+
+       dpll = DPLL_VGA_MODE_DIS;
+       if (IS_I9XX(dev)) {
+               if (is_lvds)
+                       dpll |= DPLLB_MODE_LVDS;
+               else
+                       dpll |= DPLLB_MODE_DAC_SERIAL;
+               if (is_sdvo) {
+                       dpll |= DPLL_DVO_HIGH_SPEED;
+                       if (IS_I945G(dev) || IS_I945GM(dev)) {
+                               int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+                               dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+                       }
+               }
+
+               /* compute bitmask from p1 value */
+               dpll |= (1 << (clock.p1 - 1)) << 16;
+               switch (clock.p2) {
+               case 5:
+                       dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+                       break;
+               case 7:
+                       dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+                       break;
+               case 10:
+                       dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+                       break;
+               case 14:
+                       dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+                       break;
+               }
+               if (IS_I965G(dev))
+                       dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
+       } else {
+               if (is_lvds) {
+                       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+               } else {
+                       if (clock.p1 == 2)
+                               dpll |= PLL_P1_DIVIDE_BY_TWO;
+                       else
+                               dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+                       if (clock.p2 == 4)
+                               dpll |= PLL_P2_DIVIDE_BY_4;
+               }
+       }
+
+       if (is_tv) {
+               /* XXX: just matching BIOS for now */
+/*     dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       }
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
+
+       /* setup pipeconf */
+       pipeconf = I915_READ(pipeconf_reg);
+
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       if (pipe == 0)
+               dspcntr |= DISPPLANE_SEL_PIPE_A;
+       else
+               dspcntr |= DISPPLANE_SEL_PIPE_B;
+
+       if (pipe == 0 && !IS_I965G(dev)) {
+               /* Enable pixel doubling when the dot clock is > 90% of the (display)
+                * core speed.
+                *
+                * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
+                * pipe == 0 check?
+                */
+               if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10)
+                       pipeconf |= PIPEACONF_DOUBLE_WIDE;
+               else
+                       pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+       }
+
+       dspcntr |= DISPLAY_PLANE_ENABLE;
+       pipeconf |= PIPEACONF_ENABLE;
+       dpll |= DPLL_VCO_ENABLE;
+
+
+       /* Disable the panel fitter if it was on our pipe */
+       if (intel_panel_fitter_pipe(dev) == pipe)
+               I915_WRITE(PFIT_CONTROL, 0);
+
+       DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       drm_mode_debug_printmodeline(mode);
+
+
+       if (dpll & DPLL_VCO_ENABLE) {
+               I915_WRITE(fp_reg, fp);
+               I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
+               I915_READ(dpll_reg);
+               udelay(150);
+       }
+
+       /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+        * This is an exception to the general rule that mode_set doesn't turn
+        * things on.
+        */
+       if (is_lvds) {
+               u32 lvds = I915_READ(LVDS);
+
+               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
+               /* Set the B0-B3 data pairs corresponding to whether we're going to
+                * set the DPLLs for dual-channel mode or not.
+                */
+               if (clock.p2 == 7)
+                       lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+               else
+                       lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+
+               /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+                * appropriately here, but we need to look more thoroughly into how
+                * panels behave in the two modes.
+                */
+
+               I915_WRITE(LVDS, lvds);
+               I915_READ(LVDS);
+       }
+
+       I915_WRITE(fp_reg, fp);
+       I915_WRITE(dpll_reg, dpll);
+       I915_READ(dpll_reg);
+       /* Wait for the clocks to stabilize. */
+       udelay(150);
+
+       if (IS_I965G(dev)) {
+               int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+               I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
+                          ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
+       } else {
+               /* write it again -- the BIOS does, after all */
+               I915_WRITE(dpll_reg, dpll);
+       }
+       I915_READ(dpll_reg);
+       /* Wait for the clocks to stabilize. */
+       udelay(150);
+
+       I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+                  ((adjusted_mode->crtc_htotal - 1) << 16));
+       I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
+       I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
+       I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+       I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+       I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
+       /* pipesrc and dspsize control the size that is scaled from, which should
+        * always be the user's requested size.
+        */
+       I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
+       I915_WRITE(dsppos_reg, 0);
+       I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+       I915_WRITE(pipeconf_reg, pipeconf);
+       I915_READ(pipeconf_reg);
+
+       intel_wait_for_vblank(dev);
+
+       I915_WRITE(dspcntr_reg, dspcntr);
+
+       /* Flush the plane changes */
+       intel_pipe_set_base(crtc, x, y, old_fb);
+
+       drm_vblank_post_modeset(dev, pipe);
+}
+
+/** Loads the palette/gamma unit for the CRTC with the prepared values */
+void intel_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B;
+       int i;
+
+       /* The clocks have to be on to load the palette. */
+       if (!crtc->enabled)
+               return;
+
+       for (i = 0; i < 256; i++) {
+               I915_WRITE(palreg + 4 * i,
+                          (intel_crtc->lut_r[i] << 16) |
+                          (intel_crtc->lut_g[i] << 8) |
+                          intel_crtc->lut_b[i]);
+       }
+}
+
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+                                struct drm_file *file_priv,
+                                uint32_t handle,
+                                uint32_t width, uint32_t height)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_gem_object *bo;
+       struct drm_i915_gem_object *obj_priv;
+       int pipe = intel_crtc->pipe;
+       uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
+       uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
+       uint32_t temp;
+       size_t addr;
+
+       DRM_DEBUG("\n");
+
+       /* if we want to turn off the cursor ignore width and height */
+       if (!handle) {
+               DRM_DEBUG("cursor off\n");
+               /* turn of the cursor */
+               temp = 0;
+               temp |= CURSOR_MODE_DISABLE;
+
+               I915_WRITE(control, temp);
+               I915_WRITE(base, 0);
+               return 0;
+       }
+
+       /* Currently we only support 64x64 cursors */
+       if (width != 64 || height != 64) {
+               DRM_ERROR("we currently only support 64x64 cursors\n");
+               return -EINVAL;
+       }
+
+       bo = drm_gem_object_lookup(dev, file_priv, handle);
+       if (!bo)
+               return -ENOENT;
+
+       obj_priv = bo->driver_private;
+
+       if (bo->size < width * height * 4) {
+               DRM_ERROR("buffer is to small\n");
+               drm_gem_object_unreference(bo);
+               return -ENOMEM;
+       }
+
+       if (dev_priv->cursor_needs_physical) {
+               addr = dev->agp->base + obj_priv->gtt_offset;
+       } else {
+               addr = obj_priv->gtt_offset;
+       }
+
+       intel_crtc->cursor_addr = addr;
+       temp = 0;
+       /* set the pipe for the cursor */
+       temp |= (pipe << 28);
+       temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+
+       I915_WRITE(control, temp);
+       I915_WRITE(base, addr);
+
+       return 0;
+}
+
+static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       uint32_t temp = 0;
+       uint32_t adder;
+
+       if (x < 0) {
+               temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+               x = -x;
+       }
+       if (y < 0) {
+               temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+               y = -y;
+       }
+
+       temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
+       temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+
+       adder = intel_crtc->cursor_addr;
+       I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp);
+       I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder);
+
+       return 0;
+}
+
+/** Sets the color ramps on behalf of RandR */
+void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                                u16 blue, int regno)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       intel_crtc->lut_r[regno] = red >> 8;
+       intel_crtc->lut_g[regno] = green >> 8;
+       intel_crtc->lut_b[regno] = blue >> 8;
+}
+
+static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                u16 *blue, uint32_t size)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int i;
+
+       if (size != 256)
+               return;
+
+       for (i = 0; i < 256; i++) {
+               intel_crtc->lut_r[i] = red[i] >> 8;
+               intel_crtc->lut_g[i] = green[i] >> 8;
+               intel_crtc->lut_b[i] = blue[i] >> 8;
+       }
+
+       intel_crtc_load_lut(crtc);
+}
+
+/**
+ * Get a pipe with a simple mode set on it for doing load-based monitor
+ * detection.
+ *
+ * It will be up to the load-detect code to adjust the pipe as appropriate for
+ * its requirements.  The pipe will be connected to no other outputs.
+ *
+ * Currently this code will only succeed if there is a pipe with no outputs
+ * configured for it.  In the future, it could choose to temporarily disable
+ * some outputs to free up a pipe for its use.
+ *
+ * \return crtc, or NULL if no pipes are available.
+ */
+
+/* VESA 640x480x72Hz mode to set on the pipe */
+static struct drm_display_mode load_detect_mode = {
+       DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
+                704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+};
+
+struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
+                                           struct drm_display_mode *mode,
+                                           int *dpms_mode)
+{
+       struct intel_crtc *intel_crtc;
+       struct drm_crtc *possible_crtc;
+       struct drm_crtc *supported_crtc =NULL;
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_crtc *crtc = NULL;
+       struct drm_device *dev = encoder->dev;
+       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+       struct drm_crtc_helper_funcs *crtc_funcs;
+       int i = -1;
+
+       /*
+        * Algorithm gets a little messy:
+        *   - if the connector already has an assigned crtc, use it (but make
+        *     sure it's on first)
+        *   - try to find the first unused crtc that can drive this connector,
+        *     and use that if we find one
+        *   - if there are no unused crtcs available, try to use the first
+        *     one we found that supports the connector
+        */
+
+       /* See if we already have a CRTC for this connector */
+       if (encoder->crtc) {
+               crtc = encoder->crtc;
+               /* Make sure the crtc and connector are running */
+               intel_crtc = to_intel_crtc(crtc);
+               *dpms_mode = intel_crtc->dpms_mode;
+               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+                       crtc_funcs = crtc->helper_private;
+                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+                       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+               }
+               return crtc;
+       }
+
+       /* Find an unused one (if possible) */
+       list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) {
+               i++;
+               if (!(encoder->possible_crtcs & (1 << i)))
+                       continue;
+               if (!possible_crtc->enabled) {
+                       crtc = possible_crtc;
+                       break;
+               }
+               if (!supported_crtc)
+                       supported_crtc = possible_crtc;
+       }
+
+       /*
+        * If we didn't find an unused CRTC, don't use any.
+        */
+       if (!crtc) {
+               return NULL;
+       }
+
+       encoder->crtc = crtc;
+       intel_output->load_detect_temp = true;
+
+       intel_crtc = to_intel_crtc(crtc);
+       *dpms_mode = intel_crtc->dpms_mode;
+
+       if (!crtc->enabled) {
+               if (!mode)
+                       mode = &load_detect_mode;
+               drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
+       } else {
+               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+                       crtc_funcs = crtc->helper_private;
+                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+               }
+
+               /* Add this connector to the crtc */
+               encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode);
+               encoder_funcs->commit(encoder);
+       }
+       /* let the connector get through one full cycle before testing */
+       intel_wait_for_vblank(dev);
+
+       return crtc;
+}
+
+void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode)
+{
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_device *dev = encoder->dev;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+       if (intel_output->load_detect_temp) {
+               encoder->crtc = NULL;
+               intel_output->load_detect_temp = false;
+               crtc->enabled = drm_helper_crtc_in_use(crtc);
+               drm_helper_disable_unused_functions(dev);
+       }
+
+       /* Switch crtc and output back off if necessary */
+       if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
+               if (encoder->crtc == crtc)
+                       encoder_funcs->dpms(encoder, dpms_mode);
+               crtc_funcs->dpms(crtc, dpms_mode);
+       }
+}
+
+/* Returns the clock of the currently programmed mode of the given pipe. */
+static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B);
+       u32 fp;
+       intel_clock_t clock;
+
+       if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
+               fp = I915_READ((pipe == 0) ? FPA0 : FPB0);
+       else
+               fp = I915_READ((pipe == 0) ? FPA1 : FPB1);
+
+       clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
+       clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
+       clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
+       if (IS_I9XX(dev)) {
+               clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
+                              DPLL_FPA01_P1_POST_DIV_SHIFT);
+
+               switch (dpll & DPLL_MODE_MASK) {
+               case DPLLB_MODE_DAC_SERIAL:
+                       clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ?
+                               5 : 10;
+                       break;
+               case DPLLB_MODE_LVDS:
+                       clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ?
+                               7 : 14;
+                       break;
+               default:
+                       DRM_DEBUG("Unknown DPLL mode %08x in programmed "
+                                 "mode\n", (int)(dpll & DPLL_MODE_MASK));
+                       return 0;
+               }
+
+               /* XXX: Handle the 100Mhz refclk */
+               i9xx_clock(96000, &clock);
+       } else {
+               bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
+
+               if (is_lvds) {
+                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
+                                      DPLL_FPA01_P1_POST_DIV_SHIFT);
+                       clock.p2 = 14;
+
+                       if ((dpll & PLL_REF_INPUT_MASK) ==
+                           PLLB_REF_INPUT_SPREADSPECTRUMIN) {
+                               /* XXX: might not be 66MHz */
+                               i8xx_clock(66000, &clock);
+                       } else
+                               i8xx_clock(48000, &clock);
+               } else {
+                       if (dpll & PLL_P1_DIVIDE_BY_TWO)
+                               clock.p1 = 2;
+                       else {
+                               clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
+                                           DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
+                       }
+                       if (dpll & PLL_P2_DIVIDE_BY_4)
+                               clock.p2 = 4;
+                       else
+                               clock.p2 = 2;
+
+                       i8xx_clock(48000, &clock);
+               }
+       }
+
+       /* XXX: It would be nice to validate the clocks, but we can't reuse
+        * i830PllIsValid() because it relies on the xf86_config connector
+        * configuration being accurate, which it isn't necessarily.
+        */
+
+       return clock.dot;
+}
+
+/** Returns the currently programmed mode of the given pipe. */
+struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
+                                            struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       struct drm_display_mode *mode;
+       int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
+       int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
+       int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
+       int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
+
+       mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+       if (!mode)
+               return NULL;
+
+       mode->clock = intel_crtc_clock_get(dev, crtc);
+       mode->hdisplay = (htot & 0xffff) + 1;
+       mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
+       mode->hsync_start = (hsync & 0xffff) + 1;
+       mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
+       mode->vdisplay = (vtot & 0xffff) + 1;
+       mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
+       mode->vsync_start = (vsync & 0xffff) + 1;
+       mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
+
+       drm_mode_set_name(mode);
+       drm_mode_set_crtcinfo(mode, 0);
+
+       return mode;
+}
+
+static void intel_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       drm_crtc_cleanup(crtc);
+       kfree(intel_crtc);
+}
+
+static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+       .dpms = intel_crtc_dpms,
+       .mode_fixup = intel_crtc_mode_fixup,
+       .mode_set = intel_crtc_mode_set,
+       .mode_set_base = intel_pipe_set_base,
+       .prepare = intel_crtc_prepare,
+       .commit = intel_crtc_commit,
+};
+
+static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .cursor_set = intel_crtc_cursor_set,
+       .cursor_move = intel_crtc_cursor_move,
+       .gamma_set = intel_crtc_gamma_set,
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = intel_crtc_destroy,
+};
+
+
+static void intel_crtc_init(struct drm_device *dev, int pipe)
+{
+       struct intel_crtc *intel_crtc;
+       int i;
+
+       intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+       if (intel_crtc == NULL)
+               return;
+
+       drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
+
+       drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
+       intel_crtc->pipe = pipe;
+       for (i = 0; i < 256; i++) {
+               intel_crtc->lut_r[i] = i;
+               intel_crtc->lut_g[i] = i;
+               intel_crtc->lut_b[i] = i;
+       }
+
+       intel_crtc->cursor_addr = 0;
+       intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
+       drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+
+       intel_crtc->mode_set.crtc = &intel_crtc->base;
+       intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1);
+       intel_crtc->mode_set.num_connectors = 0;
+
+       if (i915_fbpercrtc) {
+
+
+
+       }
+}
+
+struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
+{
+       struct drm_crtc *crtc = NULL;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               if (intel_crtc->pipe == pipe)
+                       break;
+       }
+       return crtc;
+}
+
+static int intel_connector_clones(struct drm_device *dev, int type_mask)
+{
+       int index_mask = 0;
+       struct drm_connector *connector;
+       int entry = 0;
+
+        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct intel_output *intel_output = to_intel_output(connector);
+               if (type_mask & (1 << intel_output->type))
+                       index_mask |= (1 << entry);
+               entry++;
+       }
+       return index_mask;
+}
+
+
+static void intel_setup_outputs(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+
+       intel_crt_init(dev);
+
+       /* Set up integrated LVDS */
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               intel_lvds_init(dev);
+
+       if (IS_I9XX(dev)) {
+               intel_sdvo_init(dev, SDVOB);
+               intel_sdvo_init(dev, SDVOC);
+       } else
+               intel_dvo_init(dev);
+
+       if (IS_I9XX(dev) && !IS_I915G(dev))
+               intel_tv_init(dev);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               struct intel_output *intel_output = to_intel_output(connector);
+               struct drm_encoder *encoder = &intel_output->enc;
+               int crtc_mask = 0, clone_mask = 0;
+
+               /* valid crtcs */
+               switch(intel_output->type) {
+               case INTEL_OUTPUT_DVO:
+               case INTEL_OUTPUT_SDVO:
+                       crtc_mask = ((1 << 0)|
+                                    (1 << 1));
+                       clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
+                                     (1 << INTEL_OUTPUT_DVO) |
+                                     (1 << INTEL_OUTPUT_SDVO));
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       crtc_mask = ((1 << 0)|
+                                    (1 << 1));
+                       clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
+                                     (1 << INTEL_OUTPUT_DVO) |
+                                     (1 << INTEL_OUTPUT_SDVO));
+                       break;
+               case INTEL_OUTPUT_LVDS:
+                       crtc_mask = (1 << 1);
+                       clone_mask = (1 << INTEL_OUTPUT_LVDS);
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       crtc_mask = ((1 << 0) |
+                                    (1 << 1));
+                       clone_mask = (1 << INTEL_OUTPUT_TVOUT);
+                       break;
+               }
+               encoder->possible_crtcs = crtc_mask;
+               encoder->possible_clones = intel_connector_clones(dev, clone_mask);
+       }
+}
+
+static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct drm_device *dev = fb->dev;
+
+       if (fb->fbdev)
+               intelfb_remove(dev, fb);
+
+       drm_framebuffer_cleanup(fb);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(intel_fb->obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       kfree(intel_fb);
+}
+
+static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                               struct drm_file *file_priv,
+                                               unsigned int *handle)
+{
+       struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+       struct drm_gem_object *object = intel_fb->obj;
+
+       return drm_gem_handle_create(file_priv, object, handle);
+}
+
+static const struct drm_framebuffer_funcs intel_fb_funcs = {
+       .destroy = intel_user_framebuffer_destroy,
+       .create_handle = intel_user_framebuffer_create_handle,
+};
+
+int intel_framebuffer_create(struct drm_device *dev,
+                            struct drm_mode_fb_cmd *mode_cmd,
+                            struct drm_framebuffer **fb,
+                            struct drm_gem_object *obj)
+{
+       struct intel_framebuffer *intel_fb;
+       int ret;
+
+       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+       if (!intel_fb)
+               return -ENOMEM;
+
+       ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
+       if (ret) {
+               DRM_ERROR("framebuffer init failed %d\n", ret);
+               return ret;
+       }
+
+       drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
+
+       intel_fb->obj = obj;
+
+       *fb = &intel_fb->base;
+
+       return 0;
+}
+
+
+static struct drm_framebuffer *
+intel_user_framebuffer_create(struct drm_device *dev,
+                             struct drm_file *filp,
+                             struct drm_mode_fb_cmd *mode_cmd)
+{
+       struct drm_gem_object *obj;
+       struct drm_framebuffer *fb;
+       int ret;
+
+       obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
+       if (!obj)
+               return NULL;
+
+       ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
+       if (ret) {
+               drm_gem_object_unreference(obj);
+               return NULL;
+       }
+
+       return fb;
+}
+
+static const struct drm_mode_config_funcs intel_mode_funcs = {
+       .fb_create = intel_user_framebuffer_create,
+       .fb_changed = intelfb_probe,
+};
+
+void intel_modeset_init(struct drm_device *dev)
+{
+       int num_pipe;
+       int i;
+
+       drm_mode_config_init(dev);
+
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+
+       dev->mode_config.funcs = (void *)&intel_mode_funcs;
+
+       if (IS_I965G(dev)) {
+               dev->mode_config.max_width = 8192;
+               dev->mode_config.max_height = 8192;
+       } else {
+               dev->mode_config.max_width = 2048;
+               dev->mode_config.max_height = 2048;
+       }
+
+       /* set memory base */
+       if (IS_I9XX(dev))
+               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
+       else
+               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+
+       if (IS_MOBILE(dev) || IS_I9XX(dev))
+               num_pipe = 2;
+       else
+               num_pipe = 1;
+       DRM_DEBUG("%d display pipe%s available.\n",
+                 num_pipe, num_pipe > 1 ? "s" : "");
+
+       for (i = 0; i < num_pipe; i++) {
+               intel_crtc_init(dev, i);
+       }
+
+       intel_setup_outputs(dev);
+}
+
+void intel_modeset_cleanup(struct drm_device *dev)
+{
+       drm_mode_config_cleanup(dev);
+}
+
+
+/* current intel driver doesn't take advantage of encoders
+   always give back the encoder for the connector
+*/
+struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       return &intel_output->enc;
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
new file mode 100644 (file)
index 0000000..407edd5
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef __INTEL_DRV_H__
+#define __INTEL_DRV_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "drm_crtc.h"
+
+#include "drm_crtc_helper.h"
+/*
+ * Display related stuff
+ */
+
+/* store information about an Ixxx DVO */
+/* The i830->i865 use multiple DVOs with multiple i2cs */
+/* the i915, i945 have a single sDVO i2c bus - which is different */
+#define MAX_OUTPUTS 6
+/* maximum connectors per crtcs in the mode set */
+#define INTELFB_CONN_LIMIT 4
+
+#define INTEL_I2C_BUS_DVO 1
+#define INTEL_I2C_BUS_SDVO 2
+
+/* these are outputs from the chip - integrated only
+   external chips are via DVO or SDVO output */
+#define INTEL_OUTPUT_UNUSED 0
+#define INTEL_OUTPUT_ANALOG 1
+#define INTEL_OUTPUT_DVO 2
+#define INTEL_OUTPUT_SDVO 3
+#define INTEL_OUTPUT_LVDS 4
+#define INTEL_OUTPUT_TVOUT 5
+
+#define INTEL_DVO_CHIP_NONE 0
+#define INTEL_DVO_CHIP_LVDS 1
+#define INTEL_DVO_CHIP_TMDS 2
+#define INTEL_DVO_CHIP_TVOUT 4
+
+struct intel_i2c_chan {
+       struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
+       u32 reg; /* GPIO reg */
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+        u8 slave_addr;
+};
+
+struct intel_framebuffer {
+       struct drm_framebuffer base;
+       struct drm_gem_object *obj;
+};
+
+
+struct intel_output {
+       struct drm_connector base;
+
+       struct drm_encoder enc;
+       int type;
+       struct intel_i2c_chan *i2c_bus; /* for control functions */
+       struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */
+       bool load_detect_temp;
+       void *dev_priv;
+};
+
+struct intel_crtc {
+       struct drm_crtc base;
+       int pipe;
+       int plane;
+       uint32_t cursor_addr;
+       u8 lut_r[256], lut_g[256], lut_b[256];
+       int dpms_mode;
+       struct intel_framebuffer *fbdev_fb;
+       /* a mode_set for fbdev users on this crtc */
+       struct drm_mode_set mode_set;
+};
+
+#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
+#define to_intel_output(x) container_of(x, struct intel_output, base)
+#define enc_to_intel_output(x) container_of(x, struct intel_output, enc)
+#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
+
+struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                       const char *name);
+void intel_i2c_destroy(struct intel_i2c_chan *chan);
+int intel_ddc_get_modes(struct intel_output *intel_output);
+extern bool intel_ddc_probe(struct intel_output *intel_output);
+
+extern void intel_crt_init(struct drm_device *dev);
+extern void intel_sdvo_init(struct drm_device *dev, int output_device);
+extern void intel_dvo_init(struct drm_device *dev);
+extern void intel_tv_init(struct drm_device *dev);
+extern void intel_lvds_init(struct drm_device *dev);
+
+extern void intel_crtc_load_lut(struct drm_crtc *crtc);
+extern void intel_encoder_prepare (struct drm_encoder *encoder);
+extern void intel_encoder_commit (struct drm_encoder *encoder);
+
+extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
+
+extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
+                                                   struct drm_crtc *crtc);
+extern void intel_wait_for_vblank(struct drm_device *dev);
+extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
+                                                  struct drm_display_mode *mode,
+                                                  int *dpms_mode);
+extern void intel_release_load_detect_pipe(struct intel_output *intel_output,
+                                          int dpms_mode);
+
+extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
+extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
+extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
+extern int intelfb_probe(struct drm_device *dev);
+extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
+extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
+extern void intelfb_restore(void);
+extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                                   u16 blue, int regno);
+
+extern int intel_framebuffer_create(struct drm_device *dev,
+                                   struct drm_mode_fb_cmd *mode_cmd,
+                                   struct drm_framebuffer **fb,
+                                   struct drm_gem_object *obj);
+#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
new file mode 100644 (file)
index 0000000..8b8d6e6
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "dvo.h"
+
+#define SIL164_ADDR    0x38
+#define CH7xxx_ADDR    0x76
+#define TFP410_ADDR    0x38
+
+static struct intel_dvo_device intel_dvo_devices[] = {
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "sil164",
+               .dvo_reg = DVOC,
+               .slave_addr = SIL164_ADDR,
+               .dev_ops = &sil164_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "ch7xxx",
+               .dvo_reg = DVOC,
+               .slave_addr = CH7xxx_ADDR,
+               .dev_ops = &ch7xxx_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_LVDS,
+               .name = "ivch",
+               .dvo_reg = DVOA,
+               .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
+               .dev_ops = &ivch_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_TMDS,
+               .name = "tfp410",
+               .dvo_reg = DVOC,
+               .slave_addr = TFP410_ADDR,
+               .dev_ops = &tfp410_ops,
+       },
+       {
+               .type = INTEL_DVO_CHIP_LVDS,
+               .name = "ch7017",
+               .dvo_reg = DVOC,
+               .slave_addr = 0x75,
+               .gpio = GPIOE,
+               .dev_ops = &ch7017_ops,
+       }
+};
+
+static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+       u32 dvo_reg = dvo->dvo_reg;
+       u32 temp = I915_READ(dvo_reg);
+
+       if (mode == DRM_MODE_DPMS_ON) {
+               I915_WRITE(dvo_reg, temp | DVO_ENABLE);
+               I915_READ(dvo_reg);
+               dvo->dev_ops->dpms(dvo, mode);
+       } else {
+               dvo->dev_ops->dpms(dvo, mode);
+               I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
+               I915_READ(dvo_reg);
+       }
+}
+
+static void intel_dvo_save(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       /* Each output should probably just save the registers it touches,
+        * but for now, use more overkill.
+        */
+       dev_priv->saveDVOA = I915_READ(DVOA);
+       dev_priv->saveDVOB = I915_READ(DVOB);
+       dev_priv->saveDVOC = I915_READ(DVOC);
+
+       dvo->dev_ops->save(dvo);
+}
+
+static void intel_dvo_restore(struct drm_connector *connector)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       dvo->dev_ops->restore(dvo);
+
+       I915_WRITE(DVOA, dev_priv->saveDVOA);
+       I915_WRITE(DVOB, dev_priv->saveDVOB);
+       I915_WRITE(DVOC, dev_priv->saveDVOC);
+}
+
+static int intel_dvo_mode_valid(struct drm_connector *connector,
+                               struct drm_display_mode *mode)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       /* XXX: Validate clock range */
+
+       if (dvo->panel_fixed_mode) {
+               if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+
+       return dvo->dev_ops->mode_valid(dvo, mode);
+}
+
+static bool intel_dvo_mode_fixup(struct drm_encoder *encoder,
+                                struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode)
+{
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       /* If we have timings from the BIOS for the panel, put them in
+        * to the adjusted mode.  The CRTC will be set up for this mode,
+        * with the panel scaling set up to source from the H/VDisplay
+        * of the original mode.
+        */
+       if (dvo->panel_fixed_mode != NULL) {
+#define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x
+               C(hdisplay);
+               C(hsync_start);
+               C(hsync_end);
+               C(htotal);
+               C(vdisplay);
+               C(vsync_start);
+               C(vsync_end);
+               C(vtotal);
+               C(clock);
+               drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+#undef C
+       }
+
+       if (dvo->dev_ops->mode_fixup)
+               return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode);
+
+       return true;
+}
+
+static void intel_dvo_mode_set(struct drm_encoder *encoder,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+       int pipe = intel_crtc->pipe;
+       u32 dvo_val;
+       u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+
+       switch (dvo_reg) {
+       case DVOA:
+       default:
+               dvo_srcdim_reg = DVOA_SRCDIM;
+               break;
+       case DVOB:
+               dvo_srcdim_reg = DVOB_SRCDIM;
+               break;
+       case DVOC:
+               dvo_srcdim_reg = DVOC_SRCDIM;
+               break;
+       }
+
+       dvo->dev_ops->mode_set(dvo, mode, adjusted_mode);
+
+       /* Save the data order, since I don't know what it should be set to. */
+       dvo_val = I915_READ(dvo_reg) &
+                 (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
+       dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |
+                  DVO_BLANK_ACTIVE_HIGH;
+
+       if (pipe == 1)
+               dvo_val |= DVO_PIPE_B_SELECT;
+       dvo_val |= DVO_PIPE_STALL;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+               dvo_val |= DVO_HSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+               dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
+
+       I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED);
+
+       /*I915_WRITE(DVOB_SRCDIM,
+         (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+         (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
+       I915_WRITE(dvo_srcdim_reg,
+                  (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+                  (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
+       /*I915_WRITE(DVOB, dvo_val);*/
+       I915_WRITE(dvo_reg, dvo_val);
+}
+
+/**
+ * Detect the output connection on our DVO device.
+ *
+ * Unimplemented.
+ */
+static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       return dvo->dev_ops->detect(dvo);
+}
+
+static int intel_dvo_get_modes(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       /* We should probably have an i2c driver get_modes function for those
+        * devices which will have a fixed set of modes determined by the chip
+        * (TV-out, for example), but for now with just TMDS and LVDS,
+        * that's not the case.
+        */
+       intel_ddc_get_modes(intel_output);
+       if (!list_empty(&connector->probed_modes))
+               return 1;
+
+
+       if (dvo->panel_fixed_mode != NULL) {
+               struct drm_display_mode *mode;
+               mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode);
+               if (mode) {
+                       drm_mode_probed_add(connector, mode);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static void intel_dvo_destroy (struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+
+       if (dvo) {
+               if (dvo->dev_ops->destroy)
+                       dvo->dev_ops->destroy(dvo);
+               if (dvo->panel_fixed_mode)
+                       kfree(dvo->panel_fixed_mode);
+               /* no need, in i830_dvoices[] now */
+               //kfree(dvo);
+       }
+       if (intel_output->i2c_bus)
+               intel_i2c_destroy(intel_output->i2c_bus);
+       if (intel_output->ddc_bus)
+               intel_i2c_destroy(intel_output->ddc_bus);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(intel_output);
+}
+
+#ifdef RANDR_GET_CRTC_INTERFACE
+static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+       int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT);
+
+       return intel_pipe_to_crtc(pScrn, pipe);
+}
+#endif
+
+static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = {
+       .dpms = intel_dvo_dpms,
+       .mode_fixup = intel_dvo_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .mode_set = intel_dvo_mode_set,
+       .commit = intel_encoder_commit,
+};
+
+static const struct drm_connector_funcs intel_dvo_connector_funcs = {
+       .save = intel_dvo_save,
+       .restore = intel_dvo_restore,
+       .detect = intel_dvo_detect,
+       .destroy = intel_dvo_destroy,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+};
+
+static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
+       .mode_valid = intel_dvo_mode_valid,
+       .get_modes = intel_dvo_get_modes,
+       .best_encoder = intel_best_encoder,
+};
+
+static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
+       .destroy = intel_dvo_enc_destroy,
+};
+
+
+/**
+ * Attempts to get a fixed panel timing for LVDS (currently only the i830).
+ *
+ * Other chips with DVO LVDS will need to extend this to deal with the LVDS
+ * chip being on DVOB/C and having multiple pipes.
+ */
+static struct drm_display_mode *
+intel_dvo_get_current_mode (struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_dvo_device *dvo = intel_output->dev_priv;
+       uint32_t dvo_reg = dvo->dvo_reg;
+       uint32_t dvo_val = I915_READ(dvo_reg);
+       struct drm_display_mode *mode = NULL;
+
+       /* If the DVO port is active, that'll be the LVDS, so we can pull out
+        * its timings to get how the BIOS set up the panel.
+        */
+       if (dvo_val & DVO_ENABLE) {
+               struct drm_crtc *crtc;
+               int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
+
+               crtc = intel_get_crtc_from_pipe(dev, pipe);
+               if (crtc) {
+                       mode = intel_crtc_mode_get(dev, crtc);
+
+                       if (mode) {
+                               mode->type |= DRM_MODE_TYPE_PREFERRED;
+                               if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)
+                                       mode->flags |= DRM_MODE_FLAG_PHSYNC;
+                               if (dvo_val & DVO_VSYNC_ACTIVE_HIGH)
+                                       mode->flags |= DRM_MODE_FLAG_PVSYNC;
+                       }
+               }
+       }
+       return mode;
+}
+
+void intel_dvo_init(struct drm_device *dev)
+{
+       struct intel_output *intel_output;
+       struct intel_dvo_device *dvo;
+       struct intel_i2c_chan *i2cbus = NULL;
+       int ret = 0;
+       int i;
+       int gpio_inited = 0;
+       int encoder_type = DRM_MODE_ENCODER_NONE;
+       intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output)
+               return;
+
+       /* Set up the DDC bus */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
+       if (!intel_output->ddc_bus)
+               goto free_intel;
+
+       /* Now, try to find a controller */
+       for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
+               struct drm_connector *connector = &intel_output->base;
+               int gpio;
+
+               dvo = &intel_dvo_devices[i];
+
+               /* Allow the I2C driver info to specify the GPIO to be used in
+                * special cases, but otherwise default to what's defined
+                * in the spec.
+                */
+               if (dvo->gpio != 0)
+                       gpio = dvo->gpio;
+               else if (dvo->type == INTEL_DVO_CHIP_LVDS)
+                       gpio = GPIOB;
+               else
+                       gpio = GPIOE;
+
+               /* Set up the I2C bus necessary for the chip we're probing.
+                * It appears that everything is on GPIOE except for panels
+                * on i830 laptops, which are on GPIOB (DVOA).
+                */
+               if (gpio_inited != gpio) {
+                       if (i2cbus != NULL)
+                               intel_i2c_destroy(i2cbus);
+                       if (!(i2cbus = intel_i2c_create(dev, gpio,
+                               gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
+                               continue;
+                       }
+                       gpio_inited = gpio;
+               }
+
+               if (dvo->dev_ops!= NULL)
+                       ret = dvo->dev_ops->init(dvo, i2cbus);
+               else
+                       ret = false;
+
+               if (!ret)
+                       continue;
+
+               intel_output->type = INTEL_OUTPUT_DVO;
+               switch (dvo->type) {
+               case INTEL_DVO_CHIP_TMDS:
+                       drm_connector_init(dev, connector,
+                                          &intel_dvo_connector_funcs,
+                                          DRM_MODE_CONNECTOR_DVII);
+                       encoder_type = DRM_MODE_ENCODER_TMDS;
+                       break;
+               case INTEL_DVO_CHIP_LVDS:
+                       drm_connector_init(dev, connector,
+                                          &intel_dvo_connector_funcs,
+                                          DRM_MODE_CONNECTOR_LVDS);
+                       encoder_type = DRM_MODE_ENCODER_LVDS;
+                       break;
+               }
+
+               drm_connector_helper_add(connector,
+                                        &intel_dvo_connector_helper_funcs);
+               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+               connector->interlace_allowed = false;
+               connector->doublescan_allowed = false;
+
+               intel_output->dev_priv = dvo;
+               intel_output->i2c_bus = i2cbus;
+
+               drm_encoder_init(dev, &intel_output->enc,
+                                &intel_dvo_enc_funcs, encoder_type);
+               drm_encoder_helper_add(&intel_output->enc,
+                                      &intel_dvo_helper_funcs);
+
+               drm_mode_connector_attach_encoder(&intel_output->base,
+                                                 &intel_output->enc);
+               if (dvo->type == INTEL_DVO_CHIP_LVDS) {
+                       /* For our LVDS chipsets, we should hopefully be able
+                        * to dig the fixed panel mode out of the BIOS data.
+                        * However, it's in a different format from the BIOS
+                        * data on chipsets with integrated LVDS (stored in AIM
+                        * headers, likely), so for now, just get the current
+                        * mode being output through DVO.
+                        */
+                       dvo->panel_fixed_mode =
+                               intel_dvo_get_current_mode(connector);
+                       dvo->panel_wants_dither = true;
+               }
+
+               drm_sysfs_connector_add(connector);
+               return;
+       }
+
+       intel_i2c_destroy(intel_output->ddc_bus);
+       /* Didn't find a chip, so tear down. */
+       if (i2cbus != NULL)
+               intel_i2c_destroy(i2cbus);
+free_intel:
+       kfree(intel_output);
+}
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
new file mode 100644 (file)
index 0000000..afd1217
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * Copyright Â© 2007 David Airlie
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     David Airlie
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+struct intelfb_par {
+       struct drm_device *dev;
+       struct drm_display_mode *our_mode;
+       struct intel_framebuffer *intel_fb;
+       int crtc_count;
+       /* crtc currently bound to this */
+       uint32_t crtc_ids[2];
+};
+
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                       unsigned blue, unsigned transp,
+                       struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_crtc *crtc;
+       int i;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               struct drm_mode_set *modeset = &intel_crtc->mode_set;
+               struct drm_framebuffer *fb = modeset->fb;
+
+               for (i = 0; i < par->crtc_count; i++)
+                       if (crtc->base.id == par->crtc_ids[i])
+                               break;
+
+               if (i == par->crtc_count)
+                       continue;
+
+
+               if (regno > 255)
+                       return 1;
+
+               if (fb->depth == 8) {
+                       intel_crtc_fb_gamma_set(crtc, red, green, blue, regno);
+                       return 0;
+               }
+
+               if (regno < 16) {
+                       switch (fb->depth) {
+                       case 15:
+                               fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
+                                       ((green & 0xf800) >>  6) |
+                                       ((blue & 0xf800) >> 11);
+                               break;
+                       case 16:
+                               fb->pseudo_palette[regno] = (red & 0xf800) |
+                                       ((green & 0xfc00) >>  5) |
+                                       ((blue  & 0xf800) >> 11);
+                               break;
+                       case 24:
+                       case 32:
+                               fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                                       (green & 0xff00) |
+                                       ((blue  & 0xff00) >> 8);
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int intelfb_check_var(struct fb_var_screeninfo *var,
+                       struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct intel_framebuffer *intel_fb = par->intel_fb;
+       struct drm_framebuffer *fb = &intel_fb->base;
+       int depth;
+
+       if (var->pixclock == -1 || !var->pixclock)
+               return -EINVAL;
+
+       /* Need to resize the fb object !!! */
+       if (var->xres > fb->width || var->yres > fb->height) {
+               DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
+               DRM_ERROR("Need resizing code.\n");
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               depth = var->bits_per_pixel;
+               break;
+       }
+
+       switch (depth) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 15:
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               var->transp.offset = 15;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* this will let fbcon do the mode init */
+/* FIXME: take mode config lock? */
+static int intelfb_set_par(struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct fb_var_screeninfo *var = &info->var;
+       int i;
+
+       DRM_DEBUG("%d %d\n", var->xres, var->pixclock);
+
+       if (var->pixclock != -1) {
+
+               DRM_ERROR("PIXEL CLCOK SET\n");
+               return -EINVAL;
+       } else {
+               struct drm_crtc *crtc;
+               int ret;
+
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+                       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+                       for (i = 0; i < par->crtc_count; i++)
+                               if (crtc->base.id == par->crtc_ids[i])
+                                       break;
+
+                       if (i == par->crtc_count)
+                               continue;
+
+                       if (crtc->fb == intel_crtc->mode_set.fb) {
+                               mutex_lock(&dev->mode_config.mutex);
+                               ret = crtc->funcs->set_config(&intel_crtc->mode_set);
+                               mutex_unlock(&dev->mode_config.mutex);
+                               if (ret)
+                                       return ret;
+                       }
+               }
+               return 0;
+       }
+}
+
+static int intelfb_pan_display(struct fb_var_screeninfo *var,
+                               struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_mode_set *modeset;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       int ret = 0;
+       int i;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               for (i = 0; i < par->crtc_count; i++)
+                       if (crtc->base.id == par->crtc_ids[i])
+                               break;
+
+               if (i == par->crtc_count)
+                       continue;
+
+               intel_crtc = to_intel_crtc(crtc);
+               modeset = &intel_crtc->mode_set;
+
+               modeset->x = var->xoffset;
+               modeset->y = var->yoffset;
+
+               if (modeset->num_connectors) {
+                       mutex_lock(&dev->mode_config.mutex);
+                       ret = crtc->funcs->set_config(modeset);
+                       mutex_unlock(&dev->mode_config.mutex);
+                       if (!ret) {
+                               info->var.xoffset = var->xoffset;
+                               info->var.yoffset = var->yoffset;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static void intelfb_on(struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int i;
+
+       /*
+        * For each CRTC in this fb, find all associated encoders
+        * and turn them off, then turn off the CRTC.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+               for (i = 0; i < par->crtc_count; i++)
+                       if (crtc->base.id == par->crtc_ids[i])
+                               break;
+
+               crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+
+               /* Found a CRTC on this fb, now find encoders */
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       if (encoder->crtc == crtc) {
+                               struct drm_encoder_helper_funcs *encoder_funcs;
+                               encoder_funcs = encoder->helper_private;
+                               encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+                       }
+               }
+       }
+}
+
+static void intelfb_off(struct fb_info *info, int dpms_mode)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int i;
+
+       /*
+        * For each CRTC in this fb, find all associated encoders
+        * and turn them off, then turn off the CRTC.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+               for (i = 0; i < par->crtc_count; i++)
+                       if (crtc->base.id == par->crtc_ids[i])
+                               break;
+
+               /* Found a CRTC on this fb, now find encoders */
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       if (encoder->crtc == crtc) {
+                               struct drm_encoder_helper_funcs *encoder_funcs;
+                               encoder_funcs = encoder->helper_private;
+                               encoder_funcs->dpms(encoder, dpms_mode);
+                       }
+               }
+               if (dpms_mode == DRM_MODE_DPMS_OFF)
+                       crtc_funcs->dpms(crtc, dpms_mode);
+       }
+}
+
+static int intelfb_blank(int blank, struct fb_info *info)
+{
+       switch (blank) {
+       case FB_BLANK_UNBLANK:
+               intelfb_on(info);
+               break;
+       case FB_BLANK_NORMAL:
+               intelfb_off(info, DRM_MODE_DPMS_STANDBY);
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               intelfb_off(info, DRM_MODE_DPMS_STANDBY);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               intelfb_off(info, DRM_MODE_DPMS_SUSPEND);
+               break;
+       case FB_BLANK_POWERDOWN:
+               intelfb_off(info, DRM_MODE_DPMS_OFF);
+               break;
+       }
+       return 0;
+}
+
+static struct fb_ops intelfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = intelfb_check_var,
+       .fb_set_par = intelfb_set_par,
+       .fb_setcolreg = intelfb_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+       .fb_pan_display = intelfb_pan_display,
+       .fb_blank = intelfb_blank,
+};
+
+/**
+ * Curretly it is assumed that the old framebuffer is reused.
+ *
+ * LOCKING
+ * caller should hold the mode config lock.
+ *
+ */
+int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       struct drm_display_mode *mode = crtc->desired_mode;
+
+       fb = crtc->fb;
+       if (!fb)
+               return 1;
+
+       info = fb->fbdev;
+       if (!info)
+               return 1;
+
+       if (!mode)
+               return 1;
+
+       info->var.xres = mode->hdisplay;
+       info->var.right_margin = mode->hsync_start - mode->hdisplay;
+       info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+       info->var.left_margin = mode->htotal - mode->hsync_end;
+       info->var.yres = mode->vdisplay;
+       info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+       info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
+       /* avoid overflow */
+       info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
+
+       return 0;
+}
+EXPORT_SYMBOL(intelfb_resize);
+
+static struct drm_mode_set kernelfb_mode;
+
+static int intelfb_panic(struct notifier_block *n, unsigned long ununsed,
+                        void *panic_str)
+{
+       DRM_ERROR("panic occurred, switching back to text console\n");
+
+       intelfb_restore();
+       return 0;
+}
+
+static struct notifier_block paniced = {
+       .notifier_call = intelfb_panic,
+};
+
+static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
+                         uint32_t fb_height, uint32_t surface_width,
+                         uint32_t surface_height,
+                         struct intel_framebuffer **intel_fb_p)
+{
+       struct fb_info *info;
+       struct intelfb_par *par;
+       struct drm_framebuffer *fb;
+       struct intel_framebuffer *intel_fb;
+       struct drm_mode_fb_cmd mode_cmd;
+       struct drm_gem_object *fbo = NULL;
+       struct drm_i915_gem_object *obj_priv;
+       struct device *device = &dev->pdev->dev;
+       int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+
+       mode_cmd.width = surface_width;
+       mode_cmd.height = surface_height;
+
+       mode_cmd.bpp = 32;
+       mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64);
+       mode_cmd.depth = 24;
+
+       size = mode_cmd.pitch * mode_cmd.height;
+       size = ALIGN(size, PAGE_SIZE);
+       fbo = drm_gem_object_alloc(dev, size);
+       if (!fbo) {
+               printk(KERN_ERR "failed to allocate framebuffer\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       obj_priv = fbo->driver_private;
+
+       mutex_lock(&dev->struct_mutex);
+
+       ret = i915_gem_object_pin(fbo, PAGE_SIZE);
+       if (ret) {
+               DRM_ERROR("failed to pin fb: %d\n", ret);
+               goto out_unref;
+       }
+
+       /* Flush everything out, we'll be doing GTT only from now on */
+       i915_gem_object_set_to_gtt_domain(fbo, 1);
+
+       ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo);
+       if (ret) {
+               DRM_ERROR("failed to allocate fb.\n");
+               goto out_unref;
+       }
+
+       list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
+
+       intel_fb = to_intel_framebuffer(fb);
+       *intel_fb_p = intel_fb;
+
+       info = framebuffer_alloc(sizeof(struct intelfb_par), device);
+       if (!info) {
+               ret = -ENOMEM;
+               goto out_unref;
+       }
+
+       par = info->par;
+
+       strcpy(info->fix.id, "inteldrmfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 1; /* doing it in hw */
+       info->fix.ypanstep = 1; /* doing it in hw */
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_I830;
+       info->fix.type_aux = 0;
+
+       info->flags = FBINFO_DEFAULT;
+
+       info->fbops = &intelfb_ops;
+
+       info->fix.line_length = fb->pitch;
+       info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
+       info->fix.smem_len = size;
+
+       info->flags = FBINFO_DEFAULT;
+
+       info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset,
+                                      size);
+       if (!info->screen_base) {
+               ret = -ENOSPC;
+               goto out_unref;
+       }
+       info->screen_size = size;
+
+//     memset(info->screen_base, 0, size);
+
+       info->pseudo_palette = fb->pseudo_palette;
+       info->var.xres_virtual = fb->width;
+       info->var.yres_virtual = fb->height;
+       info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+
+       info->var.xres = fb_width;
+       info->var.yres = fb_height;
+
+       /* FIXME: we really shouldn't expose mmio space at all */
+       info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
+       info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar);
+
+       info->pixmap.size = 64*1024;
+       info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 1;
+
+       switch(fb->depth) {
+       case 8:
+               info->var.red.offset = 0;
+               info->var.green.offset = 0;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8; /* 8bit DAC */
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 15:
+               info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 5;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+               info->var.transp.length = 1;
+               break;
+       case 16:
+               info->var.red.offset = 11;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 6;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 0;
+               break;
+       case 24:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               break;
+       }
+
+       fb->fbdev = info;
+
+       par->intel_fb = intel_fb;
+       par->dev = dev;
+
+       /* To allow resizeing without swapping buffers */
+       printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
+              intel_fb->base.height, obj_priv->gtt_offset, fbo);
+
+       mutex_unlock(&dev->struct_mutex);
+       return 0;
+
+out_unref:
+       drm_gem_object_unreference(fbo);
+       mutex_unlock(&dev->struct_mutex);
+out:
+       return ret;
+}
+
+static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_framebuffer *intel_fb;
+       struct drm_framebuffer *fb;
+       struct drm_connector *connector;
+       struct fb_info *info;
+       struct intelfb_par *par;
+       struct drm_mode_set *modeset;
+       unsigned int width, height;
+       int new_fb = 0;
+       int ret, i, conn_count;
+
+       if (!drm_helper_crtc_in_use(crtc))
+               return 0;
+
+       if (!crtc->desired_mode)
+               return 0;
+
+       width = crtc->desired_mode->hdisplay;
+       height = crtc->desired_mode->vdisplay;
+
+       /* is there an fb bound to this crtc already */
+       if (!intel_crtc->mode_set.fb) {
+               ret = intelfb_create(dev, width, height, width, height, &intel_fb);
+               if (ret)
+                       return -EINVAL;
+               new_fb = 1;
+       } else {
+               fb = intel_crtc->mode_set.fb;
+               intel_fb = to_intel_framebuffer(fb);
+               if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
+                       return -EINVAL;
+       }
+
+       info = intel_fb->base.fbdev;
+       par = info->par;
+
+       modeset = &intel_crtc->mode_set;
+       modeset->fb = &intel_fb->base;
+       conn_count = 0;
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->encoder)
+                       if (connector->encoder->crtc == modeset->crtc) {
+                               modeset->connectors[conn_count] = connector;
+                               conn_count++;
+                               if (conn_count > INTELFB_CONN_LIMIT)
+                                       BUG();
+                       }
+       }
+
+       for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
+               modeset->connectors[i] = NULL;
+
+       par->crtc_ids[0] = crtc->base.id;
+
+       modeset->num_connectors = conn_count;
+       if (modeset->mode != modeset->crtc->desired_mode)
+               modeset->mode = modeset->crtc->desired_mode;
+
+       par->crtc_count = 1;
+
+       if (new_fb) {
+               info->var.pixclock = -1;
+               if (register_framebuffer(info) < 0)
+                       return -EINVAL;
+       } else
+               intelfb_set_par(info);
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+              info->fix.id);
+
+       /* Switch back to kernel console on panic */
+       kernelfb_mode = *modeset;
+       atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+       printk(KERN_INFO "registered panic notifier\n");
+
+       return 0;
+}
+
+static int intelfb_multi_fb_probe(struct drm_device *dev)
+{
+
+       struct drm_crtc *crtc;
+       int ret = 0;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               ret = intelfb_multi_fb_probe_crtc(dev, crtc);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+static int intelfb_single_fb_probe(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_connector *connector;
+       unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
+       unsigned int surface_width = 0, surface_height = 0;
+       int new_fb = 0;
+       int crtc_count = 0;
+       int ret, i, conn_count = 0;
+       struct intel_framebuffer *intel_fb;
+       struct fb_info *info;
+       struct intelfb_par *par;
+       struct drm_mode_set *modeset = NULL;
+
+       DRM_DEBUG("\n");
+
+       /* Get a count of crtcs now in use and new min/maxes width/heights */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (!drm_helper_crtc_in_use(crtc))
+                       continue;
+
+               crtc_count++;
+               if (!crtc->desired_mode)
+                       continue;
+
+               /* Smallest mode determines console size... */
+               if (crtc->desired_mode->hdisplay < fb_width)
+                       fb_width = crtc->desired_mode->hdisplay;
+
+               if (crtc->desired_mode->vdisplay < fb_height)
+                       fb_height = crtc->desired_mode->vdisplay;
+
+               /* ... but largest for memory allocation dimensions */
+               if (crtc->desired_mode->hdisplay > surface_width)
+                       surface_width = crtc->desired_mode->hdisplay;
+
+               if (crtc->desired_mode->vdisplay > surface_height)
+                       surface_height = crtc->desired_mode->vdisplay;
+       }
+
+       if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
+               /* hmm everyone went away - assume VGA cable just fell out
+                  and will come back later. */
+               DRM_DEBUG("no CRTCs available?\n");
+               return 0;
+       }
+
+//fail
+       /* Find the fb for our new config */
+       if (list_empty(&dev->mode_config.fb_kernel_list)) {
+               DRM_DEBUG("creating new fb (console size %dx%d, "
+                         "buffer size %dx%d)\n", fb_width, fb_height,
+                         surface_width, surface_height);
+               ret = intelfb_create(dev, fb_width, fb_height, surface_width,
+                                    surface_height, &intel_fb);
+               if (ret)
+                       return -EINVAL;
+               new_fb = 1;
+       } else {
+               struct drm_framebuffer *fb;
+
+               fb = list_first_entry(&dev->mode_config.fb_kernel_list,
+                                     struct drm_framebuffer, filp_head);
+               intel_fb = to_intel_framebuffer(fb);
+
+               /* if someone hotplugs something bigger than we have already
+                * allocated, we are pwned.  As really we can't resize an
+                * fbdev that is in the wild currently due to fbdev not really
+                * being designed for the lower layers moving stuff around
+                * under it.
+                * - so in the grand style of things - punt.
+                */
+               if ((fb->width < surface_width) ||
+                   (fb->height < surface_height)) {
+                       DRM_ERROR("fb not large enough for console\n");
+                       return -EINVAL;
+               }
+       }
+// fail
+
+       info = intel_fb->base.fbdev;
+       par = info->par;
+
+       crtc_count = 0;
+       /*
+        * For each CRTC, set up the connector list for the CRTC's mode
+        * set configuration.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+               modeset = &intel_crtc->mode_set;
+               modeset->fb = &intel_fb->base;
+               conn_count = 0;
+               list_for_each_entry(connector, &dev->mode_config.connector_list,
+                                   head) {
+                       if (!connector->encoder)
+                               continue;
+
+                       if(connector->encoder->crtc == modeset->crtc) {
+                               modeset->connectors[conn_count++] = connector;
+                               if (conn_count > INTELFB_CONN_LIMIT)
+                                       BUG();
+                       }
+               }
+
+               /* Zero out remaining connector pointers */
+               for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
+                       modeset->connectors[i] = NULL;
+
+               par->crtc_ids[crtc_count++] = crtc->base.id;
+
+               modeset->num_connectors = conn_count;
+               if (modeset->mode != modeset->crtc->desired_mode)
+                       modeset->mode = modeset->crtc->desired_mode;
+       }
+       par->crtc_count = crtc_count;
+
+       if (new_fb) {
+               info->var.pixclock = -1;
+               if (register_framebuffer(info) < 0)
+                       return -EINVAL;
+       } else
+               intelfb_set_par(info);
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+              info->fix.id);
+
+       /* Switch back to kernel console on panic */
+       kernelfb_mode = *modeset;
+       atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+       printk(KERN_INFO "registered panic notifier\n");
+
+       return 0;
+}
+
+/**
+ * intelfb_restore - restore the framebuffer console (kernel) config
+ *
+ * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
+ */
+void intelfb_restore(void)
+{
+       drm_crtc_helper_set_config(&kernelfb_mode);
+}
+
+static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
+{
+        intelfb_restore();
+}
+
+static struct sysrq_key_op sysrq_intelfb_restore_op = {
+        .handler = intelfb_sysrq,
+        .help_msg = "force fb",
+        .action_msg = "force restore of fb console",
+};
+
+int intelfb_probe(struct drm_device *dev)
+{
+       int ret;
+
+       DRM_DEBUG("\n");
+
+       /* something has changed in the lower levels of hell - deal with it
+          here */
+
+       /* two modes : a) 1 fb to rule all crtcs.
+                      b) one fb per crtc.
+          two actions 1) new connected device
+                      2) device removed.
+          case a/1 : if the fb surface isn't big enough - resize the surface fb.
+                     if the fb size isn't big enough - resize fb into surface.
+                     if everything big enough configure the new crtc/etc.
+          case a/2 : undo the configuration
+                     possibly resize down the fb to fit the new configuration.
+           case b/1 : see if it is on a new crtc - setup a new fb and add it.
+          case b/2 : teardown the new fb.
+       */
+
+       /* mode a first */
+       /* search for an fb */
+       if (i915_fbpercrtc == 1) {
+               ret = intelfb_multi_fb_probe(dev);
+       } else {
+               ret = intelfb_single_fb_probe(dev);
+       }
+
+       register_sysrq_key('g', &sysrq_intelfb_restore_op);
+
+       return ret;
+}
+EXPORT_SYMBOL(intelfb_probe);
+
+int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
+{
+       struct fb_info *info;
+
+       if (!fb)
+               return -EINVAL;
+
+       info = fb->fbdev;
+
+       if (info) {
+               unregister_framebuffer(info);
+               iounmap(info->screen_base);
+               framebuffer_release(info);
+       }
+
+       atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
+       memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set));
+       return 0;
+}
+EXPORT_SYMBOL(intelfb_remove);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
new file mode 100644 (file)
index 0000000..a5a2f53
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright Â© 2006-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/*
+ * Intel GPIO access functions
+ */
+
+#define I2C_RISEFALL_TIME 20
+
+static int get_clock(void *data)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 val;
+
+       val = I915_READ(chan->reg);
+       return ((val & GPIO_CLOCK_VAL_IN) != 0);
+}
+
+static int get_data(void *data)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 val;
+
+       val = I915_READ(chan->reg);
+       return ((val & GPIO_DATA_VAL_IN) != 0);
+}
+
+static void set_clock(void *data, int state_high)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_device *dev = chan->drm_dev;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 reserved = 0, clock_bits;
+
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(dev) && !IS_845G(dev))
+               reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
+                                                  GPIO_CLOCK_PULLUP_DISABLE);
+
+       if (state_high)
+               clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
+       else
+               clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
+                       GPIO_CLOCK_VAL_MASK;
+       I915_WRITE(chan->reg, reserved | clock_bits);
+       udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+}
+
+static void set_data(void *data, int state_high)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_device *dev = chan->drm_dev;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 reserved = 0, data_bits;
+
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(dev) && !IS_845G(dev))
+               reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
+                                                  GPIO_CLOCK_PULLUP_DISABLE);
+
+       if (state_high)
+               data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
+       else
+               data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
+                       GPIO_DATA_VAL_MASK;
+
+       I915_WRITE(chan->reg, reserved | data_bits);
+       udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+}
+
+/**
+ * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
+ * @dev: DRM device
+ * @output: driver specific output device
+ * @reg: GPIO reg to use
+ * @name: name for this bus
+ *
+ * Creates and registers a new i2c bus with the Linux i2c layer, for use
+ * in output probing and control (e.g. DDC or SDVO control functions).
+ *
+ * Possible values for @reg include:
+ *   %GPIOA
+ *   %GPIOB
+ *   %GPIOC
+ *   %GPIOD
+ *   %GPIOE
+ *   %GPIOF
+ *   %GPIOG
+ *   %GPIOH
+ * see PRM for details on how these different busses are used.
+ */
+struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                       const char *name)
+{
+       struct intel_i2c_chan *chan;
+
+       chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
+       if (!chan)
+               goto out_free;
+
+       chan->drm_dev = dev;
+       chan->reg = reg;
+       snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
+       chan->adapter.owner = THIS_MODULE;
+#ifndef I2C_HW_B_INTELFB
+#define I2C_HW_B_INTELFB I2C_HW_B_I810
+#endif
+       chan->adapter.id = I2C_HW_B_INTELFB;
+       chan->adapter.algo_data = &chan->algo;
+       chan->adapter.dev.parent = &dev->pdev->dev;
+       chan->algo.setsda = set_data;
+       chan->algo.setscl = set_clock;
+       chan->algo.getsda = get_data;
+       chan->algo.getscl = get_clock;
+       chan->algo.udelay = 20;
+       chan->algo.timeout = usecs_to_jiffies(2200);
+       chan->algo.data = chan;
+
+       i2c_set_adapdata(&chan->adapter, chan);
+
+       if(i2c_bit_add_bus(&chan->adapter))
+               goto out_free;
+
+       /* JJJ:  raise SCL and SDA? */
+       set_data(chan, 1);
+       set_clock(chan, 1);
+       udelay(20);
+
+       return chan;
+
+out_free:
+       kfree(chan);
+       return NULL;
+}
+
+/**
+ * intel_i2c_destroy - unregister and free i2c bus resources
+ * @output: channel to free
+ *
+ * Unregister the adapter from the i2c layer, then free the structure.
+ */
+void intel_i2c_destroy(struct intel_i2c_chan *chan)
+{
+       if (!chan)
+               return;
+
+       i2c_del_adapter(&chan->adapter);
+       kfree(chan);
+}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
new file mode 100644 (file)
index 0000000..ccecfaf
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_edid.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/**
+ * Sets the backlight level.
+ *
+ * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
+ */
+static void intel_lvds_set_backlight(struct drm_device *dev, int level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 blc_pwm_ctl;
+
+       blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
+                                (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+}
+
+/**
+ * Returns the maximum level of the backlight duty cycle field.
+ */
+static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+               BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+}
+
+/**
+ * Sets the power state for the panel.
+ */
+static void intel_lvds_set_power(struct drm_device *dev, bool on)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp_status;
+
+       if (on) {
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
+                          POWER_TARGET_ON);
+               do {
+                       pp_status = I915_READ(PP_STATUS);
+               } while ((pp_status & PP_ON) == 0);
+
+               intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
+       } else {
+               intel_lvds_set_backlight(dev, 0);
+
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) &
+                          ~POWER_TARGET_ON);
+               do {
+                       pp_status = I915_READ(PP_STATUS);
+               } while (pp_status & PP_ON);
+       }
+}
+
+static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+
+       if (mode == DRM_MODE_DPMS_ON)
+               intel_lvds_set_power(dev, true);
+       else
+               intel_lvds_set_power(dev, false);
+
+       /* XXX: We never power down the LVDS pairs. */
+}
+
+static void intel_lvds_save(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS);
+       dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS);
+       dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
+       dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
+       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
+                                      BACKLIGHT_DUTY_CYCLE_MASK);
+
+       /*
+        * If the light is off at server startup, just make it full brightness
+        */
+       if (dev_priv->backlight_duty_cycle == 0)
+               dev_priv->backlight_duty_cycle =
+                       intel_lvds_get_max_backlight(dev);
+}
+
+static void intel_lvds_restore(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+       I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON);
+       I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF);
+       I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
+       I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+       if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
+               intel_lvds_set_power(dev, true);
+       else
+               intel_lvds_set_power(dev, false);
+}
+
+static int intel_lvds_mode_valid(struct drm_connector *connector,
+                                struct drm_display_mode *mode)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+
+       if (fixed_mode) {
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+
+       return MODE_OK;
+}
+
+static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       struct drm_encoder *tmp_encoder;
+
+       /* Should never happen!! */
+       if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+               printk(KERN_ERR "Can't support LVDS on pipe A\n");
+               return false;
+       }
+
+       /* Should never happen!! */
+       list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
+               if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) {
+                       printk(KERN_ERR "Can't enable LVDS and another "
+                              "encoder on the same pipe\n");
+                       return false;
+               }
+       }
+
+       /*
+        * If we have timings from the BIOS for the panel, put them in
+        * to the adjusted mode.  The CRTC will be set up for this mode,
+        * with the panel scaling set up to source from the H/VDisplay
+        * of the original mode.
+        */
+       if (dev_priv->panel_fixed_mode != NULL) {
+               adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay;
+               adjusted_mode->hsync_start =
+                       dev_priv->panel_fixed_mode->hsync_start;
+               adjusted_mode->hsync_end =
+                       dev_priv->panel_fixed_mode->hsync_end;
+               adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal;
+               adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay;
+               adjusted_mode->vsync_start =
+                       dev_priv->panel_fixed_mode->vsync_start;
+               adjusted_mode->vsync_end =
+                       dev_priv->panel_fixed_mode->vsync_end;
+               adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
+               adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
+               drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+       }
+
+       /*
+        * XXX: It would be nice to support lower refresh rates on the
+        * panels to reduce power consumption, and perhaps match the
+        * user's requested refresh rate.
+        */
+
+       return true;
+}
+
+static void intel_lvds_prepare(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
+                                      BACKLIGHT_DUTY_CYCLE_MASK);
+
+       intel_lvds_set_power(dev, false);
+}
+
+static void intel_lvds_commit( struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->backlight_duty_cycle == 0)
+               dev_priv->backlight_duty_cycle =
+                       intel_lvds_get_max_backlight(dev);
+
+       intel_lvds_set_power(dev, true);
+}
+
+static void intel_lvds_mode_set(struct drm_encoder *encoder,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+       u32 pfit_control;
+
+       /*
+        * The LVDS pin pair will already have been turned on in the
+        * intel_crtc_mode_set since it has a large impact on the DPLL
+        * settings.
+        */
+
+       /*
+        * Enable automatic panel scaling so that non-native modes fill the
+        * screen.  Should be enabled before the pipe is enabled, according to
+        * register description and PRM.
+        */
+       if (mode->hdisplay != adjusted_mode->hdisplay ||
+           mode->vdisplay != adjusted_mode->vdisplay)
+               pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
+                               HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
+                               HORIZ_INTERP_BILINEAR);
+       else
+               pfit_control = 0;
+
+       if (!IS_I965G(dev)) {
+               if (dev_priv->panel_wants_dither)
+                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+       }
+       else
+               pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
+
+       I915_WRITE(PFIT_CONTROL, pfit_control);
+}
+
+/**
+ * Detect the LVDS connection.
+ *
+ * This always returns CONNECTOR_STATUS_CONNECTED.  This connector should only have
+ * been set up if the LVDS was actually connected anyway.
+ */
+static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
+{
+       return connector_status_connected;
+}
+
+/**
+ * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
+ */
+static int intel_lvds_get_modes(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
+
+       ret = intel_ddc_get_modes(intel_output);
+
+       if (ret)
+               return ret;
+
+       /* Didn't get an EDID, so
+        * Set wide sync ranges so we get all modes
+        * handed to valid_mode for checking
+        */
+       connector->display_info.min_vfreq = 0;
+       connector->display_info.max_vfreq = 200;
+       connector->display_info.min_hfreq = 0;
+       connector->display_info.max_hfreq = 200;
+
+       if (dev_priv->panel_fixed_mode != NULL) {
+               struct drm_display_mode *mode;
+
+               mutex_unlock(&dev->mode_config.mutex);
+               mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
+               drm_mode_probed_add(connector, mode);
+               mutex_unlock(&dev->mode_config.mutex);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * intel_lvds_destroy - unregister and free LVDS structures
+ * @connector: connector to free
+ *
+ * Unregister the DDC bus for this connector then free the driver private
+ * structure.
+ */
+static void intel_lvds_destroy(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       if (intel_output->ddc_bus)
+               intel_i2c_destroy(intel_output->ddc_bus);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = {
+       .dpms = intel_lvds_dpms,
+       .mode_fixup = intel_lvds_mode_fixup,
+       .prepare = intel_lvds_prepare,
+       .mode_set = intel_lvds_mode_set,
+       .commit = intel_lvds_commit,
+};
+
+static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
+       .get_modes = intel_lvds_get_modes,
+       .mode_valid = intel_lvds_mode_valid,
+       .best_encoder = intel_best_encoder,
+};
+
+static const struct drm_connector_funcs intel_lvds_connector_funcs = {
+       .save = intel_lvds_save,
+       .restore = intel_lvds_restore,
+       .detect = intel_lvds_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = intel_lvds_destroy,
+};
+
+
+static void intel_lvds_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
+       .destroy = intel_lvds_enc_destroy,
+};
+
+
+
+/**
+ * intel_lvds_init - setup LVDS connectors on this device
+ * @dev: drm device
+ *
+ * Create the connector, register the LVDS DDC bus, and try to figure out what
+ * modes we can display on the LVDS panel (if present).
+ */
+void intel_lvds_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+       struct drm_display_mode *scan; /* *modes, *bios_mode; */
+       struct drm_crtc *crtc;
+       u32 lvds;
+       int pipe;
+
+       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output) {
+               return;
+       }
+
+       connector = &intel_output->base;
+       encoder = &intel_output->enc;
+       drm_connector_init(dev, &intel_output->base, &intel_lvds_connector_funcs,
+                          DRM_MODE_CONNECTOR_LVDS);
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_lvds_enc_funcs,
+                        DRM_MODE_ENCODER_LVDS);
+
+       drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
+       intel_output->type = INTEL_OUTPUT_LVDS;
+
+       drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
+       drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
+       connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+
+
+       /*
+        * LVDS discovery:
+        * 1) check for EDID on DDC
+        * 2) check for VBT data
+        * 3) check to see if LVDS is already on
+        *    if none of the above, no panel
+        * 4) make sure lid is open
+        *    if closed, act like it's not there for now
+        */
+
+       /* Set up the DDC bus. */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
+       if (!intel_output->ddc_bus) {
+               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
+                          "failed.\n");
+               goto failed;
+       }
+
+       /*
+        * Attempt to get the fixed panel mode from DDC.  Assume that the
+        * preferred mode is the right one.
+        */
+       intel_ddc_get_modes(intel_output);
+
+       list_for_each_entry(scan, &connector->probed_modes, head) {
+               mutex_lock(&dev->mode_config.mutex);
+               if (scan->type & DRM_MODE_TYPE_PREFERRED) {
+                       dev_priv->panel_fixed_mode =
+                               drm_mode_duplicate(dev, scan);
+                       mutex_unlock(&dev->mode_config.mutex);
+                       goto out; /* FIXME: check for quirks */
+               }
+               mutex_unlock(&dev->mode_config.mutex);
+       }
+
+       /* Failed to get EDID, what about VBT? */
+       if (dev_priv->vbt_mode) {
+               mutex_lock(&dev->mode_config.mutex);
+               dev_priv->panel_fixed_mode =
+                       drm_mode_duplicate(dev, dev_priv->vbt_mode);
+               mutex_unlock(&dev->mode_config.mutex);
+       }
+
+       /*
+        * If we didn't get EDID, try checking if the panel is already turned
+        * on.  If so, assume that whatever is currently programmed is the
+        * correct mode.
+        */
+       lvds = I915_READ(LVDS);
+       pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
+       crtc = intel_get_crtc_from_pipe(dev, pipe);
+
+       if (crtc && (lvds & LVDS_PORT_EN)) {
+               dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
+               if (dev_priv->panel_fixed_mode) {
+                       dev_priv->panel_fixed_mode->type |=
+                               DRM_MODE_TYPE_PREFERRED;
+                       goto out; /* FIXME: check for quirks */
+               }
+       }
+
+       /* If we still don't have a mode after all that, give up. */
+       if (!dev_priv->panel_fixed_mode)
+               goto failed;
+
+       /* FIXME: detect aopen & mac mini type stuff automatically? */
+       /*
+        * Blacklist machines with BIOSes that list an LVDS panel without
+        * actually having one.
+        */
+       if (IS_I945GM(dev)) {
+               /* aopen mini pc */
+               if (dev->pdev->subsystem_vendor == 0xa0a0)
+                       goto failed;
+
+               if ((dev->pdev->subsystem_vendor == 0x8086) &&
+                   (dev->pdev->subsystem_device == 0x7270)) {
+                       /* It's a Mac Mini or Macbook Pro.
+                        *
+                        * Apple hardware is out to get us.  The macbook pro
+                        * has a real LVDS panel, but the mac mini does not,
+                        * and they have the same device IDs.  We'll
+                        * distinguish by panel size, on the assumption
+                        * that Apple isn't about to make any machines with an
+                        * 800x600 display.
+                        */
+
+                       if (dev_priv->panel_fixed_mode != NULL &&
+                           dev_priv->panel_fixed_mode->hdisplay == 800 &&
+                           dev_priv->panel_fixed_mode->vdisplay == 600) {
+                               DRM_DEBUG("Suspected Mac Mini, ignoring the LVDS\n");
+                               goto failed;
+                       }
+               }
+       }
+
+
+out:
+       drm_sysfs_connector_add(connector);
+       return;
+
+failed:
+       DRM_DEBUG("No LVDS modes found, disabling.\n");
+       if (intel_output->ddc_bus)
+               intel_i2c_destroy(intel_output->ddc_bus);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
new file mode 100644 (file)
index 0000000..e42019e
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include "drmP.h"
+#include "intel_drv.h"
+
+/**
+ * intel_ddc_probe
+ *
+ */
+bool intel_ddc_probe(struct intel_output *intel_output)
+{
+       u8 out_buf[] = { 0x0, 0x0};
+       u8 buf[2];
+       int ret;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0x50,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = 0x50,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
+       if (ret == 2)
+               return true;
+
+       return false;
+}
+
+/**
+ * intel_ddc_get_modes - get modelist from monitor
+ * @connector: DRM connector device to use
+ *
+ * Fetch the EDID information from @connector using the DDC bus.
+ */
+int intel_ddc_get_modes(struct intel_output *intel_output)
+{
+       struct edid *edid;
+       int ret = 0;
+
+       edid = drm_get_edid(&intel_output->base,
+                           &intel_output->ddc_bus->adapter);
+       if (edid) {
+               drm_mode_connector_update_edid_property(&intel_output->base,
+                                                       edid);
+               ret = drm_add_edid_modes(&intel_output->base, edid);
+               kfree(edid);
+       }
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
new file mode 100644 (file)
index 0000000..fbbaa4f
--- /dev/null
@@ -0,0 +1,1128 @@
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright Â© 2006-2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_sdvo_regs.h"
+
+#undef SDVO_DEBUG
+
+struct intel_sdvo_priv {
+       struct intel_i2c_chan *i2c_bus;
+       int slaveaddr;
+       int output_device;
+
+       u16 active_outputs;
+
+       struct intel_sdvo_caps caps;
+       int pixel_clock_min, pixel_clock_max;
+
+       int save_sdvo_mult;
+       u16 save_active_outputs;
+       struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
+       struct intel_sdvo_dtd save_output_dtd[16];
+       u32 save_SDVOX;
+};
+
+/**
+ * Writes the SDVOB or SDVOC with the given value, but always writes both
+ * SDVOB and SDVOC to work around apparent hardware issues (according to
+ * comments in the BIOS).
+ */
+static void intel_sdvo_write_sdvox(struct intel_output *intel_output, u32 val)
+{
+       struct drm_device *dev = intel_output->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_sdvo_priv   *sdvo_priv = intel_output->dev_priv;
+       u32 bval = val, cval = val;
+       int i;
+
+       if (sdvo_priv->output_device == SDVOB) {
+               cval = I915_READ(SDVOC);
+       } else {
+               bval = I915_READ(SDVOB);
+       }
+       /*
+        * Write the registers twice for luck. Sometimes,
+        * writing them only once doesn't appear to 'stick'.
+        * The BIOS does this too. Yay, magic
+        */
+       for (i = 0; i < 2; i++)
+       {
+               I915_WRITE(SDVOB, bval);
+               I915_READ(SDVOB);
+               I915_WRITE(SDVOC, cval);
+               I915_READ(SDVOC);
+       }
+}
+
+static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
+                                u8 *ch)
+{
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u8 out_buf[2];
+       u8 buf[2];
+       int ret;
+
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2)
+       {
+               *ch = buf[0];
+               return true;
+       }
+
+       DRM_DEBUG("i2c transfer returned %d\n", ret);
+       return false;
+}
+
+static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
+                                 u8 ch)
+{
+       u8 out_buf[2];
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = intel_output->i2c_bus->slave_addr,
+                       .flags = 0,
+                       .len = 2,
+                       .buf = out_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1)
+       {
+               return true;
+       }
+       return false;
+}
+
+#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
+/** Mapping of command numbers to names, for debug output */
+const static struct _sdvo_cmd_name {
+    u8 cmd;
+    char *name;
+} sdvo_cmd_names[] = {
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
+};
+
+#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
+#define SDVO_PRIV(output)   ((struct intel_sdvo_priv *) (output)->dev_priv)
+
+#ifdef SDVO_DEBUG
+static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
+                                  void *args, int args_len)
+{
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int i;
+
+       DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
+       for (i = 0; i < args_len; i++)
+               printk("%02X ", ((u8 *)args)[i]);
+       for (; i < 8; i++)
+               printk("   ");
+       for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
+               if (cmd == sdvo_cmd_names[i].cmd) {
+                       printk("(%s)", sdvo_cmd_names[i].name);
+                       break;
+               }
+       }
+       if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
+               printk("(%02X)",cmd);
+       printk("\n");
+}
+#else
+#define intel_sdvo_debug_write(o, c, a, l)
+#endif
+
+static void intel_sdvo_write_cmd(struct intel_output *intel_output, u8 cmd,
+                                void *args, int args_len)
+{
+       int i;
+
+       intel_sdvo_debug_write(intel_output, cmd, args, args_len);
+
+       for (i = 0; i < args_len; i++) {
+               intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0 - i,
+                                     ((u8*)args)[i]);
+       }
+
+       intel_sdvo_write_byte(intel_output, SDVO_I2C_OPCODE, cmd);
+}
+
+#ifdef SDVO_DEBUG
+static const char *cmd_status_names[] = {
+       "Power on",
+       "Success",
+       "Not supported",
+       "Invalid arg",
+       "Pending",
+       "Target not specified",
+       "Scaling not supported"
+};
+
+static void intel_sdvo_debug_response(struct intel_output *intel_output,
+                                     void *response, int response_len,
+                                     u8 status)
+{
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+       DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv));
+       for (i = 0; i < response_len; i++)
+               printk("%02X ", ((u8 *)response)[i]);
+       for (; i < 8; i++)
+               printk("   ");
+       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+               printk("(%s)", cmd_status_names[status]);
+       else
+               printk("(??? %d)", status);
+       printk("\n");
+}
+#else
+#define intel_sdvo_debug_response(o, r, l, s)
+#endif
+
+static u8 intel_sdvo_read_response(struct intel_output *intel_output,
+                                  void *response, int response_len)
+{
+       int i;
+       u8 status;
+       u8 retry = 50;
+
+       while (retry--) {
+               /* Read the command response */
+               for (i = 0; i < response_len; i++) {
+                       intel_sdvo_read_byte(intel_output,
+                                            SDVO_I2C_RETURN_0 + i,
+                                            &((u8 *)response)[i]);
+               }
+
+               /* read the return status */
+               intel_sdvo_read_byte(intel_output, SDVO_I2C_CMD_STATUS,
+                                    &status);
+
+               intel_sdvo_debug_response(intel_output, response, response_len,
+                                         status);
+               if (status != SDVO_CMD_STATUS_PENDING)
+                       return status;
+
+               mdelay(50);
+       }
+
+       return status;
+}
+
+static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
+{
+       if (mode->clock >= 100000)
+               return 1;
+       else if (mode->clock >= 50000)
+               return 2;
+       else
+               return 4;
+}
+
+/**
+ * Don't check status code from this as it switches the bus back to the
+ * SDVO chips which defeats the purpose of doing a bus switch in the first
+ * place.
+ */
+static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output,
+                                             u8 target)
+{
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
+}
+
+static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1)
+{
+       struct intel_sdvo_set_target_input_args targets = {0};
+       u8 status;
+
+       if (target_0 && target_1)
+               return SDVO_CMD_STATUS_NOTSUPP;
+
+       if (target_1)
+               targets.target_1 = 1;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_INPUT, &targets,
+                            sizeof(targets));
+
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+/**
+ * Return whether each input is trained.
+ *
+ * This function is making an assumption about the layout of the response,
+ * which should be checked against the docs.
+ */
+static bool intel_sdvo_get_trained_inputs(struct intel_output *intel_output, bool *input_1, bool *input_2)
+{
+       struct intel_sdvo_get_trained_inputs_response response;
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &response, sizeof(response));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       *input_1 = response.input0_trained;
+       *input_2 = response.input1_trained;
+       return true;
+}
+
+static bool intel_sdvo_get_active_outputs(struct intel_output *intel_output,
+                                         u16 *outputs)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, outputs, sizeof(*outputs));
+
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_active_outputs(struct intel_output *intel_output,
+                                         u16 outputs)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs,
+                            sizeof(outputs));
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output,
+                                              int mode)
+{
+       u8 status, state = SDVO_ENCODER_STATE_ON;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               state = SDVO_ENCODER_STATE_ON;
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+               state = SDVO_ENCODER_STATE_STANDBY;
+               break;
+       case DRM_MODE_DPMS_SUSPEND:
+               state = SDVO_ENCODER_STATE_SUSPEND;
+               break;
+       case DRM_MODE_DPMS_OFF:
+               state = SDVO_ENCODER_STATE_OFF;
+               break;
+       }
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state,
+                            sizeof(state));
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_get_input_pixel_clock_range(struct intel_output *intel_output,
+                                                  int *clock_min,
+                                                  int *clock_max)
+{
+       struct intel_sdvo_pixel_clock_range clocks;
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
+                            NULL, 0);
+
+       status = intel_sdvo_read_response(intel_output, &clocks, sizeof(clocks));
+
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       /* Convert the values from units of 10 kHz to kHz. */
+       *clock_min = clocks.min * 10;
+       *clock_max = clocks.max * 10;
+
+       return true;
+}
+
+static bool intel_sdvo_set_target_output(struct intel_output *intel_output,
+                                        u16 outputs)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs,
+                            sizeof(outputs));
+
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_get_timing(struct intel_output *intel_output, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, cmd, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &dtd->part1,
+                                         sizeof(dtd->part1));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       intel_sdvo_write_cmd(intel_output, cmd + 1, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &dtd->part2,
+                                         sizeof(dtd->part2));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_get_input_timing(struct intel_output *intel_output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(intel_output,
+                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_get_output_timing(struct intel_output *intel_output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(intel_output,
+                                    SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_timing(struct intel_output *intel_output, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, cmd, &dtd->part1, sizeof(dtd->part1));
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       intel_sdvo_write_cmd(intel_output, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_set_input_timing(struct intel_output *intel_output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_timing(intel_output,
+                                    SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_output_timing(struct intel_output *intel_output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_timing(intel_output,
+                                    SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+
+static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output)
+{
+       u8 response, status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &response, 1);
+
+       if (status != SDVO_CMD_STATUS_SUCCESS) {
+               DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n");
+               return SDVO_CLOCK_RATE_MULT_1X;
+       } else {
+               DRM_DEBUG("Current clock rate multiplier: %d\n", response);
+       }
+
+       return response;
+}
+
+static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 val)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
+       status = intel_sdvo_read_response(intel_output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       /* Make the CRTC code factor in the SDVO pixel multiplier.  The SDVO
+        * device will be told of the multiplier during mode_set.
+        */
+       adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+       return true;
+}
+
+static void intel_sdvo_mode_set(struct drm_encoder *encoder,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u16 width, height;
+       u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+       u16 h_sync_offset, v_sync_offset;
+       u32 sdvox;
+       struct intel_sdvo_dtd output_dtd;
+       int sdvo_pixel_multiply;
+
+       if (!mode)
+               return;
+
+       width = mode->crtc_hdisplay;
+       height = mode->crtc_vdisplay;
+
+       /* do some mode translations */
+       h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
+       h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+
+       v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
+       v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+
+       h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
+       v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+
+       output_dtd.part1.clock = mode->clock / 10;
+       output_dtd.part1.h_active = width & 0xff;
+       output_dtd.part1.h_blank = h_blank_len & 0xff;
+       output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) |
+               ((h_blank_len >> 8) & 0xf);
+       output_dtd.part1.v_active = height & 0xff;
+       output_dtd.part1.v_blank = v_blank_len & 0xff;
+       output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) |
+               ((v_blank_len >> 8) & 0xf);
+
+       output_dtd.part2.h_sync_off = h_sync_offset;
+       output_dtd.part2.h_sync_width = h_sync_len & 0xff;
+       output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
+               (v_sync_len & 0xf);
+       output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
+               ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
+               ((v_sync_len & 0x30) >> 4);
+
+       output_dtd.part2.dtd_flags = 0x18;
+       if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+               output_dtd.part2.dtd_flags |= 0x2;
+       if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+               output_dtd.part2.dtd_flags |= 0x4;
+
+       output_dtd.part2.sdvo_flags = 0;
+       output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0;
+       output_dtd.part2.reserved = 0;
+
+       /* Set the output timing to the screen */
+       intel_sdvo_set_target_output(intel_output, sdvo_priv->active_outputs);
+       intel_sdvo_set_output_timing(intel_output, &output_dtd);
+
+       /* Set the input timing to the screen. Assume always input 0. */
+       intel_sdvo_set_target_input(intel_output, true, false);
+
+       /* We would like to use i830_sdvo_create_preferred_input_timing() to
+        * provide the device with a timing it can support, if it supports that
+        * feature.  However, presumably we would need to adjust the CRTC to
+        * output the preferred timing, and we don't support that currently.
+        */
+       intel_sdvo_set_input_timing(intel_output, &output_dtd);
+
+       switch (intel_sdvo_get_pixel_multiplier(mode)) {
+       case 1:
+               intel_sdvo_set_clock_rate_mult(intel_output,
+                                              SDVO_CLOCK_RATE_MULT_1X);
+               break;
+       case 2:
+               intel_sdvo_set_clock_rate_mult(intel_output,
+                                              SDVO_CLOCK_RATE_MULT_2X);
+               break;
+       case 4:
+               intel_sdvo_set_clock_rate_mult(intel_output,
+                                              SDVO_CLOCK_RATE_MULT_4X);
+               break;
+       }
+
+       /* Set the SDVO control regs. */
+        if (0/*IS_I965GM(dev)*/) {
+                sdvox = SDVO_BORDER_ENABLE;
+        } else {
+                sdvox = I915_READ(sdvo_priv->output_device);
+                switch (sdvo_priv->output_device) {
+                case SDVOB:
+                        sdvox &= SDVOB_PRESERVE_MASK;
+                        break;
+                case SDVOC:
+                        sdvox &= SDVOC_PRESERVE_MASK;
+                        break;
+                }
+                sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
+        }
+       if (intel_crtc->pipe == 1)
+               sdvox |= SDVO_PIPE_B_SELECT;
+
+       sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
+       if (IS_I965G(dev)) {
+               /* done in crtc_mode_set as the dpll_md reg must be written
+                  early */
+       } else if (IS_I945G(dev) || IS_I945GM(dev)) {
+               /* done in crtc_mode_set as it lives inside the
+                  dpll register */
+       } else {
+               sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+       }
+
+       intel_sdvo_write_sdvox(intel_output, sdvox);
+}
+
+static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u32 temp;
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               intel_sdvo_set_active_outputs(intel_output, 0);
+               if (0)
+                       intel_sdvo_set_encoder_power_state(intel_output, mode);
+
+               if (mode == DRM_MODE_DPMS_OFF) {
+                       temp = I915_READ(sdvo_priv->output_device);
+                       if ((temp & SDVO_ENABLE) != 0) {
+                               intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE);
+                       }
+               }
+       } else {
+               bool input1, input2;
+               int i;
+               u8 status;
+
+               temp = I915_READ(sdvo_priv->output_device);
+               if ((temp & SDVO_ENABLE) == 0)
+                       intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE);
+               for (i = 0; i < 2; i++)
+                 intel_wait_for_vblank(dev);
+
+               status = intel_sdvo_get_trained_inputs(intel_output, &input1,
+                                                      &input2);
+
+
+               /* Warn if the device reported failure to sync.
+                * A lot of SDVO devices fail to notify of sync, but it's
+                * a given it the status is a success, we succeeded.
+                */
+               if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+                       DRM_DEBUG("First %s output reported failure to sync\n",
+                                  SDVO_NAME(sdvo_priv));
+               }
+
+               if (0)
+                       intel_sdvo_set_encoder_power_state(intel_output, mode);
+               intel_sdvo_set_active_outputs(intel_output, sdvo_priv->active_outputs);
+       }
+       return;
+}
+
+static void intel_sdvo_save(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int o;
+
+       sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_output);
+       intel_sdvo_get_active_outputs(intel_output, &sdvo_priv->save_active_outputs);
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+               intel_sdvo_set_target_input(intel_output, true, false);
+               intel_sdvo_get_input_timing(intel_output,
+                                           &sdvo_priv->save_input_dtd_1);
+       }
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+               intel_sdvo_set_target_input(intel_output, false, true);
+               intel_sdvo_get_input_timing(intel_output,
+                                           &sdvo_priv->save_input_dtd_2);
+       }
+
+       for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
+       {
+               u16  this_output = (1 << o);
+               if (sdvo_priv->caps.output_flags & this_output)
+               {
+                       intel_sdvo_set_target_output(intel_output, this_output);
+                       intel_sdvo_get_output_timing(intel_output,
+                                                    &sdvo_priv->save_output_dtd[o]);
+               }
+       }
+
+       sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
+}
+
+static void intel_sdvo_restore(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int o;
+       int i;
+       bool input1, input2;
+       u8 status;
+
+       intel_sdvo_set_active_outputs(intel_output, 0);
+
+       for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
+       {
+               u16  this_output = (1 << o);
+               if (sdvo_priv->caps.output_flags & this_output) {
+                       intel_sdvo_set_target_output(intel_output, this_output);
+                       intel_sdvo_set_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]);
+               }
+       }
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+               intel_sdvo_set_target_input(intel_output, true, false);
+               intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_1);
+       }
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+               intel_sdvo_set_target_input(intel_output, false, true);
+               intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_2);
+       }
+
+       intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult);
+
+       I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX);
+
+       if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
+       {
+               for (i = 0; i < 2; i++)
+                       intel_wait_for_vblank(dev);
+               status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2);
+               if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
+                       DRM_DEBUG("First %s output reported failure to sync\n",
+                                  SDVO_NAME(sdvo_priv));
+       }
+
+       intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs);
+}
+
+static int intel_sdvo_mode_valid(struct drm_connector *connector,
+                                struct drm_display_mode *mode)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (sdvo_priv->pixel_clock_min > mode->clock)
+               return MODE_CLOCK_LOW;
+
+       if (sdvo_priv->pixel_clock_max < mode->clock)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static bool intel_sdvo_get_capabilities(struct intel_output *intel_output, struct intel_sdvo_caps *caps)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, caps, sizeof(*caps));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
+{
+       struct drm_connector *connector = NULL;
+       struct intel_output *iout = NULL;
+       struct intel_sdvo_priv *sdvo;
+
+       /* find the sdvo connector */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               iout = to_intel_output(connector);
+
+               if (iout->type != INTEL_OUTPUT_SDVO)
+                       continue;
+
+               sdvo = iout->dev_priv;
+
+               if (sdvo->output_device == SDVOB && sdvoB)
+                       return connector;
+
+               if (sdvo->output_device == SDVOC && !sdvoB)
+                       return connector;
+
+       }
+
+       return NULL;
+}
+
+int intel_sdvo_supports_hotplug(struct drm_connector *connector)
+{
+       u8 response[2];
+       u8 status;
+       struct intel_output *intel_output;
+       DRM_DEBUG("\n");
+
+       if (!connector)
+               return 0;
+
+       intel_output = to_intel_output(connector);
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &response, 2);
+
+       if (response[0] !=0)
+               return 1;
+
+       return 0;
+}
+
+void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
+{
+       u8 response[2];
+       u8 status;
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+       intel_sdvo_read_response(intel_output, &response, 2);
+
+       if (on) {
+               intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+               status = intel_sdvo_read_response(intel_output, &response, 2);
+
+               intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+       } else {
+               response[0] = 0;
+               response[1] = 0;
+               intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+       }
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+       intel_sdvo_read_response(intel_output, &response, 2);
+}
+
+static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
+{
+       u8 response[2];
+       u8 status;
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+       status = intel_sdvo_read_response(intel_output, &response, 2);
+
+       DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]);
+       if ((response[0] != 0) || (response[1] != 0))
+               return connector_status_connected;
+       else
+               return connector_status_disconnected;
+}
+
+static int intel_sdvo_get_modes(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       /* set the bus switch and get the modes */
+       intel_sdvo_set_control_bus_switch(intel_output, SDVO_CONTROL_BUS_DDC2);
+       intel_ddc_get_modes(intel_output);
+
+       if (list_empty(&connector->probed_modes))
+               return 0;
+       return 1;
+}
+
+static void intel_sdvo_destroy(struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       if (intel_output->i2c_bus)
+               intel_i2c_destroy(intel_output->i2c_bus);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(intel_output);
+}
+
+static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
+       .dpms = intel_sdvo_dpms,
+       .mode_fixup = intel_sdvo_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .mode_set = intel_sdvo_mode_set,
+       .commit = intel_encoder_commit,
+};
+
+static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
+       .save = intel_sdvo_save,
+       .restore = intel_sdvo_restore,
+       .detect = intel_sdvo_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = intel_sdvo_destroy,
+};
+
+static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
+       .get_modes = intel_sdvo_get_modes,
+       .mode_valid = intel_sdvo_mode_valid,
+       .best_encoder = intel_best_encoder,
+};
+
+static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
+       .destroy = intel_sdvo_enc_destroy,
+};
+
+
+void intel_sdvo_init(struct drm_device *dev, int output_device)
+{
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+       struct intel_sdvo_priv *sdvo_priv;
+       struct intel_i2c_chan *i2cbus = NULL;
+       int connector_type;
+       u8 ch[0x40];
+       int i;
+       int encoder_type, output_id;
+
+       intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
+       if (!intel_output) {
+               return;
+       }
+
+       connector = &intel_output->base;
+
+       drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
+                          DRM_MODE_CONNECTOR_Unknown);
+       drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+       sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
+       intel_output->type = INTEL_OUTPUT_SDVO;
+
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       /* setup the DDC bus. */
+       if (output_device == SDVOB)
+               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+       else
+               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+
+       if (!i2cbus)
+               goto err_connector;
+
+       sdvo_priv->i2c_bus = i2cbus;
+
+       if (output_device == SDVOB) {
+               output_id = 1;
+               sdvo_priv->i2c_bus->slave_addr = 0x38;
+       } else {
+               output_id = 2;
+               sdvo_priv->i2c_bus->slave_addr = 0x39;
+       }
+
+       sdvo_priv->output_device = output_device;
+       intel_output->i2c_bus = i2cbus;
+       intel_output->dev_priv = sdvo_priv;
+
+
+       /* Read the regs to test if we can talk to the device */
+       for (i = 0; i < 0x40; i++) {
+               if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
+                       DRM_DEBUG("No SDVO device found on SDVO%c\n",
+                                 output_device == SDVOB ? 'B' : 'C');
+                       goto err_i2c;
+               }
+       }
+
+       intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
+
+       memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs));
+
+       /* TODO, CVBS, SVID, YPRPB & SCART outputs. */
+       if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
+               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+               encoder_type = DRM_MODE_ENCODER_DAC;
+               connector_type = DRM_MODE_CONNECTOR_VGA;
+       }
+       else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
+               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+               encoder_type = DRM_MODE_ENCODER_DAC;
+               connector_type = DRM_MODE_CONNECTOR_VGA;
+       }
+       else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+               encoder_type = DRM_MODE_ENCODER_TMDS;
+               connector_type = DRM_MODE_CONNECTOR_DVID;
+       }
+       else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1;
+               connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+               encoder_type = DRM_MODE_ENCODER_TMDS;
+               connector_type = DRM_MODE_CONNECTOR_DVID;
+       }
+       else
+       {
+               unsigned char bytes[2];
+
+               memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
+               DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n",
+                         SDVO_NAME(sdvo_priv),
+                         bytes[0], bytes[1]);
+               goto err_i2c;
+       }
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type);
+       drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
+       connector->connector_type = connector_type;
+
+       drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
+       drm_sysfs_connector_add(connector);
+
+       /* Set the input timing to the screen. Assume always input 0. */
+       intel_sdvo_set_target_input(intel_output, true, false);
+
+       intel_sdvo_get_input_pixel_clock_range(intel_output,
+                                              &sdvo_priv->pixel_clock_min,
+                                              &sdvo_priv->pixel_clock_max);
+
+
+       DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, "
+                 "clock range %dMHz - %dMHz, "
+                 "input 1: %c, input 2: %c, "
+                 "output 1: %c, output 2: %c\n",
+                 SDVO_NAME(sdvo_priv),
+                 sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
+                 sdvo_priv->caps.device_rev_id,
+                 sdvo_priv->pixel_clock_min / 1000,
+                 sdvo_priv->pixel_clock_max / 1000,
+                 (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+                 (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+                 /* check currently supported outputs */
+                 sdvo_priv->caps.output_flags &
+                       (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
+                 sdvo_priv->caps.output_flags &
+                       (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
+
+       intel_output->ddc_bus = i2cbus;
+
+       return;
+
+err_i2c:
+       intel_i2c_destroy(intel_output->i2c_bus);
+err_connector:
+       drm_connector_cleanup(connector);
+       kfree(intel_output);
+
+       return;
+}
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h
new file mode 100644 (file)
index 0000000..861a43f
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+/**
+ * @file SDVO command definitions and structures.
+ */
+
+#define SDVO_OUTPUT_FIRST   (0)
+#define SDVO_OUTPUT_TMDS0   (1 << 0)
+#define SDVO_OUTPUT_RGB0    (1 << 1)
+#define SDVO_OUTPUT_CVBS0   (1 << 2)
+#define SDVO_OUTPUT_SVID0   (1 << 3)
+#define SDVO_OUTPUT_YPRPB0  (1 << 4)
+#define SDVO_OUTPUT_SCART0  (1 << 5)
+#define SDVO_OUTPUT_LVDS0   (1 << 6)
+#define SDVO_OUTPUT_TMDS1   (1 << 8)
+#define SDVO_OUTPUT_RGB1    (1 << 9)
+#define SDVO_OUTPUT_CVBS1   (1 << 10)
+#define SDVO_OUTPUT_SVID1   (1 << 11)
+#define SDVO_OUTPUT_YPRPB1  (1 << 12)
+#define SDVO_OUTPUT_SCART1  (1 << 13)
+#define SDVO_OUTPUT_LVDS1   (1 << 14)
+#define SDVO_OUTPUT_LAST    (14)
+
+struct intel_sdvo_caps {
+    u8 vendor_id;
+    u8 device_id;
+    u8 device_rev_id;
+    u8 sdvo_version_major;
+    u8 sdvo_version_minor;
+    unsigned int sdvo_inputs_mask:2;
+    unsigned int smooth_scaling:1;
+    unsigned int sharp_scaling:1;
+    unsigned int up_scaling:1;
+    unsigned int down_scaling:1;
+    unsigned int stall_support:1;
+    unsigned int pad:1;
+    u16 output_flags;
+} __attribute__((packed));
+
+/** This matches the EDID DTD structure, more or less */
+struct intel_sdvo_dtd {
+    struct {
+       u16 clock;              /**< pixel clock, in 10kHz units */
+       u8 h_active;            /**< lower 8 bits (pixels) */
+       u8 h_blank;             /**< lower 8 bits (pixels) */
+       u8 h_high;              /**< upper 4 bits each h_active, h_blank */
+       u8 v_active;            /**< lower 8 bits (lines) */
+       u8 v_blank;             /**< lower 8 bits (lines) */
+       u8 v_high;              /**< upper 4 bits each v_active, v_blank */
+    } part1;
+
+    struct {
+       u8 h_sync_off;  /**< lower 8 bits, from hblank start */
+       u8 h_sync_width;        /**< lower 8 bits (pixels) */
+       /** lower 4 bits each vsync offset, vsync width */
+       u8 v_sync_off_width;
+       /**
+        * 2 high bits of hsync offset, 2 high bits of hsync width,
+        * bits 4-5 of vsync offset, and 2 high bits of vsync width.
+        */
+       u8 sync_off_width_high;
+       u8 dtd_flags;
+       u8 sdvo_flags;
+       /** bits 6-7 of vsync offset at bits 6-7 */
+       u8 v_sync_off_high;
+       u8 reserved;
+    } part2;
+} __attribute__((packed));
+
+struct intel_sdvo_pixel_clock_range {
+    u16 min;                   /**< pixel clock, in 10kHz units */
+    u16 max;                   /**< pixel clock, in 10kHz units */
+} __attribute__((packed));
+
+struct intel_sdvo_preferred_input_timing_args {
+    u16 clock;
+    u16 width;
+    u16 height;
+} __attribute__((packed));
+
+/* I2C registers for SDVO */
+#define SDVO_I2C_ARG_0                         0x07
+#define SDVO_I2C_ARG_1                         0x06
+#define SDVO_I2C_ARG_2                         0x05
+#define SDVO_I2C_ARG_3                         0x04
+#define SDVO_I2C_ARG_4                         0x03
+#define SDVO_I2C_ARG_5                         0x02
+#define SDVO_I2C_ARG_6                         0x01
+#define SDVO_I2C_ARG_7                         0x00
+#define SDVO_I2C_OPCODE                                0x08
+#define SDVO_I2C_CMD_STATUS                    0x09
+#define SDVO_I2C_RETURN_0                      0x0a
+#define SDVO_I2C_RETURN_1                      0x0b
+#define SDVO_I2C_RETURN_2                      0x0c
+#define SDVO_I2C_RETURN_3                      0x0d
+#define SDVO_I2C_RETURN_4                      0x0e
+#define SDVO_I2C_RETURN_5                      0x0f
+#define SDVO_I2C_RETURN_6                      0x10
+#define SDVO_I2C_RETURN_7                      0x11
+#define SDVO_I2C_VENDOR_BEGIN                  0x20
+
+/* Status results */
+#define SDVO_CMD_STATUS_POWER_ON               0x0
+#define SDVO_CMD_STATUS_SUCCESS                        0x1
+#define SDVO_CMD_STATUS_NOTSUPP                        0x2
+#define SDVO_CMD_STATUS_INVALID_ARG            0x3
+#define SDVO_CMD_STATUS_PENDING                        0x4
+#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED   0x5
+#define SDVO_CMD_STATUS_SCALING_NOT_SUPP       0x6
+
+/* SDVO commands, argument/result registers */
+
+#define SDVO_CMD_RESET                                 0x01
+
+/** Returns a struct intel_sdvo_caps */
+#define SDVO_CMD_GET_DEVICE_CAPS                       0x02
+
+#define SDVO_CMD_GET_FIRMWARE_REV                      0x86
+# define SDVO_DEVICE_FIRMWARE_MINOR                    SDVO_I2C_RETURN_0
+# define SDVO_DEVICE_FIRMWARE_MAJOR                    SDVO_I2C_RETURN_1
+# define SDVO_DEVICE_FIRMWARE_PATCH                    SDVO_I2C_RETURN_2
+
+/**
+ * Reports which inputs are trained (managed to sync).
+ *
+ * Devices must have trained within 2 vsyncs of a mode change.
+ */
+#define SDVO_CMD_GET_TRAINED_INPUTS                    0x03
+struct intel_sdvo_get_trained_inputs_response {
+    unsigned int input0_trained:1;
+    unsigned int input1_trained:1;
+    unsigned int pad:6;
+} __attribute__((packed));
+
+/** Returns a struct intel_sdvo_output_flags of active outputs. */
+#define SDVO_CMD_GET_ACTIVE_OUTPUTS                    0x04
+
+/**
+ * Sets the current set of active outputs.
+ *
+ * Takes a struct intel_sdvo_output_flags.  Must be preceded by a SET_IN_OUT_MAP
+ * on multi-output devices.
+ */
+#define SDVO_CMD_SET_ACTIVE_OUTPUTS                    0x05
+
+/**
+ * Returns the current mapping of SDVO inputs to outputs on the device.
+ *
+ * Returns two struct intel_sdvo_output_flags structures.
+ */
+#define SDVO_CMD_GET_IN_OUT_MAP                                0x06
+
+/**
+ * Sets the current mapping of SDVO inputs to outputs on the device.
+ *
+ * Takes two struct i380_sdvo_output_flags structures.
+ */
+#define SDVO_CMD_SET_IN_OUT_MAP                                0x07
+
+/**
+ * Returns a struct intel_sdvo_output_flags of attached displays.
+ */
+#define SDVO_CMD_GET_ATTACHED_DISPLAYS                 0x0b
+
+/**
+ * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging.
+ */
+#define SDVO_CMD_GET_HOT_PLUG_SUPPORT                  0x0c
+
+/**
+ * Takes a struct intel_sdvo_output_flags.
+ */
+#define SDVO_CMD_SET_ACTIVE_HOT_PLUG                   0x0d
+
+/**
+ * Returns a struct intel_sdvo_output_flags of displays with hot plug
+ * interrupts enabled.
+ */
+#define SDVO_CMD_GET_ACTIVE_HOT_PLUG                   0x0e
+
+#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE            0x0f
+struct intel_sdvo_get_interrupt_event_source_response {
+    u16 interrupt_status;
+    unsigned int ambient_light_interrupt:1;
+    unsigned int pad:7;
+} __attribute__((packed));
+
+/**
+ * Selects which input is affected by future input commands.
+ *
+ * Commands affected include SET_INPUT_TIMINGS_PART[12],
+ * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12],
+ * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS.
+ */
+#define SDVO_CMD_SET_TARGET_INPUT                      0x10
+struct intel_sdvo_set_target_input_args {
+    unsigned int target_1:1;
+    unsigned int pad:7;
+} __attribute__((packed));
+
+/**
+ * Takes a struct intel_sdvo_output_flags of which outputs are targetted by
+ * future output commands.
+ *
+ * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12],
+ * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE.
+ */
+#define SDVO_CMD_SET_TARGET_OUTPUT                     0x11
+
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART1               0x12
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART2               0x13
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART1               0x14
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART2               0x15
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1              0x16
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2              0x17
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1              0x18
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2              0x19
+/* Part 1 */
+# define SDVO_DTD_CLOCK_LOW                            SDVO_I2C_ARG_0
+# define SDVO_DTD_CLOCK_HIGH                           SDVO_I2C_ARG_1
+# define SDVO_DTD_H_ACTIVE                             SDVO_I2C_ARG_2
+# define SDVO_DTD_H_BLANK                              SDVO_I2C_ARG_3
+# define SDVO_DTD_H_HIGH                               SDVO_I2C_ARG_4
+# define SDVO_DTD_V_ACTIVE                             SDVO_I2C_ARG_5
+# define SDVO_DTD_V_BLANK                              SDVO_I2C_ARG_6
+# define SDVO_DTD_V_HIGH                               SDVO_I2C_ARG_7
+/* Part 2 */
+# define SDVO_DTD_HSYNC_OFF                            SDVO_I2C_ARG_0
+# define SDVO_DTD_HSYNC_WIDTH                          SDVO_I2C_ARG_1
+# define SDVO_DTD_VSYNC_OFF_WIDTH                      SDVO_I2C_ARG_2
+# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH                  SDVO_I2C_ARG_3
+# define SDVO_DTD_DTD_FLAGS                            SDVO_I2C_ARG_4
+# define SDVO_DTD_DTD_FLAG_INTERLACED                          (1 << 7)
+# define SDVO_DTD_DTD_FLAG_STEREO_MASK                         (3 << 5)
+# define SDVO_DTD_DTD_FLAG_INPUT_MASK                          (3 << 3)
+# define SDVO_DTD_DTD_FLAG_SYNC_MASK                           (3 << 1)
+# define SDVO_DTD_SDVO_FLAS                            SDVO_I2C_ARG_5
+# define SDVO_DTD_SDVO_FLAG_STALL                              (1 << 7)
+# define SDVO_DTD_SDVO_FLAG_CENTERED                           (0 << 6)
+# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT                         (1 << 6)
+# define SDVO_DTD_SDVO_FLAG_SCALING_MASK                       (3 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_NONE                       (0 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP                      (1 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH                     (2 << 4)
+# define SDVO_DTD_VSYNC_OFF_HIGH                       SDVO_I2C_ARG_6
+
+/**
+ * Generates a DTD based on the given width, height, and flags.
+ *
+ * This will be supported by any device supporting scaling or interlaced
+ * modes.
+ */
+#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING         0x1a
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW         SDVO_I2C_ARG_0
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH                SDVO_I2C_ARG_1
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW         SDVO_I2C_ARG_2
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH                SDVO_I2C_ARG_3
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW                SDVO_I2C_ARG_4
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH       SDVO_I2C_ARG_5
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS             SDVO_I2C_ARG_6
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED          (1 << 0)
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED              (1 << 1)
+
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1      0x1b
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2      0x1c
+
+/** Returns a struct intel_sdvo_pixel_clock_range */
+#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE           0x1d
+/** Returns a struct intel_sdvo_pixel_clock_range */
+#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE          0x1e
+
+/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */
+#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS                0x1f
+
+/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
+#define SDVO_CMD_GET_CLOCK_RATE_MULT                   0x20
+/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
+#define SDVO_CMD_SET_CLOCK_RATE_MULT                   0x21
+# define SDVO_CLOCK_RATE_MULT_1X                               (1 << 0)
+# define SDVO_CLOCK_RATE_MULT_2X                               (1 << 1)
+# define SDVO_CLOCK_RATE_MULT_4X                               (1 << 3)
+
+#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS              0x27
+
+#define SDVO_CMD_GET_TV_FORMAT                         0x28
+
+#define SDVO_CMD_SET_TV_FORMAT                         0x29
+
+#define SDVO_CMD_GET_SUPPORTED_POWER_STATES            0x2a
+#define SDVO_CMD_GET_ENCODER_POWER_STATE               0x2b
+#define SDVO_CMD_SET_ENCODER_POWER_STATE               0x2c
+# define SDVO_ENCODER_STATE_ON                                 (1 << 0)
+# define SDVO_ENCODER_STATE_STANDBY                            (1 << 1)
+# define SDVO_ENCODER_STATE_SUSPEND                            (1 << 2)
+# define SDVO_ENCODER_STATE_OFF                                        (1 << 3)
+
+#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT             0x93
+
+#define SDVO_CMD_SET_CONTROL_BUS_SWITCH                        0x7a
+# define SDVO_CONTROL_BUS_PROM                         0x0
+# define SDVO_CONTROL_BUS_DDC1                         0x1
+# define SDVO_CONTROL_BUS_DDC2                         0x2
+# define SDVO_CONTROL_BUS_DDC3                         0x3
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
new file mode 100644 (file)
index 0000000..fbb35dc
--- /dev/null
@@ -0,0 +1,1725 @@
+/*
+ * Copyright Â© 2006-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file
+ * Integrated TV-out support for the 915GM and 945GM.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_edid.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+enum tv_margin {
+       TV_MARGIN_LEFT, TV_MARGIN_TOP,
+       TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
+};
+
+/** Private structure for the integrated TV support */
+struct intel_tv_priv {
+       int type;
+       char *tv_format;
+       int margin[4];
+       u32 save_TV_H_CTL_1;
+       u32 save_TV_H_CTL_2;
+       u32 save_TV_H_CTL_3;
+       u32 save_TV_V_CTL_1;
+       u32 save_TV_V_CTL_2;
+       u32 save_TV_V_CTL_3;
+       u32 save_TV_V_CTL_4;
+       u32 save_TV_V_CTL_5;
+       u32 save_TV_V_CTL_6;
+       u32 save_TV_V_CTL_7;
+       u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
+
+       u32 save_TV_CSC_Y;
+       u32 save_TV_CSC_Y2;
+       u32 save_TV_CSC_U;
+       u32 save_TV_CSC_U2;
+       u32 save_TV_CSC_V;
+       u32 save_TV_CSC_V2;
+       u32 save_TV_CLR_KNOBS;
+       u32 save_TV_CLR_LEVEL;
+       u32 save_TV_WIN_POS;
+       u32 save_TV_WIN_SIZE;
+       u32 save_TV_FILTER_CTL_1;
+       u32 save_TV_FILTER_CTL_2;
+       u32 save_TV_FILTER_CTL_3;
+
+       u32 save_TV_H_LUMA[60];
+       u32 save_TV_H_CHROMA[60];
+       u32 save_TV_V_LUMA[43];
+       u32 save_TV_V_CHROMA[43];
+
+       u32 save_TV_DAC;
+       u32 save_TV_CTL;
+};
+
+struct video_levels {
+       int blank, black, burst;
+};
+
+struct color_conversion {
+       u16 ry, gy, by, ay;
+       u16 ru, gu, bu, au;
+       u16 rv, gv, bv, av;
+};
+
+static const u32 filter_table[] = {
+       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+       0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
+       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+       0x28003100, 0x28002F00, 0x00003100, 0x36403000,
+       0x2D002CC0, 0x30003640, 0x2D0036C0,
+       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+       0x28003100, 0x28002F00, 0x00003100,
+};
+
+/*
+ * Color conversion values have 3 separate fixed point formats:
+ *
+ * 10 bit fields (ay, au)
+ *   1.9 fixed point (b.bbbbbbbbb)
+ * 11 bit fields (ry, by, ru, gu, gv)
+ *   exp.mantissa (ee.mmmmmmmmm)
+ *   ee = 00 = 10^-1 (0.mmmmmmmmm)
+ *   ee = 01 = 10^-2 (0.0mmmmmmmmm)
+ *   ee = 10 = 10^-3 (0.00mmmmmmmmm)
+ *   ee = 11 = 10^-4 (0.000mmmmmmmmm)
+ * 12 bit fields (gy, rv, bu)
+ *   exp.mantissa (eee.mmmmmmmmm)
+ *   eee = 000 = 10^-1 (0.mmmmmmmmm)
+ *   eee = 001 = 10^-2 (0.0mmmmmmmmm)
+ *   eee = 010 = 10^-3 (0.00mmmmmmmmm)
+ *   eee = 011 = 10^-4 (0.000mmmmmmmmm)
+ *   eee = 100 = reserved
+ *   eee = 101 = reserved
+ *   eee = 110 = reserved
+ *   eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
+ *
+ * Saturation and contrast are 8 bits, with their own representation:
+ * 8 bit field (saturation, contrast)
+ *   exp.mantissa (ee.mmmmmm)
+ *   ee = 00 = 10^-1 (0.mmmmmm)
+ *   ee = 01 = 10^0 (m.mmmmm)
+ *   ee = 10 = 10^1 (mm.mmmm)
+ *   ee = 11 = 10^2 (mmm.mmm)
+ *
+ * Simple conversion function:
+ *
+ * static u32
+ * float_to_csc_11(float f)
+ * {
+ *     u32 exp;
+ *     u32 mant;
+ *     u32 ret;
+ *
+ *     if (f < 0)
+ *         f = -f;
+ *
+ *     if (f >= 1) {
+ *         exp = 0x7;
+ *        mant = 1 << 8;
+ *     } else {
+ *         for (exp = 0; exp < 3 && f < 0.5; exp++)
+ *            f *= 2.0;
+ *         mant = (f * (1 << 9) + 0.5);
+ *         if (mant >= (1 << 9))
+ *             mant = (1 << 9) - 1;
+ *     }
+ *     ret = (exp << 9) | mant;
+ *     return ret;
+ * }
+ */
+
+/*
+ * Behold, magic numbers!  If we plant them they might grow a big
+ * s-video cable to the sky... or something.
+ *
+ * Pre-converted to appropriate hex value.
+ */
+
+/*
+ * PAL & NTSC values for composite & s-video connections
+ */
+static const struct color_conversion ntsc_m_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_m_levels_composite = {
+       .blank = 225, .black = 267, .burst = 113,
+};
+
+static const struct color_conversion ntsc_m_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_m_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 133,
+};
+
+static const struct color_conversion ntsc_j_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
+       .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00,
+       .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_j_levels_composite = {
+       .blank = 225, .black = 225, .burst = 113,
+};
+
+static const struct color_conversion ntsc_j_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
+       .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00,
+       .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_j_levels_svideo = {
+       .blank = 266, .black = 266, .burst = 133,
+};
+
+static const struct color_conversion pal_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
+       .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00,
+       .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00,
+};
+
+static const struct video_levels pal_levels_composite = {
+       .blank = 237, .black = 237, .burst = 118,
+};
+
+static const struct color_conversion pal_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
+       .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00,
+       .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00,
+};
+
+static const struct video_levels pal_levels_svideo = {
+       .blank = 280, .black = 280, .burst = 139,
+};
+
+static const struct color_conversion pal_m_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+};
+
+static const struct video_levels pal_m_levels_composite = {
+       .blank = 225, .black = 267, .burst = 113,
+};
+
+static const struct color_conversion pal_m_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+};
+
+static const struct video_levels pal_m_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 133,
+};
+
+static const struct color_conversion pal_n_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+};
+
+static const struct video_levels pal_n_levels_composite = {
+       .blank = 225, .black = 267, .burst = 118,
+};
+
+static const struct color_conversion pal_n_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+};
+
+static const struct video_levels pal_n_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 139,
+};
+
+/*
+ * Component connections
+ */
+static const struct color_conversion sdtv_csc_yprpb = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146,
+       .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00,
+       .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00,
+};
+
+static const struct color_conversion sdtv_csc_rgb = {
+       .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
+       .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
+       .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
+};
+
+static const struct color_conversion hdtv_csc_yprpb = {
+       .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146,
+       .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00,
+       .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00,
+};
+
+static const struct color_conversion hdtv_csc_rgb = {
+       .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
+       .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
+       .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
+};
+
+static const struct video_levels component_levels = {
+       .blank = 279, .black = 279, .burst = 0,
+};
+
+
+struct tv_mode {
+       char *name;
+       int clock;
+       int refresh; /* in millihertz (for precision) */
+       u32 oversample;
+       int hsync_end, hblank_start, hblank_end, htotal;
+       bool progressive, trilevel_sync, component_only;
+       int vsync_start_f1, vsync_start_f2, vsync_len;
+       bool veq_ena;
+       int veq_start_f1, veq_start_f2, veq_len;
+       int vi_end_f1, vi_end_f2, nbr_end;
+       bool burst_ena;
+       int hburst_start, hburst_len;
+       int vburst_start_f1, vburst_end_f1;
+       int vburst_start_f2, vburst_end_f2;
+       int vburst_start_f3, vburst_end_f3;
+       int vburst_start_f4, vburst_end_f4;
+       /*
+        * subcarrier programming
+        */
+       int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
+       u32 sc_reset;
+       bool pal_burst;
+       /*
+        * blank/black levels
+        */
+       const struct video_levels *composite_levels, *svideo_levels;
+       const struct color_conversion *composite_color, *svideo_color;
+       const u32 *filter_table;
+       int max_srcw;
+};
+
+
+/*
+ * Sub carrier DDA
+ *
+ *  I think this works as follows:
+ *
+ *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
+ *
+ * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
+ *
+ * So,
+ *  dda1_ideal = subcarrier/pixel * 4096
+ *  dda1_inc = floor (dda1_ideal)
+ *  dda2 = dda1_ideal - dda1_inc
+ *
+ *  then pick a ratio for dda2 that gives the closest approximation. If
+ *  you can't get close enough, you can play with dda3 as well. This
+ *  seems likely to happen when dda2 is small as the jumps would be larger
+ *
+ * To invert this,
+ *
+ *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
+ *
+ * The constants below were all computed using a 107.520MHz clock
+ */
+
+/**
+ * Register programming values for TV modes.
+ *
+ * These values account for -1s required.
+ */
+
+const static struct tv_mode tv_modes[] = {
+       {
+               .name           = "NTSC-M",
+               .clock          = 107520,
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start   = 836,              .htotal             = 857,
+
+               .progressive    = false,            .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    136,
+               .dda2_inc       =   7624,           .dda2_size          =  20013,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst      = false,
+
+               .composite_levels = &ntsc_m_levels_composite,
+               .composite_color = &ntsc_m_csc_composite,
+               .svideo_levels  = &ntsc_m_levels_svideo,
+               .svideo_color = &ntsc_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "NTSC-443",
+               .clock          = 107520,
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start   = 836,              .htotal             = 857,
+
+               .progressive    = false,            .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = 8,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =  18557,       .dda2_size      =  20625,
+               .dda3_inc       =      0,       .dda3_size      =      0,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = true,
+
+               .composite_levels = &ntsc_m_levels_composite,
+               .composite_color = &ntsc_m_csc_composite,
+               .svideo_levels  = &ntsc_m_levels_svideo,
+               .svideo_color = &ntsc_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "NTSC-J",
+               .clock          = 107520,
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start = 836,        .htotal             = 857,
+
+               .progressive    = false,    .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,        .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2 = 1,          .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    136,
+               .dda2_inc       =   7624,           .dda2_size          =  20013,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst      = false,
+
+               .composite_levels = &ntsc_j_levels_composite,
+               .composite_color = &ntsc_j_csc_composite,
+               .svideo_levels  = &ntsc_j_levels_svideo,
+               .svideo_color = &ntsc_j_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "PAL-M",
+               .clock          = 107520,
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+               .hsync_end      = 64,             .hblank_end           = 124,
+               .hblank_start = 836,      .htotal               = 857,
+
+               .progressive    = false,            .trilevel_sync = false,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = true,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240,
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    136,
+               .dda2_inc       =    7624,          .dda2_size          =  20013,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst  = false,
+
+               .composite_levels = &pal_m_levels_composite,
+               .composite_color = &pal_m_csc_composite,
+               .svideo_levels  = &pal_m_levels_svideo,
+               .svideo_color = &pal_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
+               .name       = "PAL-N",
+               .clock          = 107520,
+               .refresh        = 25000,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               .hsync_end      = 64,               .hblank_end         = 128,
+               .hblank_start = 844,        .htotal             = 863,
+
+               .progressive  = false,    .trilevel_sync = false,
+
+
+               .vsync_start_f1 = 6,       .vsync_start_f2      = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 24,               .vi_end_f2          = 25,
+               .nbr_end        = 286,
+
+               .burst_ena      = true,
+               .hburst_start = 73,                 .hburst_len         = 34,
+               .vburst_start_f1 = 8,       .vburst_end_f1      = 285,
+               .vburst_start_f2 = 8,       .vburst_end_f2      = 286,
+               .vburst_start_f3 = 9,       .vburst_end_f3      = 286,
+               .vburst_start_f4 = 9,       .vburst_end_f4      = 285,
+
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =  18557,       .dda2_size      =  20625,
+               .dda3_inc       =      0,       .dda3_size      =      0,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = true,
+
+               .composite_levels = &pal_n_levels_composite,
+               .composite_color = &pal_n_csc_composite,
+               .svideo_levels  = &pal_n_levels_svideo,
+               .svideo_color = &pal_n_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
+               .name       = "PAL",
+               .clock          = 107520,
+               .refresh        = 25000,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               .hsync_end      = 64,               .hblank_end         = 128,
+               .hblank_start   = 844,      .htotal             = 863,
+
+               .progressive    = false,    .trilevel_sync = false,
+
+               .vsync_start_f1 = 5,        .vsync_start_f2     = 6,
+               .vsync_len      = 5,
+
+               .veq_ena        = true,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,        .veq_len            = 15,
+
+               .vi_end_f1      = 24,               .vi_end_f2          = 25,
+               .nbr_end        = 286,
+
+               .burst_ena      = true,
+               .hburst_start   = 73,               .hburst_len         = 32,
+               .vburst_start_f1 = 8,               .vburst_end_f1      = 285,
+               .vburst_start_f2 = 8,               .vburst_end_f2      = 286,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 286,
+               .vburst_start_f4 = 9,               .vburst_end_f4      = 285,
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =  18557,       .dda2_size      =  20625,
+               .dda3_inc       =      0,       .dda3_size      =      0,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = true,
+
+               .composite_levels = &pal_levels_composite,
+               .composite_color = &pal_csc_composite,
+               .svideo_levels  = &pal_levels_svideo,
+               .svideo_color = &pal_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "480p@59.94Hz",
+               .clock  = 107520,
+               .refresh        = 59940,
+               .oversample     = TV_OVERSAMPLE_4X,
+               .component_only = 1,
+
+               .hsync_end      = 64,               .hblank_end         = 122,
+               .hblank_start   = 842,              .htotal             = 857,
+
+               .progressive    = true,.trilevel_sync = false,
+
+               .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
+               .vsync_len      = 12,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 496,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "480p@60Hz",
+               .clock  = 107520,
+               .refresh        = 60000,
+               .oversample     = TV_OVERSAMPLE_4X,
+               .component_only = 1,
+
+               .hsync_end      = 64,               .hblank_end         = 122,
+               .hblank_start   = 842,              .htotal             = 856,
+
+               .progressive    = true,.trilevel_sync = false,
+
+               .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
+               .vsync_len      = 12,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 496,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "576p",
+               .clock  = 107520,
+               .refresh        = 50000,
+               .oversample     = TV_OVERSAMPLE_4X,
+               .component_only = 1,
+
+               .hsync_end      = 64,               .hblank_end         = 139,
+               .hblank_start   = 859,              .htotal             = 863,
+
+               .progressive    = true,         .trilevel_sync = false,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 48,               .vi_end_f2          = 48,
+               .nbr_end        = 575,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@60Hz",
+               .clock          = 148800,
+               .refresh        = 60000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1649,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@59.94Hz",
+               .clock          = 148800,
+               .refresh        = 59940,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1651,
+
+               .progressive    = true,             .trilevel_sync = true,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@50Hz",
+               .clock          = 148800,
+               .refresh        = 50000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1979,
+
+               .progressive    = true,                 .trilevel_sync = true,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = false,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+               .max_srcw = 800
+       },
+       {
+               .name       = "1080i@50Hz",
+               .clock          = 148800,
+               .refresh        = 25000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2639,
+
+               .progressive    = false,            .trilevel_sync = true,
+
+               .vsync_start_f1 = 4,              .vsync_start_f2     = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = true,             .veq_start_f1       = 4,
+               .veq_start_f2   = 4,        .veq_len            = 10,
+
+
+               .vi_end_f1      = 21,           .vi_end_f2          = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "1080i@60Hz",
+               .clock          = 148800,
+               .refresh        = 30000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2199,
+
+               .progressive    = false,            .trilevel_sync = true,
+
+               .vsync_start_f1 = 4,               .vsync_start_f2     = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = true,             .veq_start_f1       = 4,
+               .veq_start_f2   = 4,                .veq_len            = 10,
+
+
+               .vi_end_f1      = 21,               .vi_end_f2          = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "1080i@59.94Hz",
+               .clock          = 148800,
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2200,
+
+               .progressive    = false,            .trilevel_sync = true,
+
+               .vsync_start_f1 = 4,            .vsync_start_f2    = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = true,             .veq_start_f1       = 4,
+               .veq_start_f2 = 4,                  .veq_len = 10,
+
+
+               .vi_end_f1      = 21,           .vi_end_f2              = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = false,
+
+               .filter_table = filter_table,
+       },
+};
+
+#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
+
+static void
+intel_tv_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       switch(mode) {
+       case DRM_MODE_DPMS_ON:
+               I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
+               break;
+       }
+}
+
+static void
+intel_tv_save(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       int i;
+
+       tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1);
+       tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2);
+       tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3);
+       tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1);
+       tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2);
+       tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3);
+       tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4);
+       tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5);
+       tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6);
+       tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7);
+       tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1);
+       tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2);
+       tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3);
+
+       tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y);
+       tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2);
+       tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U);
+       tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2);
+       tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V);
+       tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2);
+       tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS);
+       tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL);
+       tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS);
+       tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE);
+       tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1);
+       tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2);
+       tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3);
+
+       for (i = 0; i < 60; i++)
+               tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2));
+       for (i = 0; i < 60; i++)
+               tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2));
+       for (i = 0; i < 43; i++)
+               tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2));
+       for (i = 0; i < 43; i++)
+               tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2));
+
+       tv_priv->save_TV_DAC = I915_READ(TV_DAC);
+       tv_priv->save_TV_CTL = I915_READ(TV_CTL);
+}
+
+static void
+intel_tv_restore(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       struct drm_crtc *crtc = connector->encoder->crtc;
+       struct intel_crtc *intel_crtc;
+       int i;
+
+       /* FIXME: No CRTC? */
+       if (!crtc)
+               return;
+
+       intel_crtc = to_intel_crtc(crtc);
+       I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1);
+       I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2);
+       I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3);
+       I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1);
+       I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2);
+       I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3);
+       I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4);
+       I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5);
+       I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6);
+       I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7);
+       I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1);
+       I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2);
+       I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3);
+
+       I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y);
+       I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2);
+       I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U);
+       I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2);
+       I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V);
+       I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2);
+       I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS);
+       I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL);
+
+       {
+               int pipeconf_reg = (intel_crtc->pipe == 0) ?
+                       PIPEACONF : PIPEBCONF;
+               int dspcntr_reg = (intel_crtc->plane == 0) ?
+                       DSPACNTR : DSPBCNTR;
+               int pipeconf = I915_READ(pipeconf_reg);
+               int dspcntr = I915_READ(dspcntr_reg);
+               int dspbase_reg = (intel_crtc->plane == 0) ?
+                       DSPAADDR : DSPBADDR;
+               /* Pipe must be off here */
+               I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+
+               if (!IS_I9XX(dev)) {
+                       /* Wait for vblank for the disable to take effect */
+                       intel_wait_for_vblank(dev);
+               }
+
+               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+               /* Wait for vblank for the disable to take effect. */
+               intel_wait_for_vblank(dev);
+
+               /* Filter ctl must be set before TV_WIN_SIZE */
+               I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1);
+               I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2);
+               I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3);
+               I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS);
+               I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE);
+               I915_WRITE(pipeconf_reg, pipeconf);
+               I915_WRITE(dspcntr_reg, dspcntr);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+       }
+
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]);
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]);
+
+       I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
+       I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
+}
+
+static const struct tv_mode *
+intel_tv_mode_lookup (char *tv_format)
+{
+       int i;
+
+       for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
+               const struct tv_mode *tv_mode = &tv_modes[i];
+
+               if (!strcmp(tv_format, tv_mode->name))
+                       return tv_mode;
+       }
+       return NULL;
+}
+
+static const struct tv_mode *
+intel_tv_mode_find (struct intel_output *intel_output)
+{
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+
+       return intel_tv_mode_lookup(tv_priv->tv_format);
+}
+
+static enum drm_mode_status
+intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+
+       /* Ensure TV refresh is close to desired refresh */
+       if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
+               return MODE_OK;
+       return MODE_CLOCK_RANGE;
+}
+
+
+static bool
+intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                   struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_mode_config *drm_config = &dev->mode_config;
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output);
+       struct drm_encoder *other_encoder;
+
+       if (!tv_mode)
+               return false;
+
+       /* FIXME: lock encoder list */
+       list_for_each_entry(other_encoder, &drm_config->encoder_list, head) {
+               if (other_encoder != encoder &&
+                   other_encoder->crtc == encoder->crtc)
+                       return false;
+       }
+
+       adjusted_mode->clock = tv_mode->clock;
+       return true;
+}
+
+static void
+intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+                 struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_output *intel_output = enc_to_intel_output(encoder);
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+       u32 tv_ctl;
+       u32 hctl1, hctl2, hctl3;
+       u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
+       u32 scctl1, scctl2, scctl3;
+       int i, j;
+       const struct video_levels *video_levels;
+       const struct color_conversion *color_conversion;
+       bool burst_ena;
+
+       if (!tv_mode)
+               return; /* can't happen (mode_prepare prevents this) */
+
+       tv_ctl = 0;
+
+       switch (tv_priv->type) {
+       default:
+       case DRM_MODE_CONNECTOR_Unknown:
+       case DRM_MODE_CONNECTOR_Composite:
+               tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
+               video_levels = tv_mode->composite_levels;
+               color_conversion = tv_mode->composite_color;
+               burst_ena = tv_mode->burst_ena;
+               break;
+       case DRM_MODE_CONNECTOR_Component:
+               tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
+               video_levels = &component_levels;
+               if (tv_mode->burst_ena)
+                       color_conversion = &sdtv_csc_yprpb;
+               else
+                       color_conversion = &hdtv_csc_yprpb;
+               burst_ena = false;
+               break;
+       case DRM_MODE_CONNECTOR_SVIDEO:
+               tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
+               video_levels = tv_mode->svideo_levels;
+               color_conversion = tv_mode->svideo_color;
+               burst_ena = tv_mode->burst_ena;
+               break;
+       }
+       hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
+               (tv_mode->htotal << TV_HTOTAL_SHIFT);
+
+       hctl2 = (tv_mode->hburst_start << 16) |
+               (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
+
+       if (burst_ena)
+               hctl2 |= TV_BURST_ENA;
+
+       hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
+               (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
+
+       vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
+               (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
+               (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
+
+       vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
+               (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
+               (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
+
+       vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
+               (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
+               (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
+
+       if (tv_mode->veq_ena)
+               vctl3 |= TV_EQUAL_ENA;
+
+       vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
+               (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
+
+       vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
+               (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
+
+       vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
+               (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
+
+       vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
+               (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
+
+       if (intel_crtc->pipe == 1)
+               tv_ctl |= TV_ENC_PIPEB_SELECT;
+       tv_ctl |= tv_mode->oversample;
+
+       if (tv_mode->progressive)
+               tv_ctl |= TV_PROGRESSIVE;
+       if (tv_mode->trilevel_sync)
+               tv_ctl |= TV_TRILEVEL_SYNC;
+       if (tv_mode->pal_burst)
+               tv_ctl |= TV_PAL_BURST;
+       scctl1 = 0;
+       /* dda1 implies valid video levels */
+       if (tv_mode->dda1_inc) {
+               scctl1 |= TV_SC_DDA1_EN;
+               scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
+       }
+
+       if (tv_mode->dda2_inc)
+               scctl1 |= TV_SC_DDA2_EN;
+
+       if (tv_mode->dda3_inc)
+               scctl1 |= TV_SC_DDA3_EN;
+
+       scctl1 |= tv_mode->sc_reset;
+       scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
+
+       scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
+               tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
+
+       scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
+               tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
+
+       /* Enable two fixes for the chips that need them. */
+       if (dev->pci_device < 0x2772)
+               tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
+
+       I915_WRITE(TV_H_CTL_1, hctl1);
+       I915_WRITE(TV_H_CTL_2, hctl2);
+       I915_WRITE(TV_H_CTL_3, hctl3);
+       I915_WRITE(TV_V_CTL_1, vctl1);
+       I915_WRITE(TV_V_CTL_2, vctl2);
+       I915_WRITE(TV_V_CTL_3, vctl3);
+       I915_WRITE(TV_V_CTL_4, vctl4);
+       I915_WRITE(TV_V_CTL_5, vctl5);
+       I915_WRITE(TV_V_CTL_6, vctl6);
+       I915_WRITE(TV_V_CTL_7, vctl7);
+       I915_WRITE(TV_SC_CTL_1, scctl1);
+       I915_WRITE(TV_SC_CTL_2, scctl2);
+       I915_WRITE(TV_SC_CTL_3, scctl3);
+
+       if (color_conversion) {
+               I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
+                          color_conversion->gy);
+               I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) |
+                          color_conversion->ay);
+               I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
+                          color_conversion->gu);
+               I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
+                          color_conversion->au);
+               I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
+                          color_conversion->gv);
+               I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
+                          color_conversion->av);
+       }
+
+       I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+       if (video_levels)
+               I915_WRITE(TV_CLR_LEVEL,
+                          ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
+                           (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
+       {
+               int pipeconf_reg = (intel_crtc->pipe == 0) ?
+                       PIPEACONF : PIPEBCONF;
+               int dspcntr_reg = (intel_crtc->plane == 0) ?
+                       DSPACNTR : DSPBCNTR;
+               int pipeconf = I915_READ(pipeconf_reg);
+               int dspcntr = I915_READ(dspcntr_reg);
+               int dspbase_reg = (intel_crtc->plane == 0) ?
+                       DSPAADDR : DSPBADDR;
+               int xpos = 0x0, ypos = 0x0;
+               unsigned int xsize, ysize;
+               /* Pipe must be off here */
+               I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+
+               /* Wait for vblank for the disable to take effect */
+               if (!IS_I9XX(dev))
+                       intel_wait_for_vblank(dev);
+
+               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+               /* Wait for vblank for the disable to take effect. */
+               intel_wait_for_vblank(dev);
+
+               /* Filter ctl must be set before TV_WIN_SIZE */
+               I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
+               xsize = tv_mode->hblank_start - tv_mode->hblank_end;
+               if (tv_mode->progressive)
+                       ysize = tv_mode->nbr_end + 1;
+               else
+                       ysize = 2*tv_mode->nbr_end + 1;
+
+               xpos += tv_priv->margin[TV_MARGIN_LEFT];
+               ypos += tv_priv->margin[TV_MARGIN_TOP];
+               xsize -= (tv_priv->margin[TV_MARGIN_LEFT] +
+                         tv_priv->margin[TV_MARGIN_RIGHT]);
+               ysize -= (tv_priv->margin[TV_MARGIN_TOP] +
+                         tv_priv->margin[TV_MARGIN_BOTTOM]);
+               I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
+               I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
+
+               I915_WRITE(pipeconf_reg, pipeconf);
+               I915_WRITE(dspcntr_reg, dspcntr);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+       }
+
+       j = 0;
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       I915_WRITE(TV_DAC, 0);
+       I915_WRITE(TV_CTL, tv_ctl);
+}
+
+static const struct drm_display_mode reported_modes[] = {
+       {
+               .name = "NTSC 480i",
+               .clock = 107520,
+               .hdisplay = 1280,
+               .hsync_start = 1368,
+               .hsync_end = 1496,
+               .htotal = 1712,
+
+               .vdisplay = 1024,
+               .vsync_start = 1027,
+               .vsync_end = 1034,
+               .vtotal = 1104,
+               .type = DRM_MODE_TYPE_DRIVER,
+       },
+};
+
+/**
+ * Detects TV presence by checking for load.
+ *
+ * Requires that the current pipe's DPLL is active.
+
+ * \return true if TV is connected.
+ * \return false if TV is disconnected.
+ */
+static int
+intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
+{
+       struct drm_encoder *encoder = &intel_output->enc;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long irqflags;
+       u32 tv_ctl, save_tv_ctl;
+       u32 tv_dac, save_tv_dac;
+       int type = DRM_MODE_CONNECTOR_Unknown;
+
+       tv_dac = I915_READ(TV_DAC);
+
+       /* Disable TV interrupts around load detect or we'll recurse */
+       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+       i915_disable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                             PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+
+       /*
+        * Detect TV by polling)
+        */
+       if (intel_output->load_detect_temp) {
+               /* TV not currently running, prod it with destructive detect */
+               save_tv_dac = tv_dac;
+               tv_ctl = I915_READ(TV_CTL);
+               save_tv_ctl = tv_ctl;
+               tv_ctl &= ~TV_ENC_ENABLE;
+               tv_ctl &= ~TV_TEST_MODE_MASK;
+               tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+               tv_dac &= ~TVDAC_SENSE_MASK;
+               tv_dac |= (TVDAC_STATE_CHG_EN |
+                          TVDAC_A_SENSE_CTL |
+                          TVDAC_B_SENSE_CTL |
+                          TVDAC_C_SENSE_CTL |
+                          DAC_CTL_OVERRIDE |
+                          DAC_A_0_7_V |
+                          DAC_B_0_7_V |
+                          DAC_C_0_7_V);
+               I915_WRITE(TV_CTL, tv_ctl);
+               I915_WRITE(TV_DAC, tv_dac);
+               intel_wait_for_vblank(dev);
+               tv_dac = I915_READ(TV_DAC);
+               I915_WRITE(TV_DAC, save_tv_dac);
+               I915_WRITE(TV_CTL, save_tv_ctl);
+       }
+       /*
+        *  A B C
+        *  0 1 1 Composite
+        *  1 0 X svideo
+        *  0 0 0 Component
+        */
+       if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+               DRM_DEBUG("Detected Composite TV connection\n");
+               type = DRM_MODE_CONNECTOR_Composite;
+       } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+               DRM_DEBUG("Detected S-Video TV connection\n");
+               type = DRM_MODE_CONNECTOR_SVIDEO;
+       } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+               DRM_DEBUG("Detected Component TV connection\n");
+               type = DRM_MODE_CONNECTOR_Component;
+       } else {
+               DRM_DEBUG("No TV connection detected\n");
+               type = -1;
+       }
+
+       /* Restore interrupt config */
+       spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+       i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
+                            PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+
+       return type;
+}
+
+/**
+ * Detect the TV connection.
+ *
+ * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
+ * we have a pipe programmed in order to probe the TV.
+ */
+static enum drm_connector_status
+intel_tv_detect(struct drm_connector *connector)
+{
+       struct drm_crtc *crtc;
+       struct drm_display_mode mode;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       struct drm_encoder *encoder = &intel_output->enc;
+       int dpms_mode;
+       int type = tv_priv->type;
+
+       mode = reported_modes[0];
+       drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
+
+       if (encoder->crtc) {
+               type = intel_tv_detect_type(encoder->crtc, intel_output);
+       } else {
+               crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode);
+               if (crtc) {
+                       type = intel_tv_detect_type(crtc, intel_output);
+                       intel_release_load_detect_pipe(intel_output, dpms_mode);
+               } else
+                       type = -1;
+       }
+
+       if (type < 0)
+               return connector_status_disconnected;
+
+       return connector_status_connected;
+}
+
+static struct input_res {
+       char *name;
+       int w, h;
+} input_res_table[] =
+{
+       {"640x480", 640, 480},
+       {"800x600", 800, 600},
+       {"1024x768", 1024, 768},
+       {"1280x1024", 1280, 1024},
+       {"848x480", 848, 480},
+       {"1280x720", 1280, 720},
+       {"1920x1080", 1920, 1080},
+};
+
+/**
+ * Stub get_modes function.
+ *
+ * This should probably return a set of fixed modes, unless we can figure out
+ * how to probe modes off of TV connections.
+ */
+
+static int
+intel_tv_get_modes(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode_ptr;
+       struct intel_output *intel_output = to_intel_output(connector);
+       const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+       int j;
+
+       for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
+            j++) {
+               struct input_res *input = &input_res_table[j];
+               unsigned int hactive_s = input->w;
+               unsigned int vactive_s = input->h;
+
+               if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
+                       continue;
+
+               if (input->w > 1024 && (!tv_mode->progressive
+                                       && !tv_mode->component_only))
+                       continue;
+
+               mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
+                                     DRM_MEM_DRIVER);
+               strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
+
+               mode_ptr->hdisplay = hactive_s;
+               mode_ptr->hsync_start = hactive_s + 1;
+               mode_ptr->hsync_end = hactive_s + 64;
+               if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
+                       mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
+               mode_ptr->htotal = hactive_s + 96;
+
+               mode_ptr->vdisplay = vactive_s;
+               mode_ptr->vsync_start = vactive_s + 1;
+               mode_ptr->vsync_end = vactive_s + 32;
+               if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
+                       mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
+               mode_ptr->vtotal = vactive_s + 33;
+
+               mode_ptr->clock = (int) (tv_mode->refresh *
+                                        mode_ptr->vtotal *
+                                        mode_ptr->htotal / 1000) / 1000;
+
+               mode_ptr->type = DRM_MODE_TYPE_DRIVER;
+               drm_mode_probed_add(connector, mode_ptr);
+       }
+
+       return 0;
+}
+
+static void
+intel_tv_destroy (struct drm_connector *connector)
+{
+       struct intel_output *intel_output = to_intel_output(connector);
+
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv),
+                DRM_MEM_DRIVER);
+}
+
+
+static int
+intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
+                     uint64_t val)
+{
+       struct drm_device *dev = connector->dev;
+       struct intel_output *intel_output = to_intel_output(connector);
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       int ret = 0;
+
+       ret = drm_connector_property_set_value(connector, property, val);
+       if (ret < 0)
+               goto out;
+
+       if (property == dev->mode_config.tv_left_margin_property)
+               tv_priv->margin[TV_MARGIN_LEFT] = val;
+       else if (property == dev->mode_config.tv_right_margin_property)
+               tv_priv->margin[TV_MARGIN_RIGHT] = val;
+       else if (property == dev->mode_config.tv_top_margin_property)
+               tv_priv->margin[TV_MARGIN_TOP] = val;
+       else if (property == dev->mode_config.tv_bottom_margin_property)
+               tv_priv->margin[TV_MARGIN_BOTTOM] = val;
+       else if (property == dev->mode_config.tv_mode_property) {
+               if (val >= NUM_TV_MODES) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               tv_priv->tv_format = tv_modes[val].name;
+               intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+       } else {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       intel_tv_mode_set(&intel_output->enc, NULL, NULL);
+out:
+       return ret;
+}
+
+static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
+       .dpms = intel_tv_dpms,
+       .mode_fixup = intel_tv_mode_fixup,
+       .prepare = intel_encoder_prepare,
+       .mode_set = intel_tv_mode_set,
+       .commit = intel_encoder_commit,
+};
+
+static const struct drm_connector_funcs intel_tv_connector_funcs = {
+       .save = intel_tv_save,
+       .restore = intel_tv_restore,
+       .detect = intel_tv_detect,
+       .destroy = intel_tv_destroy,
+       .set_property = intel_tv_set_property,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+};
+
+static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
+       .mode_valid = intel_tv_mode_valid,
+       .get_modes = intel_tv_get_modes,
+       .best_encoder = intel_best_encoder,
+};
+
+static void intel_tv_enc_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_tv_enc_funcs = {
+       .destroy = intel_tv_enc_destroy,
+};
+
+
+void
+intel_tv_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_connector *connector;
+       struct intel_output *intel_output;
+       struct intel_tv_priv *tv_priv;
+       u32 tv_dac_on, tv_dac_off, save_tv_dac;
+       char **tv_format_names;
+       int i, initial_mode = 0;
+
+       if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
+               return;
+
+       /* Even if we have an encoder we may not have a connector */
+       if (!dev_priv->int_tv_support)
+               return;
+
+       /*
+        * Sanity check the TV output by checking to see if the
+        * DAC register holds a value
+        */
+       save_tv_dac = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
+       tv_dac_on = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+       tv_dac_off = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac);
+
+       /*
+        * If the register does not hold the state change enable
+        * bit, (either as a 0 or a 1), assume it doesn't really
+        * exist
+        */
+       if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
+           (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
+               return;
+
+       intel_output = drm_calloc(1, sizeof(struct intel_output) +
+                                 sizeof(struct intel_tv_priv), DRM_MEM_DRIVER);
+       if (!intel_output) {
+               return;
+       }
+       connector = &intel_output->base;
+
+       drm_connector_init(dev, connector, &intel_tv_connector_funcs,
+                          DRM_MODE_CONNECTOR_SVIDEO);
+
+       drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs,
+                        DRM_MODE_ENCODER_TVDAC);
+
+       drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
+       tv_priv = (struct intel_tv_priv *)(intel_output + 1);
+       intel_output->type = INTEL_OUTPUT_TVOUT;
+       intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1));
+       intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+       intel_output->dev_priv = tv_priv;
+       tv_priv->type = DRM_MODE_CONNECTOR_Unknown;
+
+       /* BIOS margin values */
+       tv_priv->margin[TV_MARGIN_LEFT] = 54;
+       tv_priv->margin[TV_MARGIN_TOP] = 36;
+       tv_priv->margin[TV_MARGIN_RIGHT] = 46;
+       tv_priv->margin[TV_MARGIN_BOTTOM] = 37;
+
+       tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
+
+       drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs);
+       drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
+       connector->interlace_allowed = false;
+       connector->doublescan_allowed = false;
+
+       /* Create TV properties then attach current values */
+       tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES,
+                                   DRM_MEM_DRIVER);
+       if (!tv_format_names)
+               goto out;
+       for (i = 0; i < NUM_TV_MODES; i++)
+               tv_format_names[i] = tv_modes[i].name;
+       drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names);
+
+       drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
+                                  initial_mode);
+       drm_connector_attach_property(connector,
+                                  dev->mode_config.tv_left_margin_property,
+                                  tv_priv->margin[TV_MARGIN_LEFT]);
+       drm_connector_attach_property(connector,
+                                  dev->mode_config.tv_top_margin_property,
+                                  tv_priv->margin[TV_MARGIN_TOP]);
+       drm_connector_attach_property(connector,
+                                  dev->mode_config.tv_right_margin_property,
+                                  tv_priv->margin[TV_MARGIN_RIGHT]);
+       drm_connector_attach_property(connector,
+                                  dev->mode_config.tv_bottom_margin_property,
+                                  tv_priv->margin[TV_MARGIN_BOTTOM]);
+out:
+       drm_sysfs_connector_add(connector);
+}
index 4b27d9abb7bcba5b0b77b8ab2b8f48e60859c2f2..cace3964feebb4288dae0a822bb03284043ffda7 100644 (file)
@@ -860,12 +860,12 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
  * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
  * be careful about how this function is called.
  */
-static void r300_discard_buffer(struct drm_device * dev, struct drm_buf * buf)
+static void r300_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf)
 {
-       drm_radeon_private_t *dev_priv = dev->dev_private;
        drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
 
-       buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
+       buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
        buf->pending = 1;
        buf->used = 0;
 }
@@ -1027,6 +1027,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
                      drm_radeon_kcmd_buffer_t *cmdbuf)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf = NULL;
        int emit_dispatch_age = 0;
@@ -1134,7 +1135,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
                        }
 
                        emit_dispatch_age = 1;
-                       r300_discard_buffer(dev, buf);
+                       r300_discard_buffer(dev, file_priv->master, buf);
                        break;
 
                case R300_CMD_WAIT:
@@ -1189,7 +1190,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
 
                /* Emit the vertex buffer age */
                BEGIN_RING(2);
-               RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch);
+               RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch);
                ADVANCE_RING();
        }
 
index dcebb4bee7aaf9e0e845db50296798f76686d1a6..63212d7bbc287a36ef9bcc3cba45b3ac6cd97deb 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "drmP.h"
 #include "drm.h"
+#include "drm_sarea.h"
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 #include "r300_reg.h"
@@ -667,15 +668,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
                RADEON_WRITE(RADEON_BUS_CNTL, tmp);
        } /* PCIE cards appears to not need this */
 
-       dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0;
-       RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
+       dev_priv->scratch[0] = 0;
+       RADEON_WRITE(RADEON_LAST_FRAME_REG, 0);
 
-       dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0;
-       RADEON_WRITE(RADEON_LAST_DISPATCH_REG,
-                    dev_priv->sarea_priv->last_dispatch);
+       dev_priv->scratch[1] = 0;
+       RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0);
 
-       dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0;
-       RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear);
+       dev_priv->scratch[2] = 0;
+       RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
 
        radeon_do_wait_for_idle(dev_priv);
 
@@ -871,9 +871,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
        }
 }
 
-static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
+static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
+                            struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
 
        DRM_DEBUG("\n");
 
@@ -998,8 +1000,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
        dev_priv->buffers_offset = init->buffers_offset;
        dev_priv->gart_textures_offset = init->gart_textures_offset;
 
-       dev_priv->sarea = drm_getsarea(dev);
-       if (!dev_priv->sarea) {
+       master_priv->sarea = drm_getsarea(dev);
+       if (!master_priv->sarea) {
                DRM_ERROR("could not find sarea!\n");
                radeon_do_cleanup_cp(dev);
                return -EINVAL;
@@ -1035,10 +1037,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
                }
        }
 
-       dev_priv->sarea_priv =
-           (drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle +
-                                   init->sarea_priv_offset);
-
 #if __OS_HAS_AGP
        if (dev_priv->flags & RADEON_IS_AGP) {
                drm_core_ioremap(dev_priv->cp_ring, dev);
@@ -1329,7 +1327,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri
        case RADEON_INIT_CP:
        case RADEON_INIT_R200_CP:
        case RADEON_INIT_R300_CP:
-               return radeon_do_init_cp(dev, init);
+               return radeon_do_init_cp(dev, init, file_priv);
        case RADEON_CLEANUP_CP:
                return radeon_do_cleanup_cp(dev);
        }
@@ -1768,6 +1766,51 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
        return ret;
 }
 
+int radeon_master_create(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_radeon_master_private *master_priv;
+       unsigned long sareapage;
+       int ret;
+
+       master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
+       if (!master_priv)
+               return -ENOMEM;
+
+       /* prebuild the SAREA */
+       sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
+       ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
+                        &master_priv->sarea);
+       if (ret) {
+               DRM_ERROR("SAREA setup failed\n");
+               return ret;
+       }
+       master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea);
+       master_priv->sarea_priv->pfCurrentPage = 0;
+
+       master->driver_priv = master_priv;
+       return 0;
+}
+
+void radeon_master_destroy(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
+
+       if (!master_priv)
+               return;
+
+       if (master_priv->sarea_priv &&
+           master_priv->sarea_priv->pfCurrentPage != 0)
+               radeon_cp_dispatch_flip(dev, master);
+
+       master_priv->sarea_priv = NULL;
+       if (master_priv->sarea)
+               drm_rmmap_locked(dev, master_priv->sarea);
+
+       drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);
+
+       master->driver_priv = NULL;
+}
+
 /* Create mappings for registers and framebuffer so userland doesn't necessarily
  * have to find them.
  */
index 71af746a4e4760d24c7c36e1141882b43117137a..fef207881f45eeb34d5149c571b80fefbb2e47b2 100644 (file)
@@ -96,6 +96,8 @@ static struct drm_driver driver = {
        .enable_vblank = radeon_enable_vblank,
        .disable_vblank = radeon_disable_vblank,
        .dri_library_name = dri_library_name,
+       .master_create = radeon_master_create,
+       .master_destroy = radeon_master_destroy,
        .irq_preinstall = radeon_driver_irq_preinstall,
        .irq_postinstall = radeon_driver_irq_postinstall,
        .irq_uninstall = radeon_driver_irq_uninstall,
index 3bbb871b25d5102a2b6d832702cc55bc338a70ea..490bc7ceef60fe21dcaa8bb800fdc18fdbe1aea1 100644 (file)
@@ -226,9 +226,13 @@ struct radeon_virt_surface {
 #define RADEON_FLUSH_EMITED    (1 < 0)
 #define RADEON_PURGE_EMITED    (1 < 1)
 
+struct drm_radeon_master_private {
+       drm_local_map_t *sarea;
+       drm_radeon_sarea_t *sarea_priv;
+};
+
 typedef struct drm_radeon_private {
        drm_radeon_ring_buffer_t ring;
-       drm_radeon_sarea_t *sarea_priv;
 
        u32 fb_location;
        u32 fb_size;
@@ -409,6 +413,9 @@ extern int radeon_driver_open(struct drm_device *dev,
 extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
                                unsigned long arg);
 
+extern int radeon_master_create(struct drm_device *dev, struct drm_master *master);
+extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master);
+extern void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master);
 /* r300_cmdbuf.c */
 extern void r300_init_reg_flags(struct drm_device *dev);
 
@@ -1335,8 +1342,9 @@ do {                                                                      \
 } while (0)
 
 #define VB_AGE_TEST_WITH_RETURN( dev_priv )                            \
-do {                                                                   \
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;          \
+do {                                                           \
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;       \
        if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) {         \
                int __ret = radeon_do_cp_idle( dev_priv );              \
                if ( __ret ) return __ret;                              \
index 5d7153fcc7b0063625a8232e66b6f89b09a042c3..ef940a079dcbbb8488a1cc977f2c328e3e79d4a4 100644 (file)
@@ -742,13 +742,14 @@ static struct {
  */
 
 static void radeon_clear_box(drm_radeon_private_t * dev_priv,
+                            struct drm_radeon_master_private *master_priv,
                             int x, int y, int w, int h, int r, int g, int b)
 {
        u32 color;
        RING_LOCALS;
 
-       x += dev_priv->sarea_priv->boxes[0].x1;
-       y += dev_priv->sarea_priv->boxes[0].y1;
+       x += master_priv->sarea_priv->boxes[0].x1;
+       y += master_priv->sarea_priv->boxes[0].y1;
 
        switch (dev_priv->color_fmt) {
        case RADEON_COLOR_FORMAT_RGB565:
@@ -776,7 +777,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv,
                 RADEON_GMC_SRC_DATATYPE_COLOR |
                 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
 
-       if (dev_priv->sarea_priv->pfCurrentPage == 1) {
+       if (master_priv->sarea_priv->pfCurrentPage == 1) {
                OUT_RING(dev_priv->front_pitch_offset);
        } else {
                OUT_RING(dev_priv->back_pitch_offset);
@@ -790,7 +791,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv,
        ADVANCE_RING();
 }
 
-static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
+static void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv, struct drm_radeon_master_private *master_priv)
 {
        /* Collapse various things into a wait flag -- trying to
         * guess if userspase slept -- better just to have them tell us.
@@ -807,12 +808,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
        /* Purple box for page flipping
         */
        if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
-               radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
+               radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255);
 
        /* Red box if we have to wait for idle at any point
         */
        if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
-               radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
+               radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0);
 
        /* Blue box: lost context?
         */
@@ -820,12 +821,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
        /* Yellow box for texture swaps
         */
        if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
-               radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
+               radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0);
 
        /* Green box if hardware never idles (as far as we can tell)
         */
        if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
-               radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
+               radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0);
 
        /* Draw bars indicating number of buffers allocated
         * (not a great measure, easily confused)
@@ -834,7 +835,7 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
                if (dev_priv->stats.requested_bufs > 100)
                        dev_priv->stats.requested_bufs = 100;
 
-               radeon_clear_box(dev_priv, 4, 16,
+               radeon_clear_box(dev_priv, master_priv, 4, 16,
                                 dev_priv->stats.requested_bufs, 4,
                                 196, 128, 128);
        }
@@ -848,11 +849,13 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
  */
 
 static void radeon_cp_dispatch_clear(struct drm_device * dev,
+                                    struct drm_master *master,
                                     drm_radeon_clear_t * clear,
                                     drm_radeon_clear_rect_t * depth_boxes)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
        drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
        int nbox = sarea_priv->nbox;
        struct drm_clip_rect *pbox = sarea_priv->boxes;
@@ -864,7 +867,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
 
        dev_priv->stats.clears++;
 
-       if (dev_priv->sarea_priv->pfCurrentPage == 1) {
+       if (sarea_priv->pfCurrentPage == 1) {
                unsigned int tmp = flags;
 
                flags &= ~(RADEON_FRONT | RADEON_BACK);
@@ -890,7 +893,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
 
                /* Make sure we restore the 3D state next time.
                 */
-               dev_priv->sarea_priv->ctx_owner = 0;
+               sarea_priv->ctx_owner = 0;
 
                for (i = 0; i < nbox; i++) {
                        int x = pbox[i].x1;
@@ -967,7 +970,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
                /* Make sure we restore the 3D state next time.
                 * we haven't touched any "normal" state - still need this?
                 */
-               dev_priv->sarea_priv->ctx_owner = 0;
+               sarea_priv->ctx_owner = 0;
 
                if ((dev_priv->flags & RADEON_HAS_HIERZ)
                    && (flags & RADEON_USE_HIERZ)) {
@@ -1214,7 +1217,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
 
                /* Make sure we restore the 3D state next time.
                 */
-               dev_priv->sarea_priv->ctx_owner = 0;
+               sarea_priv->ctx_owner = 0;
 
                for (i = 0; i < nbox; i++) {
 
@@ -1285,7 +1288,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
 
                /* Make sure we restore the 3D state next time.
                 */
-               dev_priv->sarea_priv->ctx_owner = 0;
+               sarea_priv->ctx_owner = 0;
 
                for (i = 0; i < nbox; i++) {
 
@@ -1328,20 +1331,21 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
         * wait on this value before performing the clear ioctl.  We
         * need this because the card's so damned fast...
         */
-       dev_priv->sarea_priv->last_clear++;
+       sarea_priv->last_clear++;
 
        BEGIN_RING(4);
 
-       RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
+       RADEON_CLEAR_AGE(sarea_priv->last_clear);
        RADEON_WAIT_UNTIL_IDLE();
 
        ADVANCE_RING();
 }
 
-static void radeon_cp_dispatch_swap(struct drm_device * dev)
+static void radeon_cp_dispatch_swap(struct drm_device *dev, struct drm_master *master)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
        int nbox = sarea_priv->nbox;
        struct drm_clip_rect *pbox = sarea_priv->boxes;
        int i;
@@ -1351,7 +1355,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev)
        /* Do some trivial performance monitoring...
         */
        if (dev_priv->do_boxes)
-               radeon_cp_performance_boxes(dev_priv);
+               radeon_cp_performance_boxes(dev_priv, master_priv);
 
        /* Wait for the 3D stream to idle before dispatching the bitblt.
         * This will prevent data corruption between the two streams.
@@ -1385,7 +1389,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev)
                /* Make this work even if front & back are flipped:
                 */
                OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
-               if (dev_priv->sarea_priv->pfCurrentPage == 0) {
+               if (sarea_priv->pfCurrentPage == 0) {
                        OUT_RING(dev_priv->back_pitch_offset);
                        OUT_RING(dev_priv->front_pitch_offset);
                } else {
@@ -1405,31 +1409,32 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev)
         * throttle the framerate by waiting for this value before
         * performing the swapbuffer ioctl.
         */
-       dev_priv->sarea_priv->last_frame++;
+       sarea_priv->last_frame++;
 
        BEGIN_RING(4);
 
-       RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
+       RADEON_FRAME_AGE(sarea_priv->last_frame);
        RADEON_WAIT_UNTIL_2D_IDLE();
 
        ADVANCE_RING();
 }
 
-static void radeon_cp_dispatch_flip(struct drm_device * dev)
+void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       struct drm_sarea *sarea = (struct drm_sarea *) dev_priv->sarea->handle;
-       int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
+       struct drm_sarea *sarea = (struct drm_sarea *)master_priv->sarea->handle;
+       int offset = (master_priv->sarea_priv->pfCurrentPage == 1)
            ? dev_priv->front_offset : dev_priv->back_offset;
        RING_LOCALS;
        DRM_DEBUG("pfCurrentPage=%d\n",
-                 dev_priv->sarea_priv->pfCurrentPage);
+                 master_priv->sarea_priv->pfCurrentPage);
 
        /* Do some trivial performance monitoring...
         */
        if (dev_priv->do_boxes) {
                dev_priv->stats.boxes |= RADEON_BOX_FLIP;
-               radeon_cp_performance_boxes(dev_priv);
+               radeon_cp_performance_boxes(dev_priv, master_priv);
        }
 
        /* Update the frame offsets for both CRTCs
@@ -1441,7 +1446,7 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev)
                     ((sarea->frame.y * dev_priv->front_pitch +
                       sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
                     + offset);
-       OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
+       OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base
                     + offset);
 
        ADVANCE_RING();
@@ -1450,13 +1455,13 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev)
         * throttle the framerate by waiting for this value before
         * performing the swapbuffer ioctl.
         */
-       dev_priv->sarea_priv->last_frame++;
-       dev_priv->sarea_priv->pfCurrentPage =
-               1 - dev_priv->sarea_priv->pfCurrentPage;
+       master_priv->sarea_priv->last_frame++;
+       master_priv->sarea_priv->pfCurrentPage =
+               1 - master_priv->sarea_priv->pfCurrentPage;
 
        BEGIN_RING(2);
 
-       RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
+       RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame);
 
        ADVANCE_RING();
 }
@@ -1494,11 +1499,13 @@ typedef struct {
 } drm_radeon_tcl_prim_t;
 
 static void radeon_cp_dispatch_vertex(struct drm_device * dev,
+                                     struct drm_file *file_priv,
                                      struct drm_buf * buf,
                                      drm_radeon_tcl_prim_t * prim)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
        int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
        int numverts = (int)prim->numverts;
        int nbox = sarea_priv->nbox;
@@ -1539,13 +1546,14 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev,
        } while (i < nbox);
 }
 
-static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf)
+static void radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
        drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
        RING_LOCALS;
 
-       buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
+       buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
 
        /* Emit the vertex buffer age */
        BEGIN_RING(2);
@@ -1590,12 +1598,14 @@ static void radeon_cp_dispatch_indirect(struct drm_device * dev,
        }
 }
 
-static void radeon_cp_dispatch_indices(struct drm_device * dev,
+static void radeon_cp_dispatch_indices(struct drm_device *dev,
+                                      struct drm_master *master,
                                       struct drm_buf * elt_buf,
                                       drm_radeon_tcl_prim_t * prim)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
        int offset = dev_priv->gart_buffers_offset + prim->offset;
        u32 *data;
        int dwords;
@@ -1870,7 +1880,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
                ADVANCE_RING();
                COMMIT_RING();
 
-               radeon_cp_discard_buffer(dev, buf);
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
 
                /* Update the input parameters for next time */
                image->y += height;
@@ -2110,7 +2120,8 @@ static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_fi
 static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
        drm_radeon_clear_t *clear = data;
        drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
        DRM_DEBUG("\n");
@@ -2126,7 +2137,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *
                               sarea_priv->nbox * sizeof(depth_boxes[0])))
                return -EFAULT;
 
-       radeon_cp_dispatch_clear(dev, clear, depth_boxes);
+       radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes);
 
        COMMIT_RING();
        return 0;
@@ -2134,9 +2145,10 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *
 
 /* Not sure why this isn't set all the time:
  */
-static int radeon_do_init_pageflip(struct drm_device * dev)
+static int radeon_do_init_pageflip(struct drm_device *dev, struct drm_master *master)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
        RING_LOCALS;
 
        DRM_DEBUG("\n");
@@ -2153,8 +2165,8 @@ static int radeon_do_init_pageflip(struct drm_device * dev)
 
        dev_priv->page_flipping = 1;
 
-       if (dev_priv->sarea_priv->pfCurrentPage != 1)
-               dev_priv->sarea_priv->pfCurrentPage = 0;
+       if (master_priv->sarea_priv->pfCurrentPage != 1)
+               master_priv->sarea_priv->pfCurrentPage = 0;
 
        return 0;
 }
@@ -2172,9 +2184,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
 
        if (!dev_priv->page_flipping)
-               radeon_do_init_pageflip(dev);
+               radeon_do_init_pageflip(dev, file_priv->master);
 
-       radeon_cp_dispatch_flip(dev);
+       radeon_cp_dispatch_flip(dev, file_priv->master);
 
        COMMIT_RING();
        return 0;
@@ -2183,7 +2195,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f
 static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
+
        DRM_DEBUG("\n");
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -2193,8 +2207,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f
        if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
 
-       radeon_cp_dispatch_swap(dev);
-       dev_priv->sarea_priv->ctx_owner = 0;
+       radeon_cp_dispatch_swap(dev, file_priv->master);
+       sarea_priv->ctx_owner = 0;
 
        COMMIT_RING();
        return 0;
@@ -2203,7 +2217,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f
 static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_radeon_vertex_t *vertex = data;
@@ -2211,6 +2226,8 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
+       sarea_priv = master_priv->sarea_priv;
+
        DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
                  DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
 
@@ -2263,13 +2280,13 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file
                prim.finish = vertex->count;    /* unused */
                prim.prim = vertex->prim;
                prim.numverts = vertex->count;
-               prim.vc_format = dev_priv->sarea_priv->vc_format;
+               prim.vc_format = sarea_priv->vc_format;
 
-               radeon_cp_dispatch_vertex(dev, buf, &prim);
+               radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim);
        }
 
        if (vertex->discard) {
-               radeon_cp_discard_buffer(dev, buf);
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
        }
 
        COMMIT_RING();
@@ -2279,7 +2296,8 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file
 static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_radeon_indices_t *elts = data;
@@ -2288,6 +2306,8 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
+       sarea_priv = master_priv->sarea_priv;
+
        DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
                  DRM_CURRENTPID, elts->idx, elts->start, elts->end,
                  elts->discard);
@@ -2353,11 +2373,11 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file
        prim.prim = elts->prim;
        prim.offset = 0;        /* offset from start of dma buffers */
        prim.numverts = RADEON_MAX_VB_VERTS;    /* duh */
-       prim.vc_format = dev_priv->sarea_priv->vc_format;
+       prim.vc_format = sarea_priv->vc_format;
 
-       radeon_cp_dispatch_indices(dev, buf, &prim);
+       radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim);
        if (elts->discard) {
-               radeon_cp_discard_buffer(dev, buf);
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
        }
 
        COMMIT_RING();
@@ -2468,7 +2488,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil
         */
        radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
        if (indirect->discard) {
-               radeon_cp_discard_buffer(dev, buf);
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
        }
 
        COMMIT_RING();
@@ -2478,7 +2498,8 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil
 static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
-       drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
+       drm_radeon_sarea_t *sarea_priv;
        struct drm_device_dma *dma = dev->dma;
        struct drm_buf *buf;
        drm_radeon_vertex2_t *vertex = data;
@@ -2487,6 +2508,8 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
+       sarea_priv = master_priv->sarea_priv;
+
        DRM_DEBUG("pid=%d index=%d discard=%d\n",
                  DRM_CURRENTPID, vertex->idx, vertex->discard);
 
@@ -2547,12 +2570,12 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file
                        tclprim.offset = prim.numverts * 64;
                        tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
 
-                       radeon_cp_dispatch_indices(dev, buf, &tclprim);
+                       radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim);
                } else {
                        tclprim.numverts = prim.numverts;
                        tclprim.offset = 0;     /* not used */
 
-                       radeon_cp_dispatch_vertex(dev, buf, &tclprim);
+                       radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim);
                }
 
                if (sarea_priv->nbox == 1)
@@ -2560,7 +2583,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file
        }
 
        if (vertex->discard) {
-               radeon_cp_discard_buffer(dev, buf);
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
        }
 
        COMMIT_RING();
@@ -2909,7 +2932,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file
                                goto err;
                        }
 
-                       radeon_cp_discard_buffer(dev, buf);
+                       radeon_cp_discard_buffer(dev, file_priv->master, buf);
                        break;
 
                case RADEON_CMD_PACKET3:
@@ -3020,7 +3043,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                 */
        case RADEON_PARAM_SAREA_HANDLE:
                /* The lock is the first dword in the sarea. */
-               value = (long)dev->lock.hw_lock;
+               /* no users of this parameter */
                break;
 #endif
        case RADEON_PARAM_GART_TEX_HANDLE:
@@ -3064,6 +3087,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
 static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
+       struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
        drm_radeon_setparam_t *sp = data;
        struct drm_radeon_driver_file_fields *radeon_priv;
 
@@ -3078,12 +3102,14 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil
                        DRM_DEBUG("color tiling disabled\n");
                        dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
                        dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
-                       dev_priv->sarea_priv->tiling_enabled = 0;
+                       if (master_priv->sarea_priv)
+                               master_priv->sarea_priv->tiling_enabled = 0;
                } else if (sp->value == 1) {
                        DRM_DEBUG("color tiling enabled\n");
                        dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
                        dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
-                       dev_priv->sarea_priv->tiling_enabled = 1;
+                       if (master_priv->sarea_priv)
+                               master_priv->sarea_priv->tiling_enabled = 1;
                }
                break;
        case RADEON_SETPARAM_PCIGART_LOCATION:
@@ -3129,14 +3155,6 @@ void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
 
 void radeon_driver_lastclose(struct drm_device *dev)
 {
-       if (dev->dev_private) {
-               drm_radeon_private_t *dev_priv = dev->dev_private;
-
-               if (dev_priv->sarea_priv &&
-                   dev_priv->sarea_priv->pfCurrentPage != 0)
-                       radeon_cp_dispatch_flip(dev);
-       }
-
        radeon_do_release(dev);
 }
 
index 906f9b9d715d50af2c555424ae323effc74d05d9..587f5b2380d473677360fb187919ff65358e5bbd 100644 (file)
@@ -1016,7 +1016,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
        snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u",
                 i2c->adap.nr);
 
-       i2c->clk = clk_get(&dev->dev, "I2CCLK");
+       i2c->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(i2c->clk)) {
                ret = PTR_ERR(i2c->clk);
                goto eclk;
index b7434d24904ebfa9750d655df8ab42f521ec2c40..c39079f9c73f18f4736f9abc75cb01613ceec2b7 100644 (file)
@@ -40,8 +40,8 @@
 #include <asm/io.h>
 
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c/regs-iic.h>
-#include <asm/plat-s3c/iic.h>
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
 
 /* i2c controller state */
 
index e6857e01d1bad372da0c62480753adbd1266d1f4..c9f21e3d4ead835c2065e60e4b9cfec28d47a258 100644 (file)
@@ -62,6 +62,9 @@ config IDE_TIMINGS
 config IDE_ATAPI
        bool
 
+config IDE_LEGACY
+       bool
+
 config BLK_DEV_IDE_SATA
        bool "Support for SATA (deprecated; conflicts with libata SATA driver)"
        default n
@@ -724,7 +727,7 @@ config BLK_DEV_IDE_TX4939
 
 config IDE_ARM
        tristate "ARM IDE support"
-       depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+       depends on ARM && (ARCH_RPC || ARCH_SHARK)
        default y
 
 config BLK_DEV_IDE_ICSIDE
@@ -856,6 +859,7 @@ config BLK_DEV_4DRIVES
 config BLK_DEV_ALI14XX
        tristate "ALI M14xx support"
        select IDE_TIMINGS
+       select IDE_LEGACY
        help
          This driver is enabled at runtime using the "ali14xx.probe" kernel
          boot parameter.  It enables support for the secondary IDE interface
@@ -866,6 +870,7 @@ config BLK_DEV_ALI14XX
 
 config BLK_DEV_DTC2278
        tristate "DTC-2278 support"
+       select IDE_LEGACY
        help
          This driver is enabled at runtime using the "dtc2278.probe" kernel
          boot parameter. It enables support for the secondary IDE interface
@@ -876,6 +881,7 @@ config BLK_DEV_DTC2278
 config BLK_DEV_HT6560B
        tristate "Holtek HT6560B support"
        select IDE_TIMINGS
+       select IDE_LEGACY
        help
          This driver is enabled at runtime using the "ht6560b.probe" kernel
          boot parameter. It enables support for the secondary IDE interface
@@ -886,6 +892,7 @@ config BLK_DEV_HT6560B
 config BLK_DEV_QD65XX
        tristate "QDI QD65xx support"
        select IDE_TIMINGS
+       select IDE_LEGACY
        help
          This driver is enabled at runtime using the "qd65xx.probe" kernel
          boot parameter.  It permits faster I/O speeds to be set.  See the
@@ -894,6 +901,7 @@ config BLK_DEV_QD65XX
 
 config BLK_DEV_UMC8672
        tristate "UMC-8672 support"
+       select IDE_LEGACY
        help
          This driver is enabled at runtime using the "umc8672.probe" kernel
          boot parameter. It enables support for the secondary IDE interface
index 7818d402b188ff88a84f51b901bbee13962565aa..177e3f8523edd2fb16c106d21ecd5848f44fd1fe 100644 (file)
@@ -5,7 +5,7 @@
 EXTRA_CFLAGS                           += -Idrivers/ide
 
 ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
-             ide-taskfile.o ide-park.o ide-pio-blacklist.o
+             ide-taskfile.o ide-pm.o ide-park.o ide-pio-blacklist.o
 
 # core IDE code
 ide-core-$(CONFIG_IDE_TIMINGS)         += ide-timings.o
@@ -15,6 +15,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEDMA)     += ide-dma.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA_SFF)  += ide-dma-sff.o
 ide-core-$(CONFIG_IDE_PROC_FS)         += ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)     += ide-acpi.o
+ide-core-$(CONFIG_IDE_LEGACY)          += ide-legacy.o
 
 obj-$(CONFIG_IDE)                      += ide-core.o
 
index 935385c77e062d12e6ad6061942dfcdd5cbbdd8d..3623bf013bcfde7a2249d743091317da7bd87bad 100644 (file)
@@ -424,10 +424,10 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_cmd64x,
                .enablebits     = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
-               .chipset        = ide_cmd646,
                .port_ops       = &cmd64x_port_ops,
                .dma_ops        = &cmd648_dma_ops,
-               .host_flags     = IDE_HFLAG_ABUSE_PREFETCH,
+               .host_flags     = IDE_HFLAG_SERIALIZE |
+                                 IDE_HFLAG_ABUSE_PREFETCH,
                .pio_mask       = ATA_PIO5,
                .mwdma_mask     = ATA_MWDMA2,
                .udma_mask      = ATA_UDMA2,
index 5297f07d293300da38f9c1a3f1db7af41068aca1..d37baf8ecc5fd54adc2645883b93721bd72da00b 100644 (file)
@@ -292,7 +292,6 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_iops      = init_iops_cy82c693,
        .port_ops       = &cy82c693_port_ops,
-       .chipset        = ide_cy82c693,
        .host_flags     = IDE_HFLAG_SINGLE,
        .pio_mask       = ATA_PIO4,
        .swdma_mask     = ATA_SWDMA2,
index 69150688656133fcad4cd8d311942c642d0c1d25..59bd0be9dcb3aac5715daf3ed0dec8f8b48b1c94 100644 (file)
@@ -117,6 +117,10 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base,
        hw->chipset = ide_generic;
 }
 
+static const struct ide_port_info gayle_port_info = {
+       .host_flags             = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA,
+};
+
     /*
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
@@ -178,7 +182,7 @@ found:
        hws[i] = &hw[i];
     }
 
-    rc = ide_host_add(NULL, hws, NULL);
+    rc = ide_host_add(&gayle_port_info, hws, NULL);
     if (rc)
        release_mem_region(res_start, res_n);
 
index f5afd46ed51cc80034bf2fd04ecdf6f31e2e95ab..b18e10d99d2e461de8560f571edb0bc77b0c9e59 100644 (file)
 /* various tuning parameters */
 #define HPT_RESET_STATE_ENGINE
 #undef HPT_DELAY_INTERRUPT
-#define HPT_SERIALIZE_IO       0
 
 static const char *quirk_drives[] = {
        "QUANTUM FIREBALLlct08 08",
@@ -1288,7 +1287,6 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
        struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
-       int serialize           = HPT_SERIALIZE_IO;
        u8  chip_type           = info->chip_type;
 
        /* Cache the channel's MISC. control registers' offset */
@@ -1305,13 +1303,9 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                 * Clock is shared between the channels,
                 * so we'll have to serialize them... :-(
                 */
-               serialize = 1;
+               hwif->host->host_flags |= IDE_HFLAG_SERIALIZE;
                hwif->rw_disk = &hpt3xxn_rw_disk;
        }
-
-       /* Serialize access to this device if needed */
-       if (serialize && hwif->mate)
-               hwif->serialized = hwif->mate->serialized = 1;
 }
 
 static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
index 244a8a052ce85ff3b7bdbe6a28ab5a234b847359..fd4a364330507893a59e09e8fc17a4009a4d0b84 100644 (file)
@@ -615,10 +615,10 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
        in_params[0].buffer.length = sizeof(struct GTM_buffer);
        in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
        in_params[1].type = ACPI_TYPE_BUFFER;
-       in_params[1].buffer.length = sizeof(ATA_ID_WORDS * 2);
+       in_params[1].buffer.length = ATA_ID_WORDS * 2;
        in_params[1].buffer.pointer = (u8 *)&master->idbuff;
        in_params[2].type = ACPI_TYPE_BUFFER;
-       in_params[2].buffer.length = sizeof(ATA_ID_WORDS * 2);
+       in_params[2].buffer.length = ATA_ID_WORDS * 2;
        in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
        /* Output buffer: _STM has no output */
 
index 42ab6d8715f26c6018201e32cace684d15d7435b..5daa4dd1b018a51e8b7dc73067edea997230a9e7 100644 (file)
@@ -262,7 +262,6 @@ static void cdrom_end_request(ide_drive_t *drive, int uptodate)
                struct request *failed = (struct request *) rq->buffer;
                struct cdrom_info *info = drive->driver_data;
                void *sense = &info->sense_data;
-               unsigned long flags;
 
                if (failed) {
                        if (failed->sense) {
@@ -278,11 +277,9 @@ static void cdrom_end_request(ide_drive_t *drive, int uptodate)
                                                failed->hard_nr_sectors))
                                        BUG();
                        } else {
-                               spin_lock_irqsave(&ide_lock, flags);
-                               if (__blk_end_request(failed, -EIO,
-                                                     failed->data_len))
+                               if (blk_end_request(failed, -EIO,
+                                                   failed->data_len))
                                        BUG();
-                               spin_unlock_irqrestore(&ide_lock, flags);
                        }
                } else
                        cdrom_analyze_sense_data(drive, NULL, sense);
@@ -317,7 +314,8 @@ static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st)
 static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = hwif->hwgroup->rq;
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
+       struct request *rq = hwgroup->rq;
        int stat, err, sense_key;
 
        /* check for errors */
@@ -426,16 +424,17 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                                if (time_after(jiffies, info->write_timeout))
                                        do_end_request = 1;
                                else {
+                                       struct request_queue *q = drive->queue;
                                        unsigned long flags;
 
                                        /*
                                         * take a breather relying on the unplug
                                         * timer to kick us again
                                         */
-                                       spin_lock_irqsave(&ide_lock, flags);
-                                       blk_plug_device(drive->queue);
-                                       spin_unlock_irqrestore(&ide_lock,
-                                                               flags);
+                                       spin_lock_irqsave(q->queue_lock, flags);
+                                       blk_plug_device(q);
+                                       spin_unlock_irqrestore(q->queue_lock, flags);
+
                                        return 1;
                                }
                        }
@@ -504,12 +503,14 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
 
 end_request:
        if (stat & ATA_ERR) {
+               struct request_queue *q = drive->queue;
                unsigned long flags;
 
-               spin_lock_irqsave(&ide_lock, flags);
+               spin_lock_irqsave(q->queue_lock, flags);
                blkdev_dequeue_request(rq);
-               HWGROUP(drive)->rq = NULL;
-               spin_unlock_irqrestore(&ide_lock, flags);
+               spin_unlock_irqrestore(q->queue_lock, flags);
+
+               hwgroup->rq = NULL;
 
                cdrom_queue_request_sense(drive, rq->sense, rq);
        } else
@@ -773,52 +774,6 @@ static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
        return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
 }
 
-#define IDECD_SEEK_THRESHOLD   (1000)                  /* 1000 blocks */
-#define IDECD_SEEK_TIMER       (5 * WAIT_MIN_SLEEP)    /* 100 ms */
-#define IDECD_SEEK_TIMEOUT     (2 * WAIT_CMD)          /* 20 sec */
-
-static ide_startstop_t cdrom_seek_intr(ide_drive_t *drive)
-{
-       struct cdrom_info *info = drive->driver_data;
-       int stat;
-       static int retry = 10;
-
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
-
-       if (cdrom_decode_status(drive, 0, &stat))
-               return ide_stopped;
-
-       drive->atapi_flags |= IDE_AFLAG_SEEKING;
-
-       if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
-               if (--retry == 0)
-                       drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-       }
-       return ide_stopped;
-}
-
-static void ide_cd_prepare_seek_request(ide_drive_t *drive, struct request *rq)
-{
-       sector_t frame = rq->sector;
-
-       ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
-
-       sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
-
-       memset(rq->cmd, 0, BLK_MAX_CDB);
-       rq->cmd[0] = GPCMD_SEEK;
-       put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
-
-       rq->timeout = ATAPI_WAIT_PC;
-}
-
-static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive)
-{
-       struct request *rq = drive->hwif->hwgroup->rq;
-
-       return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
-}
-
 /*
  * Fix up a possibly partially-processed request so that we can start it over
  * entirely, or even put it back on the request queue.
@@ -950,7 +905,8 @@ static int cdrom_newpc_intr_dummy_cb(struct request *rq)
 static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
-       struct request *rq = HWGROUP(drive)->rq;
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
+       struct request *rq = hwgroup->rq;
        xfer_func_t *xferfunc;
        ide_expiry_t *expiry = NULL;
        int dma_error = 0, dma, stat, thislen, uptodate = 0;
@@ -1148,17 +1104,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
 end_request:
        if (blk_pc_request(rq)) {
-               unsigned long flags;
                unsigned int dlen = rq->data_len;
 
                if (dma)
                        rq->data_len = 0;
 
-               spin_lock_irqsave(&ide_lock, flags);
-               if (__blk_end_request(rq, 0, dlen))
+               if (blk_end_request(rq, 0, dlen))
                        BUG();
-               HWGROUP(drive)->rq = NULL;
-               spin_unlock_irqrestore(&ide_lock, flags);
+
+               hwgroup->rq = NULL;
        } else {
                if (!uptodate)
                        rq->cmd_flags |= REQ_FAILED;
@@ -1260,7 +1214,6 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                                        sector_t block)
 {
-       struct cdrom_info *info = drive->driver_data;
        ide_handler_t *fn;
        int xferlen;
 
@@ -1270,44 +1223,14 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
                      (unsigned long long)block);
 
        if (blk_fs_request(rq)) {
-               if (drive->atapi_flags & IDE_AFLAG_SEEKING) {
-                       ide_hwif_t *hwif = drive->hwif;
-                       unsigned long elapsed = jiffies - info->start_seek;
-                       int stat = hwif->tp_ops->read_status(hwif);
-
-                       if ((stat & ATA_DSC) != ATA_DSC) {
-                               if (elapsed < IDECD_SEEK_TIMEOUT) {
-                                       ide_stall_queue(drive,
-                                                       IDECD_SEEK_TIMER);
-                                       return ide_stopped;
-                               }
-                               printk(KERN_ERR PFX "%s: DSC timeout\n",
-                                               drive->name);
-                       }
-                       drive->atapi_flags &= ~IDE_AFLAG_SEEKING;
-               }
-               if (rq_data_dir(rq) == READ &&
-                   IDE_LARGE_SEEK(info->last_block, block,
-                           IDECD_SEEK_THRESHOLD) &&
-                   (drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)) {
-                       xferlen = 0;
-                       fn = cdrom_start_seek_continuation;
+               xferlen = 32768;
+               fn = cdrom_start_rw_cont;
 
-                       drive->dma = 0;
-                       info->start_seek = jiffies;
-
-                       ide_cd_prepare_seek_request(drive, rq);
-               } else {
-                       xferlen = 32768;
-                       fn = cdrom_start_rw_cont;
-
-                       if (cdrom_start_rw(drive, rq) == ide_stopped)
-                               return ide_stopped;
+               if (cdrom_start_rw(drive, rq) == ide_stopped)
+                       return ide_stopped;
 
-                       if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped)
-                               return ide_stopped;
-               }
-               info->last_block = block;
+               if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped)
+                       return ide_stopped;
        } else if (blk_sense_request(rq) || blk_pc_request(rq) ||
                   rq->cmd_type == REQ_TYPE_ATA_PC) {
                xferlen = rq->data_len;
@@ -1908,13 +1831,6 @@ static ide_proc_entry_t idecd_proc[] = {
        { NULL, 0, NULL, NULL }
 };
 
-ide_devset_rw_flag(dsc_overlap, IDE_DFLAG_DSC_OVERLAP);
-
-static const struct ide_proc_devset idecd_settings[] = {
-       IDE_PROC_DEVSET(dsc_overlap, 0, 1),
-       { 0 },
-};
-
 static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
 {
        return idecd_proc;
@@ -1922,7 +1838,7 @@ static ide_proc_entry_t *ide_cd_proc_entries(ide_drive_t *drive)
 
 static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive)
 {
-       return idecd_settings;
+       return NULL;
 }
 #endif
 
@@ -2022,11 +1938,6 @@ static int ide_cdrom_setup(ide_drive_t *drive)
        /* set correct block size */
        blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
 
-       if (drive->next != drive)
-               drive->dev_flags |= IDE_DFLAG_DSC_OVERLAP;
-       else
-               drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
-
        if (ide_cdrom_register(drive, nslots)) {
                printk(KERN_ERR PFX "%s: %s failed to register device with the"
                                " cdrom driver.\n", drive->name, __func__);
@@ -2063,7 +1974,6 @@ static void ide_cd_release(struct kref *kref)
        kfree(info->toc);
        if (devinfo->handle == drive)
                unregister_cdrom(devinfo);
-       drive->dev_flags &= ~IDE_DFLAG_DSC_OVERLAP;
        drive->driver_data = NULL;
        blk_queue_prep_rq(drive->queue, NULL);
        g->private_data = NULL;
index 5882b9a9ea8b7becc8108872e996ab9f852af95d..d5ce3362dbd144ab3c871f10a4378a2f4a17d6d0 100644 (file)
@@ -88,8 +88,6 @@ struct cdrom_info {
        struct request_sense sense_data;
 
        struct request request_sense_request;
-       unsigned long last_block;
-       unsigned long start_seek;
 
        u8 max_speed;           /* Max speed of the drive. */
        u8 current_speed;       /* Current speed of the drive. */
index cac431f0df1769eda7e4f2d7fe28d7f8914602db..f6d2d44d8a9a78f5714ad05ca0c080b089e416be 100644 (file)
@@ -98,10 +98,10 @@ int ide_build_dmatable(ide_drive_t *drive, struct request *rq)
 {
        ide_hwif_t *hwif = drive->hwif;
        __le32 *table = (__le32 *)hwif->dmatable_cpu;
-       unsigned int is_trm290  = (hwif->chipset == ide_trm290) ? 1 : 0;
        unsigned int count = 0;
        int i;
        struct scatterlist *sg;
+       u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290);
 
        hwif->sg_nents = ide_build_sglist(drive, rq);
        if (hwif->sg_nents == 0)
@@ -176,15 +176,10 @@ int ide_dma_setup(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq = hwif->hwgroup->rq;
-       unsigned int reading;
+       unsigned int reading = rq_data_dir(rq) ? 0 : ATA_DMA_WR;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
        u8 dma_stat;
 
-       if (rq_data_dir(rq))
-               reading = 0;
-       else
-               reading = 1 << 3;
-
        /* fall back to pio! */
        if (!ide_build_dmatable(drive, rq)) {
                ide_map_sg(drive, rq);
@@ -209,10 +204,11 @@ int ide_dma_setup(ide_drive_t *drive)
 
        /* clear INTR & ERROR flags */
        if (mmio)
-               writeb(dma_stat | 6,
+               writeb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR,
                       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
        else
-               outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+               outb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR,
+                    hwif->dma_base + ATA_DMA_STATUS);
 
        drive->waiting_for_dma = 1;
        return 0;
@@ -246,14 +242,13 @@ static int dma_timer_expiry(ide_drive_t *drive)
 
        hwif->hwgroup->expiry = NULL;   /* one free ride for now */
 
-       /* 1 dmaing, 2 error, 4 intr */
-       if (dma_stat & 2)       /* ERROR */
+       if (dma_stat & ATA_DMA_ERR)     /* ERROR */
                return -1;
 
-       if (dma_stat & 1)       /* DMAing */
+       if (dma_stat & ATA_DMA_ACTIVE)  /* DMAing */
                return WAIT_CMD;
 
-       if (dma_stat & 4)       /* Got an Interrupt */
+       if (dma_stat & ATA_DMA_INTR)    /* Got an Interrupt */
                return WAIT_CMD;
 
        return 0;       /* Status is unknown -- reset the bus */
@@ -279,12 +274,11 @@ void ide_dma_start(ide_drive_t *drive)
         */
        if (hwif->host_flags & IDE_HFLAG_MMIO) {
                dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-               /* start DMA */
-               writeb(dma_cmd | 1,
+               writeb(dma_cmd | ATA_DMA_START,
                       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
        } else {
                dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-               outb(dma_cmd | 1, hwif->dma_base + ATA_DMA_CMD);
+               outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
        }
 
        wmb();
@@ -296,19 +290,18 @@ int ide_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
        u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
-       u8 dma_stat = 0, dma_cmd = 0;
+       u8 dma_stat = 0, dma_cmd = 0, mask;
 
        drive->waiting_for_dma = 0;
 
+       /* stop DMA */
        if (mmio) {
-               /* get DMA command mode */
                dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
-               /* stop DMA */
-               writeb(dma_cmd & ~1,
+               writeb(dma_cmd & ~ATA_DMA_START,
                       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
        } else {
                dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
-               outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD);
+               outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
        }
 
        /* get DMA status */
@@ -316,16 +309,21 @@ int ide_dma_end(ide_drive_t *drive)
 
        if (mmio)
                /* clear the INTR & ERROR bits */
-               writeb(dma_stat | 6,
+               writeb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR,
                       (void __iomem *)(hwif->dma_base + ATA_DMA_STATUS));
        else
-               outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS);
+               outb(dma_stat | ATA_DMA_ERR | ATA_DMA_INTR,
+                    hwif->dma_base + ATA_DMA_STATUS);
 
        /* purge DMA mappings */
        ide_destroy_dmatable(drive);
-       /* verify good DMA status */
        wmb();
-       return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
+
+       /* verify good DMA status */
+       mask = ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR;
+       if ((dma_stat & mask) != ATA_DMA_INTR)
+               return 0x10 | dma_stat;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(ide_dma_end);
 
@@ -335,11 +333,7 @@ int ide_dma_test_irq(ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        u8 dma_stat = hwif->tp_ops->read_sff_dma_status(hwif);
 
-       /* return 1 if INTR asserted */
-       if ((dma_stat & 4) == 4)
-               return 1;
-
-       return 0;
+       return (dma_stat & ATA_DMA_INTR) ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(ide_dma_test_irq);
 
index cc35d6dbd41026d02cdc1ab5a32085cc8c63e0db..ecacc008fdafec71175fddfc73199acb302f0110 100644 (file)
@@ -84,11 +84,11 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
                ide_dma_on(drive);
        }
 
-       if (!__blk_end_request(rq, error, nr_bytes)) {
-               if (dequeue)
-                       HWGROUP(drive)->rq = NULL;
+       if (!blk_end_request(rq, error, nr_bytes))
                ret = 0;
-       }
+
+       if (ret == 0 && dequeue)
+               drive->hwif->hwgroup->rq = NULL;
 
        return ret;
 }
@@ -107,16 +107,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
 int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
 {
        unsigned int nr_bytes = nr_sectors << 9;
-       struct request *rq;
-       unsigned long flags;
-       int ret = 1;
-
-       /*
-        * room for locking improvements here, the calls below don't
-        * need the queue lock held at all
-        */
-       spin_lock_irqsave(&ide_lock, flags);
-       rq = HWGROUP(drive)->rq;
+       struct request *rq = drive->hwif->hwgroup->rq;
 
        if (!nr_bytes) {
                if (blk_pc_request(rq))
@@ -125,105 +116,10 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
                        nr_bytes = rq->hard_cur_sectors << 9;
        }
 
-       ret = __ide_end_request(drive, rq, uptodate, nr_bytes, 1);
-
-       spin_unlock_irqrestore(&ide_lock, flags);
-       return ret;
+       return __ide_end_request(drive, rq, uptodate, nr_bytes, 1);
 }
 EXPORT_SYMBOL(ide_end_request);
 
-static void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
-{
-       struct request_pm_state *pm = rq->data;
-
-#ifdef DEBUG_PM
-       printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
-               drive->name, pm->pm_step);
-#endif
-       if (drive->media != ide_disk)
-               return;
-
-       switch (pm->pm_step) {
-       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
-               if (pm->pm_state == PM_EVENT_FREEZE)
-                       pm->pm_step = IDE_PM_COMPLETED;
-               else
-                       pm->pm_step = IDE_PM_STANDBY;
-               break;
-       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
-               pm->pm_step = IDE_PM_COMPLETED;
-               break;
-       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
-               pm->pm_step = IDE_PM_IDLE;
-               break;
-       case IDE_PM_IDLE:               /* Resume step 2 (idle)*/
-               pm->pm_step = IDE_PM_RESTORE_DMA;
-               break;
-       }
-}
-
-static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
-{
-       struct request_pm_state *pm = rq->data;
-       ide_task_t *args = rq->special;
-
-       memset(args, 0, sizeof(*args));
-
-       switch (pm->pm_step) {
-       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
-               if (drive->media != ide_disk)
-                       break;
-               /* Not supported? Switch to next step now. */
-               if (ata_id_flush_enabled(drive->id) == 0 ||
-                   (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
-                       ide_complete_power_step(drive, rq);
-                       return ide_stopped;
-               }
-               if (ata_id_flush_ext_enabled(drive->id))
-                       args->tf.command = ATA_CMD_FLUSH_EXT;
-               else
-                       args->tf.command = ATA_CMD_FLUSH;
-               goto out_do_tf;
-       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
-               args->tf.command = ATA_CMD_STANDBYNOW1;
-               goto out_do_tf;
-       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
-               ide_set_max_pio(drive);
-               /*
-                * skip IDE_PM_IDLE for ATAPI devices
-                */
-               if (drive->media != ide_disk)
-                       pm->pm_step = IDE_PM_RESTORE_DMA;
-               else
-                       ide_complete_power_step(drive, rq);
-               return ide_stopped;
-       case IDE_PM_IDLE:               /* Resume step 2 (idle) */
-               args->tf.command = ATA_CMD_IDLEIMMEDIATE;
-               goto out_do_tf;
-       case IDE_PM_RESTORE_DMA:        /* Resume step 3 (restore DMA) */
-               /*
-                * Right now, all we do is call ide_set_dma(drive),
-                * we could be smarter and check for current xfer_speed
-                * in struct drive etc...
-                */
-               if (drive->hwif->dma_ops == NULL)
-                       break;
-               /*
-                * TODO: respect IDE_DFLAG_USING_DMA
-                */
-               ide_set_dma(drive);
-               break;
-       }
-
-       pm->pm_step = IDE_PM_COMPLETED;
-       return ide_stopped;
-
-out_do_tf:
-       args->tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
-       args->data_phase = TASKFILE_NO_DATA;
-       return do_rw_taskfile(drive, args);
-}
-
 /**
  *     ide_end_dequeued_request        -       complete an IDE I/O
  *     @drive: IDE device for the I/O
@@ -242,48 +138,12 @@ out_do_tf:
 int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
                             int uptodate, int nr_sectors)
 {
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&ide_lock, flags);
        BUG_ON(!blk_rq_started(rq));
-       ret = __ide_end_request(drive, rq, uptodate, nr_sectors << 9, 0);
-       spin_unlock_irqrestore(&ide_lock, flags);
 
-       return ret;
+       return __ide_end_request(drive, rq, uptodate, nr_sectors << 9, 0);
 }
 EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
 
-
-/**
- *     ide_complete_pm_request - end the current Power Management request
- *     @drive: target drive
- *     @rq: request
- *
- *     This function cleans up the current PM request and stops the queue
- *     if necessary.
- */
-static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
-{
-       unsigned long flags;
-
-#ifdef DEBUG_PM
-       printk("%s: completing PM request, %s\n", drive->name,
-              blk_pm_suspend_request(rq) ? "suspend" : "resume");
-#endif
-       spin_lock_irqsave(&ide_lock, flags);
-       if (blk_pm_suspend_request(rq)) {
-               blk_stop_queue(drive->queue);
-       } else {
-               drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
-               blk_start_queue(drive->queue);
-       }
-       HWGROUP(drive)->rq = NULL;
-       if (__blk_end_request(rq, 0, 0))
-               BUG();
-       spin_unlock_irqrestore(&ide_lock, flags);
-}
-
 /**
  *     ide_end_drive_cmd       -       end an explicit drive command
  *     @drive: command 
@@ -300,19 +160,12 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
  
 void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 {
-       unsigned long flags;
-       struct request *rq;
-
-       spin_lock_irqsave(&ide_lock, flags);
-       rq = HWGROUP(drive)->rq;
-       spin_unlock_irqrestore(&ide_lock, flags);
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+       struct request *rq = hwgroup->rq;
 
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
                ide_task_t *task = (ide_task_t *)rq->special;
 
-               if (rq->errors == 0)
-                       rq->errors = !OK_STAT(stat, ATA_DRDY, BAD_STAT);
-
                if (task) {
                        struct ide_taskfile *tf = &task->tf;
 
@@ -333,15 +186,14 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
                return;
        }
 
-       spin_lock_irqsave(&ide_lock, flags);
-       HWGROUP(drive)->rq = NULL;
+       hwgroup->rq = NULL;
+
        rq->errors = err;
-       if (unlikely(__blk_end_request(rq, (rq->errors ? -EIO : 0),
-                                      blk_rq_bytes(rq))))
+
+       if (unlikely(blk_end_request(rq, (rq->errors ? -EIO : 0),
+                                    blk_rq_bytes(rq))))
                BUG();
-       spin_unlock_irqrestore(&ide_lock, flags);
 }
-
 EXPORT_SYMBOL(ide_end_drive_cmd);
 
 static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
@@ -720,40 +572,6 @@ static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
        }
 }
 
-static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
-{
-       struct request_pm_state *pm = rq->data;
-
-       if (blk_pm_suspend_request(rq) &&
-           pm->pm_step == IDE_PM_START_SUSPEND)
-               /* Mark drive blocked when starting the suspend sequence. */
-               drive->dev_flags |= IDE_DFLAG_BLOCKED;
-       else if (blk_pm_resume_request(rq) &&
-                pm->pm_step == IDE_PM_START_RESUME) {
-               /* 
-                * The first thing we do on wakeup is to wait for BSY bit to
-                * go away (with a looong timeout) as a drive on this hwif may
-                * just be POSTing itself.
-                * We do that before even selecting as the "other" device on
-                * the bus may be broken enough to walk on our toes at this
-                * point.
-                */
-               ide_hwif_t *hwif = drive->hwif;
-               int rc;
-#ifdef DEBUG_PM
-               printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
-#endif
-               rc = ide_wait_not_busy(hwif, 35000);
-               if (rc)
-                       printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
-               SELECT_DRIVE(drive);
-               hwif->tp_ops->set_irq(hwif, 1);
-               rc = ide_wait_not_busy(hwif, 100000);
-               if (rc)
-                       printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
-       }
-}
-
 /**
  *     start_request   -       start of I/O and command issuing for IDE
  *
@@ -927,7 +745,7 @@ repeat:
 
 /*
  * Issue a new request to a drive from hwgroup
- * Caller must have already done spin_lock_irqsave(&ide_lock, ..);
+ * Caller must have already done spin_lock_irqsave(&hwgroup->lock, ..);
  *
  * A hwgroup is a serialized group of IDE interfaces.  Usually there is
  * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
@@ -939,7 +757,7 @@ repeat:
  * possibly along with many other devices.  This is especially common in
  * PCI-based systems with off-board IDE controller cards.
  *
- * The IDE driver uses the single global ide_lock spinlock to protect
+ * The IDE driver uses a per-hwgroup spinlock to protect
  * access to the request queues, and to protect the hwgroup->busy flag.
  *
  * The first thread into the driver for a particular hwgroup sets the
@@ -955,7 +773,7 @@ repeat:
  * will start the next request from the queue.  If no more work remains,
  * the driver will clear the hwgroup->busy flag and exit.
  *
- * The ide_lock (spinlock) is used to protect all access to the
+ * The per-hwgroup spinlock is used to protect all access to the
  * hwgroup->busy flag, but is otherwise not needed for most processing in
  * the driver.  This makes the driver much more friendlier to shared IRQs
  * than previous designs, while remaining 100% (?) SMP safe and capable.
@@ -968,7 +786,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
        ide_startstop_t startstop;
        int             loops = 0;
 
-       /* caller must own ide_lock */
+       /* caller must own hwgroup->lock */
        BUG_ON(!irqs_disabled());
 
        while (!hwgroup->busy) {
@@ -1023,12 +841,12 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                }
        again:
                hwif = HWIF(drive);
-               if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
+               if (hwif != hwgroup->hwif) {
                        /*
                         * set nIEN for previous hwif, drives in the
                         * quirk_list may not like intr setups/cleanups
                         */
-                       if (drive->quirk_list != 1)
+                       if (drive->quirk_list == 0)
                                hwif->tp_ops->set_irq(hwif, 0);
                }
                hwgroup->hwif = hwif;
@@ -1036,11 +854,6 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
                drive->service_start = jiffies;
 
-               if (blk_queue_plugged(drive->queue)) {
-                       printk(KERN_ERR "ide: huh? queue was plugged!\n");
-                       break;
-               }
-
                /*
                 * we know that the queue isn't empty, but this can happen
                 * if the q->prep_rq_fn() decides to kill a request
@@ -1090,11 +903,11 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
                 */
                if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
                        disable_irq_nosync(hwif->irq);
-               spin_unlock(&ide_lock);
+               spin_unlock(&hwgroup->lock);
                local_irq_enable_in_hardirq();
                        /* allow other IRQs while we start this request */
                startstop = start_request(drive, rq);
-               spin_lock_irq(&ide_lock);
+               spin_lock_irq(&hwgroup->lock);
                if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
                        enable_irq(hwif->irq);
                if (startstop == ide_stopped)
@@ -1192,7 +1005,7 @@ void ide_timer_expiry (unsigned long data)
        unsigned long   flags;
        unsigned long   wait = -1;
 
-       spin_lock_irqsave(&ide_lock, flags);
+       spin_lock_irqsave(&hwgroup->lock, flags);
 
        if (((handler = hwgroup->handler) == NULL) ||
            (hwgroup->req_gen != hwgroup->req_gen_timer)) {
@@ -1225,7 +1038,7 @@ void ide_timer_expiry (unsigned long data)
                                        hwgroup->timer.expires  = jiffies + wait;
                                        hwgroup->req_gen_timer = hwgroup->req_gen;
                                        add_timer(&hwgroup->timer);
-                                       spin_unlock_irqrestore(&ide_lock, flags);
+                                       spin_unlock_irqrestore(&hwgroup->lock, flags);
                                        return;
                                }
                        }
@@ -1235,7 +1048,7 @@ void ide_timer_expiry (unsigned long data)
                         * the handler() function, which means we need to
                         * globally mask the specific IRQ:
                         */
-                       spin_unlock(&ide_lock);
+                       spin_unlock(&hwgroup->lock);
                        hwif  = HWIF(drive);
                        /* disable_irq_nosync ?? */
                        disable_irq(hwif->irq);
@@ -1259,14 +1072,14 @@ void ide_timer_expiry (unsigned long data)
                                                  hwif->tp_ops->read_status(hwif));
                        }
                        drive->service_time = jiffies - drive->service_start;
-                       spin_lock_irq(&ide_lock);
+                       spin_lock_irq(&hwgroup->lock);
                        enable_irq(hwif->irq);
                        if (startstop == ide_stopped)
                                hwgroup->busy = 0;
                }
        }
        ide_do_request(hwgroup, IDE_NO_IRQ);
-       spin_unlock_irqrestore(&ide_lock, flags);
+       spin_unlock_irqrestore(&hwgroup->lock, flags);
 }
 
 /**
@@ -1359,18 +1172,16 @@ irqreturn_t ide_intr (int irq, void *dev_id)
 {
        unsigned long flags;
        ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
-       ide_hwif_t *hwif;
+       ide_hwif_t *hwif = hwgroup->hwif;
        ide_drive_t *drive;
        ide_handler_t *handler;
        ide_startstop_t startstop;
+       irqreturn_t irq_ret = IRQ_NONE;
 
-       spin_lock_irqsave(&ide_lock, flags);
-       hwif = hwgroup->hwif;
+       spin_lock_irqsave(&hwgroup->lock, flags);
 
-       if (!ide_ack_intr(hwif)) {
-               spin_unlock_irqrestore(&ide_lock, flags);
-               return IRQ_NONE;
-       }
+       if (!ide_ack_intr(hwif))
+               goto out;
 
        if ((handler = hwgroup->handler) == NULL || hwgroup->polling) {
                /*
@@ -1406,9 +1217,9 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                        (void)hwif->tp_ops->read_status(hwif);
 #endif /* CONFIG_BLK_DEV_IDEPCI */
                }
-               spin_unlock_irqrestore(&ide_lock, flags);
-               return IRQ_NONE;
+               goto out;
        }
+
        drive = hwgroup->drive;
        if (!drive) {
                /*
@@ -1417,10 +1228,10 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                 *
                 * [Note - this can occur if the drive is hot unplugged]
                 */
-               spin_unlock_irqrestore(&ide_lock, flags);
-               return IRQ_HANDLED;
+               goto out_handled;
        }
-       if (!drive_is_ready(drive)) {
+
+       if (!drive_is_ready(drive))
                /*
                 * This happens regularly when we share a PCI IRQ with
                 * another device.  Unfortunately, it can also happen
@@ -1428,9 +1239,8 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                 * their status register is up to date.  Hopefully we have
                 * enough advance overhead that the latter isn't a problem.
                 */
-               spin_unlock_irqrestore(&ide_lock, flags);
-               return IRQ_NONE;
-       }
+               goto out;
+
        if (!hwgroup->busy) {
                hwgroup->busy = 1;      /* paranoia */
                printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
@@ -1438,7 +1248,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
        hwgroup->handler = NULL;
        hwgroup->req_gen++;
        del_timer(&hwgroup->timer);
-       spin_unlock(&ide_lock);
+       spin_unlock(&hwgroup->lock);
 
        if (hwif->port_ops && hwif->port_ops->clear_irq)
                hwif->port_ops->clear_irq(drive);
@@ -1449,7 +1259,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
        /* service this interrupt, may set handler for next interrupt */
        startstop = handler(drive);
 
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        /*
         * Note that handler() may have set things up for another
         * interrupt to occur soon, but it cannot happen until
@@ -1467,8 +1277,11 @@ irqreturn_t ide_intr (int irq, void *dev_id)
                                "on exit\n", drive->name);
                }
        }
-       spin_unlock_irqrestore(&ide_lock, flags);
-       return IRQ_HANDLED;
+out_handled:
+       irq_ret = IRQ_HANDLED;
+out:
+       spin_unlock_irqrestore(&hwgroup->lock, flags);
+       return irq_ret;
 }
 
 /**
@@ -1488,16 +1301,17 @@ irqreturn_t ide_intr (int irq, void *dev_id)
 
 void ide_do_drive_cmd(ide_drive_t *drive, struct request *rq)
 {
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
+       struct request_queue *q = drive->queue;
        unsigned long flags;
-       ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
-       spin_lock_irqsave(&ide_lock, flags);
        hwgroup->rq = NULL;
-       __elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
-       blk_start_queueing(drive->queue);
-       spin_unlock_irqrestore(&ide_lock, flags);
-}
 
+       spin_lock_irqsave(q->queue_lock, flags);
+       __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
+       blk_start_queueing(q);
+       spin_unlock_irqrestore(q->queue_lock, flags);
+}
 EXPORT_SYMBOL(ide_do_drive_cmd);
 
 void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
index fcde16bb53a71498ab6000626b49a2581e9df591..28232c64c3464becc4eef1319467d5a49dc86e00 100644 (file)
@@ -19,7 +19,6 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
                      const struct ide_ioctl_devset *s)
 {
        const struct ide_devset *ds;
-       unsigned long flags;
        int err = -EOPNOTSUPP;
 
        for (; (ds = s->setting); s++) {
@@ -33,9 +32,7 @@ int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
 
 read_val:
        mutex_lock(&ide_setting_mtx);
-       spin_lock_irqsave(&ide_lock, flags);
        err = ds->get(drive);
-       spin_unlock_irqrestore(&ide_lock, flags);
        mutex_unlock(&ide_setting_mtx);
        return err >= 0 ? put_user(err, (long __user *)arg) : err;
 
@@ -98,7 +95,7 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
                return -EPERM;
 
        if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
-           (drive->media == ide_disk || drive->media == ide_floppy ||
+           (drive->media != ide_tape ||
             (drive->dev_flags & IDE_DFLAG_SCSI)))
                return -EPERM;
 
index c41c3b9b6f022b89148792c05d9564021ff271da..ad8bd65392837778f126ec16a7e9696aca57e48f 100644 (file)
@@ -835,10 +835,12 @@ static void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
 void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
                      unsigned int timeout, ide_expiry_t *expiry)
 {
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
        unsigned long flags;
-       spin_lock_irqsave(&ide_lock, flags);
+
+       spin_lock_irqsave(&hwgroup->lock, flags);
        __ide_set_handler(drive, handler, timeout, expiry);
-       spin_unlock_irqrestore(&ide_lock, flags);
+       spin_unlock_irqrestore(&hwgroup->lock, flags);
 }
 
 EXPORT_SYMBOL(ide_set_handler);
@@ -860,10 +862,11 @@ EXPORT_SYMBOL(ide_set_handler);
 void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
                         unsigned timeout, ide_expiry_t *expiry)
 {
+       ide_hwif_t *hwif = drive->hwif;
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
        unsigned long flags;
-       ide_hwif_t *hwif = HWIF(drive);
 
-       spin_lock_irqsave(&ide_lock, flags);
+       spin_lock_irqsave(&hwgroup->lock, flags);
        __ide_set_handler(drive, handler, timeout, expiry);
        hwif->tp_ops->exec_command(hwif, cmd);
        /*
@@ -873,19 +876,20 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
         * FIXME: we could skip this delay with care on non shared devices
         */
        ndelay(400);
-       spin_unlock_irqrestore(&ide_lock, flags);
+       spin_unlock_irqrestore(&hwgroup->lock, flags);
 }
 EXPORT_SYMBOL(ide_execute_command);
 
 void ide_execute_pkt_cmd(ide_drive_t *drive)
 {
        ide_hwif_t *hwif = drive->hwif;
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
        unsigned long flags;
 
-       spin_lock_irqsave(&ide_lock, flags);
+       spin_lock_irqsave(&hwgroup->lock, flags);
        hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
        ndelay(400);
-       spin_unlock_irqrestore(&ide_lock, flags);
+       spin_unlock_irqrestore(&hwgroup->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
 
@@ -1076,22 +1080,16 @@ static void pre_reset(ide_drive_t *drive)
  */
 static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 {
-       unsigned int unit;
-       unsigned long flags, timeout;
-       ide_hwif_t *hwif;
-       ide_hwgroup_t *hwgroup;
-       struct ide_io_ports *io_ports;
-       const struct ide_tp_ops *tp_ops;
+       ide_hwif_t *hwif = drive->hwif;
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
+       struct ide_io_ports *io_ports = &hwif->io_ports;
+       const struct ide_tp_ops *tp_ops = hwif->tp_ops;
        const struct ide_port_ops *port_ops;
+       unsigned long flags, timeout;
+       unsigned int unit;
        DEFINE_WAIT(wait);
 
-       spin_lock_irqsave(&ide_lock, flags);
-       hwif = HWIF(drive);
-       hwgroup = HWGROUP(drive);
-
-       io_ports = &hwif->io_ports;
-
-       tp_ops = hwif->tp_ops;
+       spin_lock_irqsave(&hwgroup->lock, flags);
 
        /* We must not reset with running handlers */
        BUG_ON(hwgroup->handler != NULL);
@@ -1106,7 +1104,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
                hwgroup->polling = 1;
                __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
-               spin_unlock_irqrestore(&ide_lock, flags);
+               spin_unlock_irqrestore(&hwgroup->lock, flags);
                return ide_started;
        }
 
@@ -1129,9 +1127,9 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                if (time_before_eq(timeout, now))
                        break;
 
-               spin_unlock_irqrestore(&ide_lock, flags);
+               spin_unlock_irqrestore(&hwgroup->lock, flags);
                timeout = schedule_timeout_uninterruptible(timeout - now);
-               spin_lock_irqsave(&ide_lock, flags);
+               spin_lock_irqsave(&hwgroup->lock, flags);
        } while (timeout);
        finish_wait(&ide_park_wq, &wait);
 
@@ -1143,7 +1141,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
                pre_reset(&hwif->drives[unit]);
 
        if (io_ports->ctl_addr == 0) {
-               spin_unlock_irqrestore(&ide_lock, flags);
+               spin_unlock_irqrestore(&hwgroup->lock, flags);
                ide_complete_drive_reset(drive, -ENXIO);
                return ide_stopped;
        }
@@ -1179,7 +1177,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
        if (port_ops && port_ops->resetproc)
                port_ops->resetproc(drive);
 
-       spin_unlock_irqrestore(&ide_lock, flags);
+       spin_unlock_irqrestore(&hwgroup->lock, flags);
        return ide_started;
 }
 
diff --git a/drivers/ide/ide-legacy.c b/drivers/ide/ide-legacy.c
new file mode 100644 (file)
index 0000000..8c5dcbf
--- /dev/null
@@ -0,0 +1,58 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+
+static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
+                               u8 port_no, const struct ide_port_info *d,
+                               unsigned long config)
+{
+       unsigned long base, ctl;
+       int irq;
+
+       if (port_no == 0) {
+               base = 0x1f0;
+               ctl  = 0x3f6;
+               irq  = 14;
+       } else {
+               base = 0x170;
+               ctl  = 0x376;
+               irq  = 15;
+       }
+
+       if (!request_region(base, 8, d->name)) {
+               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+                               d->name, base, base + 7);
+               return;
+       }
+
+       if (!request_region(ctl, 1, d->name)) {
+               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
+                               d->name, ctl);
+               release_region(base, 8);
+               return;
+       }
+
+       ide_std_init_ports(hw, base, ctl);
+       hw->irq = irq;
+       hw->chipset = d->chipset;
+       hw->config = config;
+
+       hws[port_no] = hw;
+}
+
+int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
+{
+       hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
+
+       memset(&hw, 0, sizeof(hw));
+
+       if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0)
+               ide_legacy_init_one(hws, &hw[0], 0, d, config);
+       ide_legacy_init_one(hws, &hw[1], 1, d, config);
+
+       if (hws[0] == NULL && hws[1] == NULL &&
+           (d->host_flags & IDE_HFLAG_SINGLE))
+               return -ENOENT;
+
+       return ide_host_add(d, hws, NULL);
+}
+EXPORT_SYMBOL_GPL(ide_legacy_device_add);
index 9fc4cfb2a272bd6b89a112e72158eb6e1d656b9e..9f6e33d8a8b27bef1040e46b42fe894454d67709 100644 (file)
@@ -43,7 +43,6 @@ const char *ide_xfer_verbose(u8 mode)
 
        return s;
 }
-
 EXPORT_SYMBOL(ide_xfer_verbose);
 
 /**
@@ -87,7 +86,7 @@ static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
  *     This is used by most chipset support modules when "auto-tuning".
  */
 
-u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
+u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
 {
        u16 *id = drive->id;
        int pio_mode = -1, overridden = 0;
@@ -131,7 +130,6 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
 
        return pio_mode;
 }
-
 EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
 
 /* req_pio == "255" for auto-tune */
@@ -162,7 +160,6 @@ void ide_set_pio(ide_drive_t *drive, u8 req_pio)
 
        (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
 }
-
 EXPORT_SYMBOL_GPL(ide_set_pio);
 
 /**
@@ -173,7 +170,7 @@ EXPORT_SYMBOL_GPL(ide_set_pio);
  *     Enable or disable bounce buffering for the device. Drives move
  *     between PIO and DMA and that changes the rules we need.
  */
+
 void ide_toggle_bounce(ide_drive_t *drive, int on)
 {
        u64 addr = BLK_BOUNCE_HIGH;     /* dma64_addr_t */
@@ -243,14 +240,13 @@ int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
                return ide_config_drive_speed(drive, mode);
        }
 }
-
 EXPORT_SYMBOL_GPL(ide_set_dma_mode);
 
 /**
  *     ide_set_xfer_rate       -       set transfer rate
  *     @drive: drive to set
  *     @rate: speed to attempt to set
- *     
+ *
  *     General helper for setting the speed of an IDE device. This
  *     function knows about user enforced limits from the configuration
  *     which ->set_pio_mode/->set_dma_mode does not.
@@ -277,21 +273,16 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 
 static void ide_dump_opcode(ide_drive_t *drive)
 {
-       struct request *rq;
+       struct request *rq = drive->hwif->hwgroup->rq;
        ide_task_t *task = NULL;
 
-       spin_lock(&ide_lock);
-       rq = NULL;
-       if (HWGROUP(drive))
-               rq = HWGROUP(drive)->rq;
-       spin_unlock(&ide_lock);
        if (!rq)
                return;
 
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
                task = rq->special;
 
-       printk("ide: failed opcode was: ");
+       printk(KERN_ERR "ide: failed opcode was: ");
        if (task == NULL)
                printk(KERN_CONT "unknown\n");
        else
@@ -329,44 +320,55 @@ static void ide_dump_sector(ide_drive_t *drive)
        drive->hwif->tp_ops->tf_read(drive, &task);
 
        if (lba48 || (tf->device & ATA_LBA))
-               printk(", LBAsect=%llu",
+               printk(KERN_CONT ", LBAsect=%llu",
                        (unsigned long long)ide_get_lba_addr(tf, lba48));
        else
-               printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
-                                        tf->device & 0xf, tf->lbal);
+               printk(KERN_CONT ", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
+                       tf->device & 0xf, tf->lbal);
 }
 
 static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
 {
-       printk("{ ");
-       if (err & ATA_ABORTED)  printk("DriveStatusError ");
+       printk(KERN_ERR "{ ");
+       if (err & ATA_ABORTED)
+               printk(KERN_CONT "DriveStatusError ");
        if (err & ATA_ICRC)
-               printk((err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
-       if (err & ATA_UNC)      printk("UncorrectableError ");
-       if (err & ATA_IDNF)     printk("SectorIdNotFound ");
-       if (err & ATA_TRK0NF)   printk("TrackZeroNotFound ");
-       if (err & ATA_AMNF)     printk("AddrMarkNotFound ");
-       printk("}");
+               printk(KERN_CONT "%s",
+                       (err & ATA_ABORTED) ? "BadCRC " : "BadSector ");
+       if (err & ATA_UNC)
+               printk(KERN_CONT "UncorrectableError ");
+       if (err & ATA_IDNF)
+               printk(KERN_CONT "SectorIdNotFound ");
+       if (err & ATA_TRK0NF)
+               printk(KERN_CONT "TrackZeroNotFound ");
+       if (err & ATA_AMNF)
+               printk(KERN_CONT "AddrMarkNotFound ");
+       printk(KERN_CONT "}");
        if ((err & (ATA_BBK | ATA_ABORTED)) == ATA_BBK ||
            (err & (ATA_UNC | ATA_IDNF | ATA_AMNF))) {
                ide_dump_sector(drive);
                if (HWGROUP(drive) && HWGROUP(drive)->rq)
-                       printk(", sector=%llu",
+                       printk(KERN_CONT ", sector=%llu",
                               (unsigned long long)HWGROUP(drive)->rq->sector);
        }
-       printk("\n");
+       printk(KERN_CONT "\n");
 }
 
 static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
 {
-       printk("{ ");
-       if (err & ATAPI_ILI)    printk("IllegalLengthIndication ");
-       if (err & ATAPI_EOM)    printk("EndOfMedia ");
-       if (err & ATA_ABORTED)  printk("AbortedCommand ");
-       if (err & ATA_MCR)      printk("MediaChangeRequested ");
-       if (err & ATAPI_LFS)    printk("LastFailedSense=0x%02x ",
-                                      (err & ATAPI_LFS) >> 4);
-       printk("}\n");
+       printk(KERN_ERR "{ ");
+       if (err & ATAPI_ILI)
+               printk(KERN_CONT "IllegalLengthIndication ");
+       if (err & ATAPI_EOM)
+               printk(KERN_CONT "EndOfMedia ");
+       if (err & ATA_ABORTED)
+               printk(KERN_CONT "AbortedCommand ");
+       if (err & ATA_MCR)
+               printk(KERN_CONT "MediaChangeRequested ");
+       if (err & ATAPI_LFS)
+               printk(KERN_CONT "LastFailedSense=0x%02x ",
+                       (err & ATAPI_LFS) >> 4);
+       printk(KERN_CONT "}\n");
 }
 
 /**
@@ -382,34 +384,37 @@ static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
 
 u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
 {
-       unsigned long flags;
        u8 err = 0;
 
-       local_irq_save(flags);
-       printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
+       printk(KERN_ERR "%s: %s: status=0x%02x { ", drive->name, msg, stat);
        if (stat & ATA_BUSY)
-               printk("Busy ");
+               printk(KERN_CONT "Busy ");
        else {
-               if (stat & ATA_DRDY)    printk("DriveReady ");
-               if (stat & ATA_DF)      printk("DeviceFault ");
-               if (stat & ATA_DSC)     printk("SeekComplete ");
-               if (stat & ATA_DRQ)     printk("DataRequest ");
-               if (stat & ATA_CORR)    printk("CorrectedError ");
-               if (stat & ATA_IDX)     printk("Index ");
-               if (stat & ATA_ERR)     printk("Error ");
+               if (stat & ATA_DRDY)
+                       printk(KERN_CONT "DriveReady ");
+               if (stat & ATA_DF)
+                       printk(KERN_CONT "DeviceFault ");
+               if (stat & ATA_DSC)
+                       printk(KERN_CONT "SeekComplete ");
+               if (stat & ATA_DRQ)
+                       printk(KERN_CONT "DataRequest ");
+               if (stat & ATA_CORR)
+                       printk(KERN_CONT "CorrectedError ");
+               if (stat & ATA_IDX)
+                       printk(KERN_CONT "Index ");
+               if (stat & ATA_ERR)
+                       printk(KERN_CONT "Error ");
        }
-       printk("}\n");
+       printk(KERN_CONT "}\n");
        if ((stat & (ATA_BUSY | ATA_ERR)) == ATA_ERR) {
                err = ide_read_error(drive);
-               printk("%s: %s: error=0x%02x ", drive->name, msg, err);
+               printk(KERN_ERR "%s: %s: error=0x%02x ", drive->name, msg, err);
                if (drive->media == ide_disk)
                        ide_dump_ata_error(drive, err);
                else
                        ide_dump_atapi_error(drive, err);
        }
        ide_dump_opcode(drive);
-       local_irq_restore(flags);
        return err;
 }
-
 EXPORT_SYMBOL(ide_dump_status);
index 03b00e57e93ff4cf628c6fda4b1d45dadd0cf3e5..63d01c55f865504fa06b9562acf7021b4bb3c8ae 100644 (file)
@@ -7,17 +7,16 @@ DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
 
 static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
 {
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
        struct request_queue *q = drive->queue;
        struct request *rq;
        int rc;
 
        timeout += jiffies;
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        if (drive->dev_flags & IDE_DFLAG_PARKED) {
-               ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
-               int reset_timer;
+               int reset_timer = time_before(timeout, drive->sleep);
 
-               reset_timer = time_before(timeout, drive->sleep);
                drive->sleep = timeout;
                wake_up_all(&ide_park_wq);
                if (reset_timer && hwgroup->sleeping &&
@@ -26,10 +25,10 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
                        hwgroup->busy = 0;
                        blk_start_queueing(q);
                }
-               spin_unlock_irq(&ide_lock);
+               spin_unlock_irq(&hwgroup->lock);
                return;
        }
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
 
        rq = blk_get_request(q, READ, __GFP_WAIT);
        rq->cmd[0] = REQ_PARK_HEADS;
@@ -62,20 +61,21 @@ ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
                      char *buf)
 {
        ide_drive_t *drive = to_ide_device(dev);
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
        unsigned long now;
        unsigned int msecs;
 
        if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
                return -EOPNOTSUPP;
 
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        now = jiffies;
        if (drive->dev_flags & IDE_DFLAG_PARKED &&
            time_after(drive->sleep, now))
                msecs = jiffies_to_msecs(drive->sleep - now);
        else
                msecs = 0;
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
 
        return snprintf(buf, 20, "%u\n", msecs);
 }
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
new file mode 100644 (file)
index 0000000..8282c60
--- /dev/null
@@ -0,0 +1,235 @@
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+
+int generic_ide_suspend(struct device *dev, pm_message_t mesg)
+{
+       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+       ide_hwif_t *hwif = HWIF(drive);
+       struct request *rq;
+       struct request_pm_state rqpm;
+       ide_task_t args;
+       int ret;
+
+       /* call ACPI _GTM only once */
+       if ((drive->dn & 1) == 0 || pair == NULL)
+               ide_acpi_get_timing(hwif);
+
+       memset(&rqpm, 0, sizeof(rqpm));
+       memset(&args, 0, sizeof(args));
+       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+       rq->cmd_type = REQ_TYPE_PM_SUSPEND;
+       rq->special = &args;
+       rq->data = &rqpm;
+       rqpm.pm_step = IDE_PM_START_SUSPEND;
+       if (mesg.event == PM_EVENT_PRETHAW)
+               mesg.event = PM_EVENT_FREEZE;
+       rqpm.pm_state = mesg.event;
+
+       ret = blk_execute_rq(drive->queue, NULL, rq, 0);
+       blk_put_request(rq);
+
+       /* call ACPI _PS3 only after both devices are suspended */
+       if (ret == 0 && ((drive->dn & 1) || pair == NULL))
+               ide_acpi_set_state(hwif, 0);
+
+       return ret;
+}
+
+int generic_ide_resume(struct device *dev)
+{
+       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+       ide_hwif_t *hwif = HWIF(drive);
+       struct request *rq;
+       struct request_pm_state rqpm;
+       ide_task_t args;
+       int err;
+
+       /* call ACPI _PS0 / _STM only once */
+       if ((drive->dn & 1) == 0 || pair == NULL) {
+               ide_acpi_set_state(hwif, 1);
+               ide_acpi_push_timing(hwif);
+       }
+
+       ide_acpi_exec_tfs(drive);
+
+       memset(&rqpm, 0, sizeof(rqpm));
+       memset(&args, 0, sizeof(args));
+       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
+       rq->cmd_type = REQ_TYPE_PM_RESUME;
+       rq->cmd_flags |= REQ_PREEMPT;
+       rq->special = &args;
+       rq->data = &rqpm;
+       rqpm.pm_step = IDE_PM_START_RESUME;
+       rqpm.pm_state = PM_EVENT_ON;
+
+       err = blk_execute_rq(drive->queue, NULL, rq, 1);
+       blk_put_request(rq);
+
+       if (err == 0 && dev->driver) {
+               ide_driver_t *drv = to_ide_driver(dev->driver);
+
+               if (drv->resume)
+                       drv->resume(drive);
+       }
+
+       return err;
+}
+
+void ide_complete_power_step(ide_drive_t *drive, struct request *rq)
+{
+       struct request_pm_state *pm = rq->data;
+
+#ifdef DEBUG_PM
+       printk(KERN_INFO "%s: complete_power_step(step: %d)\n",
+               drive->name, pm->pm_step);
+#endif
+       if (drive->media != ide_disk)
+               return;
+
+       switch (pm->pm_step) {
+       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
+               if (pm->pm_state == PM_EVENT_FREEZE)
+                       pm->pm_step = IDE_PM_COMPLETED;
+               else
+                       pm->pm_step = IDE_PM_STANDBY;
+               break;
+       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
+               pm->pm_step = IDE_PM_COMPLETED;
+               break;
+       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
+               pm->pm_step = IDE_PM_IDLE;
+               break;
+       case IDE_PM_IDLE:               /* Resume step 2 (idle)*/
+               pm->pm_step = IDE_PM_RESTORE_DMA;
+               break;
+       }
+}
+
+ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
+{
+       struct request_pm_state *pm = rq->data;
+       ide_task_t *args = rq->special;
+
+       memset(args, 0, sizeof(*args));
+
+       switch (pm->pm_step) {
+       case IDE_PM_FLUSH_CACHE:        /* Suspend step 1 (flush cache) */
+               if (drive->media != ide_disk)
+                       break;
+               /* Not supported? Switch to next step now. */
+               if (ata_id_flush_enabled(drive->id) == 0 ||
+                   (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) {
+                       ide_complete_power_step(drive, rq);
+                       return ide_stopped;
+               }
+               if (ata_id_flush_ext_enabled(drive->id))
+                       args->tf.command = ATA_CMD_FLUSH_EXT;
+               else
+                       args->tf.command = ATA_CMD_FLUSH;
+               goto out_do_tf;
+       case IDE_PM_STANDBY:            /* Suspend step 2 (standby) */
+               args->tf.command = ATA_CMD_STANDBYNOW1;
+               goto out_do_tf;
+       case IDE_PM_RESTORE_PIO:        /* Resume step 1 (restore PIO) */
+               ide_set_max_pio(drive);
+               /*
+                * skip IDE_PM_IDLE for ATAPI devices
+                */
+               if (drive->media != ide_disk)
+                       pm->pm_step = IDE_PM_RESTORE_DMA;
+               else
+                       ide_complete_power_step(drive, rq);
+               return ide_stopped;
+       case IDE_PM_IDLE:               /* Resume step 2 (idle) */
+               args->tf.command = ATA_CMD_IDLEIMMEDIATE;
+               goto out_do_tf;
+       case IDE_PM_RESTORE_DMA:        /* Resume step 3 (restore DMA) */
+               /*
+                * Right now, all we do is call ide_set_dma(drive),
+                * we could be smarter and check for current xfer_speed
+                * in struct drive etc...
+                */
+               if (drive->hwif->dma_ops == NULL)
+                       break;
+               /*
+                * TODO: respect IDE_DFLAG_USING_DMA
+                */
+               ide_set_dma(drive);
+               break;
+       }
+
+       pm->pm_step = IDE_PM_COMPLETED;
+       return ide_stopped;
+
+out_do_tf:
+       args->tf_flags   = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+       args->data_phase = TASKFILE_NO_DATA;
+       return do_rw_taskfile(drive, args);
+}
+
+/**
+ *     ide_complete_pm_request - end the current Power Management request
+ *     @drive: target drive
+ *     @rq: request
+ *
+ *     This function cleans up the current PM request and stops the queue
+ *     if necessary.
+ */
+void ide_complete_pm_request(ide_drive_t *drive, struct request *rq)
+{
+       struct request_queue *q = drive->queue;
+       unsigned long flags;
+
+#ifdef DEBUG_PM
+       printk("%s: completing PM request, %s\n", drive->name,
+              blk_pm_suspend_request(rq) ? "suspend" : "resume");
+#endif
+       spin_lock_irqsave(q->queue_lock, flags);
+       if (blk_pm_suspend_request(rq)) {
+               blk_stop_queue(q);
+       } else {
+               drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
+               blk_start_queue(q);
+       }
+       spin_unlock_irqrestore(q->queue_lock, flags);
+
+       drive->hwif->hwgroup->rq = NULL;
+
+       if (blk_end_request(rq, 0, 0))
+               BUG();
+}
+
+void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
+{
+       struct request_pm_state *pm = rq->data;
+
+       if (blk_pm_suspend_request(rq) &&
+           pm->pm_step == IDE_PM_START_SUSPEND)
+               /* Mark drive blocked when starting the suspend sequence. */
+               drive->dev_flags |= IDE_DFLAG_BLOCKED;
+       else if (blk_pm_resume_request(rq) &&
+                pm->pm_step == IDE_PM_START_RESUME) {
+               /*
+                * The first thing we do on wakeup is to wait for BSY bit to
+                * go away (with a looong timeout) as a drive on this hwif may
+                * just be POSTing itself.
+                * We do that before even selecting as the "other" device on
+                * the bus may be broken enough to walk on our toes at this
+                * point.
+                */
+               ide_hwif_t *hwif = drive->hwif;
+               int rc;
+#ifdef DEBUG_PM
+               printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
+#endif
+               rc = ide_wait_not_busy(hwif, 35000);
+               if (rc)
+                       printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
+               SELECT_DRIVE(drive);
+               hwif->tp_ops->set_irq(hwif, 1);
+               rc = ide_wait_not_busy(hwif, 100000);
+               if (rc)
+                       printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
+       }
+}
index c55bdbd2231467541d5218de67ae2ff5479f3429..a64ec259f3d13a50c01468c98669a9712f33d9f1 100644 (file)
@@ -110,20 +110,22 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
  *     read and parse the results. This function is run with
  *     interrupts disabled. 
  */
-static inline void do_identify (ide_drive_t *drive, u8 cmd)
+
+static void do_identify(ide_drive_t *drive, u8 cmd)
 {
        ide_hwif_t *hwif = HWIF(drive);
        u16 *id = drive->id;
        char *m = (char *)&id[ATA_ID_PROD];
+       unsigned long flags;
        int bswap = 1, is_cfa;
 
+       /* local CPU only; some systems need this */
+       local_irq_save(flags);
        /* read 512 bytes of id info */
        hwif->tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
+       local_irq_restore(flags);
 
        drive->dev_flags |= IDE_DFLAG_ID_READ;
-
-       local_irq_enable();
 #ifdef DEBUG
        printk(KERN_INFO "%s: dumping identify data\n", drive->name);
        ide_dump_identify((u8 *)id);
@@ -306,17 +308,12 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd)
        s = tp_ops->read_status(hwif);
 
        if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
-               unsigned long flags;
-
-               /* local CPU only; some systems need this */
-               local_irq_save(flags);
                /* drive returned ID */
                do_identify(drive, cmd);
                /* drive responded with ID */
                rc = 0;
                /* clear drive IRQ */
                (void)tp_ops->read_status(hwif);
-               local_irq_restore(flags);
        } else {
                /* drive refused ID */
                rc = 2;
@@ -554,8 +551,8 @@ static void enable_nest (ide_drive_t *drive)
  *                     1  device was found
  *                        (note: IDE_DFLAG_PRESENT might still be not set)
  */
-static inline u8 probe_for_drive (ide_drive_t *drive)
+
+static u8 probe_for_drive(ide_drive_t *drive)
 {
        char *m;
 
@@ -642,7 +639,7 @@ static int ide_register_port(ide_hwif_t *hwif)
        int ret;
 
        /* register with global device tree */
-       strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
+       dev_set_name(&hwif->gendev, hwif->name);
        hwif->gendev.driver_data = hwif;
        if (hwif->gendev.parent == NULL) {
                if (hwif->dev)
@@ -863,31 +860,6 @@ static void ide_port_tune_devices(ide_hwif_t *hwif)
        }
 }
 
-/*
- * save_match() is used to simplify logic in init_irq() below.
- *
- * A loophole here is that we may not know about a particular
- * hwif's irq until after that hwif is actually probed/initialized..
- * This could be a problem for the case where an hwif is on a
- * dual interface that requires serialization (eg. cmd640) and another
- * hwif using one of the same irqs is initialized beforehand.
- *
- * This routine detects and reports such situations, but does not fix them.
- */
-static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
-{
-       ide_hwif_t *m = *match;
-
-       if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
-               if (!new->hwgroup)
-                       return;
-               printk(KERN_WARNING "%s: potential IRQ problem with %s and %s\n",
-                       hwif->name, new->name, m->name);
-       }
-       if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
-               *match = new;
-}
-
 /*
  * init request queue
  */
@@ -906,7 +878,8 @@ static int ide_init_queue(ide_drive_t *drive)
         *      do not.
         */
 
-       q = blk_init_queue_node(do_ide_request, &ide_lock, hwif_to_node(hwif));
+       q = blk_init_queue_node(do_ide_request, &hwif->hwgroup->lock,
+                               hwif_to_node(hwif));
        if (!q)
                return 1;
 
@@ -947,7 +920,7 @@ static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
 {
        ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
 
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        if (!hwgroup->drive) {
                /* first drive for hwgroup. */
                drive->next = drive;
@@ -957,7 +930,7 @@ static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
                drive->next = hwgroup->drive->next;
                hwgroup->drive->next = drive;
        }
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
 }
 
 /*
@@ -1002,7 +975,7 @@ void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
 
        ide_ports[hwif->index] = NULL;
 
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        /*
         * Remove us from the hwgroup, and free
         * the hwgroup if we were the only member
@@ -1030,7 +1003,7 @@ void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
                }
                BUG_ON(hwgroup->hwif == hwif);
        }
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
 }
 
 /*
@@ -1051,27 +1024,13 @@ static int init_irq (ide_hwif_t *hwif)
        mutex_lock(&ide_cfg_mtx);
        hwif->hwgroup = NULL;
 
-       /*
-        * Group up with any other hwifs that share our irq(s).
-        */
        for (index = 0; index < MAX_HWIFS; index++) {
                ide_hwif_t *h = ide_ports[index];
 
                if (h && h->hwgroup) {  /* scan only initialized ports */
-                       if (hwif->irq == h->irq) {
-                               hwif->sharing_irq = h->sharing_irq = 1;
-                               if (hwif->chipset != ide_pci ||
-                                   h->chipset != ide_pci) {
-                                       save_match(hwif, h, &match);
-                               }
-                       }
-                       if (hwif->serialized) {
-                               if (hwif->mate && hwif->mate->irq == h->irq)
-                                       save_match(hwif, h, &match);
-                       }
-                       if (h->serialized) {
-                               if (h->mate && hwif->irq == h->mate->irq)
-                                       save_match(hwif, h, &match);
+                       if (hwif->host->host_flags & IDE_HFLAG_SERIALIZE) {
+                               if (hwif->host == h->host)
+                                       match = h;
                        }
                }
        }
@@ -1092,17 +1051,19 @@ static int init_irq (ide_hwif_t *hwif)
                 * linked list, the first entry is the hwif that owns
                 * hwgroup->handler - do not change that.
                 */
-               spin_lock_irq(&ide_lock);
+               spin_lock_irq(&hwgroup->lock);
                hwif->next = hwgroup->hwif->next;
                hwgroup->hwif->next = hwif;
                BUG_ON(hwif->next == hwif);
-               spin_unlock_irq(&ide_lock);
+               spin_unlock_irq(&hwgroup->lock);
        } else {
                hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO,
                                       hwif_to_node(hwif));
                if (hwgroup == NULL)
                        goto out_up;
 
+               spin_lock_init(&hwgroup->lock);
+
                hwif->hwgroup = hwgroup;
                hwgroup->hwif = hwif->next = hwif;
 
@@ -1122,8 +1083,7 @@ static int init_irq (ide_hwif_t *hwif)
                sa = IRQF_SHARED;
 #endif /* __mc68000__ */
 
-               if (hwif->chipset == ide_pci || hwif->chipset == ide_cmd646 ||
-                   hwif->chipset == ide_ali14xx)
+               if (hwif->chipset == ide_pci)
                        sa = IRQF_SHARED;
 
                if (io_ports->ctl_addr)
@@ -1150,8 +1110,7 @@ static int init_irq (ide_hwif_t *hwif)
                io_ports->data_addr, hwif->irq);
 #endif /* __mc68000__ */
        if (match)
-               printk(KERN_CONT " (%sed with %s)",
-                       hwif->sharing_irq ? "shar" : "serializ", match->name);
+               printk(KERN_CONT " (serialized with %s)", match->name);
        printk(KERN_CONT "\n");
 
        mutex_unlock(&ide_cfg_mtx);
@@ -1263,20 +1222,21 @@ static void ide_remove_drive_from_hwgroup(ide_drive_t *drive)
 static void drive_release_dev (struct device *dev)
 {
        ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
+       ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
 
        ide_proc_unregister_device(drive);
 
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        ide_remove_drive_from_hwgroup(drive);
        kfree(drive->id);
        drive->id = NULL;
        drive->dev_flags &= ~IDE_DFLAG_PRESENT;
        /* Messed up locking ... */
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
        blk_cleanup_queue(drive->queue);
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
        drive->queue = NULL;
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
 
        complete(&drive->gendev_rel_comp);
 }
@@ -1352,7 +1312,7 @@ static void hwif_register_devices(ide_hwif_t *hwif)
                if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
                        continue;
 
-               snprintf(dev->bus_id, BUS_ID_SIZE, "%u.%u", hwif->index, i);
+               dev_set_name(dev, "%u.%u", hwif->index, i);
                dev->parent = &hwif->gendev;
                dev->bus = &ide_bus_type;
                dev->driver_data = drive;
@@ -1436,13 +1396,11 @@ static void ide_init_port(ide_hwif_t *hwif, unsigned int port,
        }
 
        if ((d->host_flags & IDE_HFLAG_SERIALIZE) ||
-           ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base)) {
-               if (hwif->mate)
-                       hwif->mate->serialized = hwif->serialized = 1;
-       }
+           ((d->host_flags & IDE_HFLAG_SERIALIZE_DMA) && hwif->dma_base))
+               hwif->host->host_flags |= IDE_HFLAG_SERIALIZE;
 
-       if (d->host_flags & IDE_HFLAG_RQSIZE_256)
-               hwif->rqsize = 256;
+       if (d->max_sectors)
+               hwif->rqsize = d->max_sectors;
 
        /* call chipset specific routine for each enabled port */
        if (d->init_hwif)
@@ -1794,59 +1752,3 @@ void ide_port_scan(ide_hwif_t *hwif)
        ide_proc_port_register_devices(hwif);
 }
 EXPORT_SYMBOL_GPL(ide_port_scan);
-
-static void ide_legacy_init_one(hw_regs_t **hws, hw_regs_t *hw,
-                               u8 port_no, const struct ide_port_info *d,
-                               unsigned long config)
-{
-       unsigned long base, ctl;
-       int irq;
-
-       if (port_no == 0) {
-               base = 0x1f0;
-               ctl  = 0x3f6;
-               irq  = 14;
-       } else {
-               base = 0x170;
-               ctl  = 0x376;
-               irq  = 15;
-       }
-
-       if (!request_region(base, 8, d->name)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
-                               d->name, base, base + 7);
-               return;
-       }
-
-       if (!request_region(ctl, 1, d->name)) {
-               printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
-                               d->name, ctl);
-               release_region(base, 8);
-               return;
-       }
-
-       ide_std_init_ports(hw, base, ctl);
-       hw->irq = irq;
-       hw->chipset = d->chipset;
-       hw->config = config;
-
-       hws[port_no] = hw;
-}
-
-int ide_legacy_device_add(const struct ide_port_info *d, unsigned long config)
-{
-       hw_regs_t hw[2], *hws[] = { NULL, NULL, NULL, NULL };
-
-       memset(&hw, 0, sizeof(hw));
-
-       if ((d->host_flags & IDE_HFLAG_QD_2ND_PORT) == 0)
-               ide_legacy_init_one(hws, &hw[0], 0, d, config);
-       ide_legacy_init_one(hws, &hw[1], 1, d, config);
-
-       if (hws[0] == NULL && hws[1] == NULL &&
-           (d->host_flags & IDE_HFLAG_SINGLE))
-               return -ENOENT;
-
-       return ide_host_add(d, hws, NULL);
-}
-EXPORT_SYMBOL_GPL(ide_legacy_device_add);
index f3cddd1b2f8f38b3c1a0c5f5d9c9c33f82802940..a14e2938e4f36c0b6bb77d9c269a0a4b6e7d8bc7 100644 (file)
@@ -46,10 +46,6 @@ static int proc_ide_read_imodel
        case ide_qd65xx:        name = "qd65xx";        break;
        case ide_umc8672:       name = "umc8672";       break;
        case ide_ht6560b:       name = "ht6560b";       break;
-       case ide_rz1000:        name = "rz1000";        break;
-       case ide_trm290:        name = "trm290";        break;
-       case ide_cmd646:        name = "cmd646";        break;
-       case ide_cy82c693:      name = "cy82c693";      break;
        case ide_4drives:       name = "4drives";       break;
        case ide_pmac:          name = "mac-io";        break;
        case ide_au1xxx:        name = "au1xxx";        break;
@@ -155,13 +151,8 @@ static int ide_read_setting(ide_drive_t *drive,
        const struct ide_devset *ds = setting->setting;
        int val = -EINVAL;
 
-       if (ds->get) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&ide_lock, flags);
+       if (ds->get)
                val = ds->get(drive);
-               spin_unlock_irqrestore(&ide_lock, flags);
-       }
 
        return val;
 }
@@ -583,31 +574,19 @@ EXPORT_SYMBOL(ide_proc_register_driver);
  *     Clean up the driver specific /proc files and IDE settings
  *     for a given drive.
  *
- *     Takes ide_setting_mtx and ide_lock.
- *     Caller must hold none of the locks.
+ *     Takes ide_setting_mtx.
  */
 
 void ide_proc_unregister_driver(ide_drive_t *drive, ide_driver_t *driver)
 {
-       unsigned long flags;
-
        ide_remove_proc_entries(drive->proc, driver->proc_entries(drive));
 
        mutex_lock(&ide_setting_mtx);
-       spin_lock_irqsave(&ide_lock, flags);
        /*
-        * ide_setting_mtx protects the settings list
-        * ide_lock protects the use of settings
-        *
-        * so we need to hold both, ide_settings_sem because we want to
-        * modify the settings list, and ide_lock because we cannot take
-        * a setting out that is being used.
-        *
-        * OTOH both ide_{read,write}_setting are only ever used under
-        * ide_setting_mtx.
+        * ide_setting_mtx protects both the settings list and the use
+        * of settings (we cannot take a setting out that is being used).
         */
        drive->settings = NULL;
-       spin_unlock_irqrestore(&ide_lock, flags);
        mutex_unlock(&ide_setting_mtx);
 }
 EXPORT_SYMBOL(ide_proc_unregister_driver);
index 04f8f13cb9d74d697f65f3c37bb03117b3bc0057..f0f09f702e9ccf54b20f7ed85d1c9d00b6326275 100644 (file)
@@ -74,9 +74,6 @@ static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
 
 DEFINE_MUTEX(ide_cfg_mtx);
 
-__cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
-EXPORT_SYMBOL(ide_lock);
-
 static void ide_port_init_devices_data(ide_hwif_t *);
 
 /*
@@ -130,7 +127,6 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif)
        }
 }
 
-/* Called with ide_lock held. */
 static void __ide_port_unregister_devices(ide_hwif_t *hwif)
 {
        int i;
@@ -139,10 +135,8 @@ static void __ide_port_unregister_devices(ide_hwif_t *hwif)
                ide_drive_t *drive = &hwif->drives[i];
 
                if (drive->dev_flags & IDE_DFLAG_PRESENT) {
-                       spin_unlock_irq(&ide_lock);
                        device_unregister(&drive->gendev);
                        wait_for_completion(&drive->gendev_rel_comp);
-                       spin_lock_irq(&ide_lock);
                }
        }
 }
@@ -150,11 +144,9 @@ static void __ide_port_unregister_devices(ide_hwif_t *hwif)
 void ide_port_unregister_devices(ide_hwif_t *hwif)
 {
        mutex_lock(&ide_cfg_mtx);
-       spin_lock_irq(&ide_lock);
        __ide_port_unregister_devices(hwif);
        hwif->present = 0;
        ide_port_init_devices_data(hwif);
-       spin_unlock_irq(&ide_lock);
        mutex_unlock(&ide_cfg_mtx);
 }
 EXPORT_SYMBOL_GPL(ide_port_unregister_devices);
@@ -192,12 +184,10 @@ void ide_unregister(ide_hwif_t *hwif)
 
        mutex_lock(&ide_cfg_mtx);
 
-       spin_lock_irq(&ide_lock);
        if (hwif->present) {
                __ide_port_unregister_devices(hwif);
                hwif->present = 0;
        }
-       spin_unlock_irq(&ide_lock);
 
        ide_proc_unregister_port(hwif);
 
@@ -340,6 +330,7 @@ static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
 static int set_pio_mode(ide_drive_t *drive, int arg)
 {
        ide_hwif_t *hwif = drive->hwif;
+       ide_hwgroup_t *hwgroup = hwif->hwgroup;
        const struct ide_port_ops *port_ops = hwif->port_ops;
 
        if (arg < 0 || arg > 255)
@@ -354,9 +345,9 @@ static int set_pio_mode(ide_drive_t *drive, int arg)
                        unsigned long flags;
 
                        /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
-                       spin_lock_irqsave(&ide_lock, flags);
+                       spin_lock_irqsave(&hwgroup->lock, flags);
                        port_ops->set_pio_mode(drive, arg);
-                       spin_unlock_irqrestore(&ide_lock, flags);
+                       spin_unlock_irqrestore(&hwgroup->lock, flags);
                } else
                        port_ops->set_pio_mode(drive, arg);
        } else {
@@ -397,80 +388,6 @@ ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
 ide_ext_devset_rw_sync(using_dma, using_dma);
 __IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
 
-static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
-{
-       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
-       ide_hwif_t *hwif = HWIF(drive);
-       struct request *rq;
-       struct request_pm_state rqpm;
-       ide_task_t args;
-       int ret;
-
-       /* call ACPI _GTM only once */
-       if ((drive->dn & 1) == 0 || pair == NULL)
-               ide_acpi_get_timing(hwif);
-
-       memset(&rqpm, 0, sizeof(rqpm));
-       memset(&args, 0, sizeof(args));
-       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-       rq->cmd_type = REQ_TYPE_PM_SUSPEND;
-       rq->special = &args;
-       rq->data = &rqpm;
-       rqpm.pm_step = IDE_PM_START_SUSPEND;
-       if (mesg.event == PM_EVENT_PRETHAW)
-               mesg.event = PM_EVENT_FREEZE;
-       rqpm.pm_state = mesg.event;
-
-       ret = blk_execute_rq(drive->queue, NULL, rq, 0);
-       blk_put_request(rq);
-
-       /* call ACPI _PS3 only after both devices are suspended */
-       if (ret == 0 && ((drive->dn & 1) || pair == NULL))
-               ide_acpi_set_state(hwif, 0);
-
-       return ret;
-}
-
-static int generic_ide_resume(struct device *dev)
-{
-       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
-       ide_hwif_t *hwif = HWIF(drive);
-       struct request *rq;
-       struct request_pm_state rqpm;
-       ide_task_t args;
-       int err;
-
-       /* call ACPI _PS0 / _STM only once */
-       if ((drive->dn & 1) == 0 || pair == NULL) {
-               ide_acpi_set_state(hwif, 1);
-               ide_acpi_push_timing(hwif);
-       }
-
-       ide_acpi_exec_tfs(drive);
-
-       memset(&rqpm, 0, sizeof(rqpm));
-       memset(&args, 0, sizeof(args));
-       rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
-       rq->cmd_type = REQ_TYPE_PM_RESUME;
-       rq->cmd_flags |= REQ_PREEMPT;
-       rq->special = &args;
-       rq->data = &rqpm;
-       rqpm.pm_step = IDE_PM_START_RESUME;
-       rqpm.pm_state = PM_EVENT_ON;
-
-       err = blk_execute_rq(drive->queue, NULL, rq, 1);
-       blk_put_request(rq);
-
-       if (err == 0 && dev->driver) {
-               ide_driver_t *drv = to_ide_driver(dev->driver);
-
-               if (drv->resume)
-                       drv->resume(drive);
-       }
-
-       return err;
-}
-
 /**
  * ide_device_get      -       get an additional reference to a ide_drive_t
  * @drive:     device to get a reference to
index f728f2927b5a03a9ed4d1c8086ba67c9da350810..bdcac94d7c1fbd3ca08b6a126a097b82a2562212 100644 (file)
 
 #define DRV_NAME "ide_arm"
 
-#ifdef CONFIG_ARCH_CLPS7500
-# include <mach/hardware.h>
-#
-# define IDE_ARM_IO    (ISASLOT_IO + 0x1f0)
-# define IDE_ARM_IRQ   IRQ_ISA_14
-#else
-# define IDE_ARM_IO    0x1f0
-# define IDE_ARM_IRQ   IRQ_HARDDISK
-#endif
+#define IDE_ARM_IO     0x1f0
+#define IDE_ARM_IRQ    IRQ_HARDDISK
 
 static int __init ide_arm_init(void)
 {
index 799557c25eefede0c583680ccf5fbb39d91510ca..624e62e5cc9af8043c9a83fd5c41b4a92f50bf82 100644 (file)
@@ -350,16 +350,17 @@ static const struct ide_dma_ops pdc2026x_dma_ops = {
        .dma_timeout            = pdc202xx_dma_timeout,
 };
 
-#define DECLARE_PDC2026X_DEV(udma, extra_flags) \
+#define DECLARE_PDC2026X_DEV(udma, sectors) \
        { \
                .name           = DRV_NAME, \
                .init_chipset   = init_chipset_pdc202xx, \
                .port_ops       = &pdc2026x_port_ops, \
                .dma_ops        = &pdc2026x_dma_ops, \
-               .host_flags     = IDE_HFLAGS_PDC202XX | extra_flags, \
+               .host_flags     = IDE_HFLAGS_PDC202XX, \
                .pio_mask       = ATA_PIO4, \
                .mwdma_mask     = ATA_MWDMA2, \
                .udma_mask      = udma, \
+               .max_sectors    = sectors, \
        }
 
 static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
@@ -376,8 +377,8 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
 
        /* 1: PDC2026{2,3} */
        DECLARE_PDC2026X_DEV(ATA_UDMA4, 0),
-       /* 2: PDC2026{5,7} */
-       DECLARE_PDC2026X_DEV(ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
+       /* 2: PDC2026{5,7}: UDMA5, limit LBA48 requests to 256 sectors */
+       DECLARE_PDC2026X_DEV(ATA_UDMA5, 256),
 };
 
 /**
index 7daf0135cbac678a0e22dcda2c388ceebf843f9b..a6414a884eb120f07018b5b8a2b9887d8275d191 100644 (file)
 
 #define DRV_NAME "rz1000"
 
-static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
+static int __devinit rz1000_disable_readahead(struct pci_dev *dev)
 {
-       struct pci_dev *dev = to_pci_dev(hwif->dev);
        u16 reg;
 
        if (!pci_read_config_word (dev, 0x40, &reg) &&
            !pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
                printk(KERN_INFO "%s: disabled chipset read-ahead "
-                       "(buggy RZ1000/RZ1001)\n", hwif->name);
+                       "(buggy RZ1000/RZ1001)\n", pci_name(dev));
+               return 0;
        } else {
-               if (hwif->mate)
-                       hwif->mate->serialized = hwif->serialized = 1;
-               hwif->host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
                printk(KERN_INFO "%s: serialized, disabled unmasking "
-                       "(buggy RZ1000/RZ1001)\n", hwif->name);
+                       "(buggy RZ1000/RZ1001)\n", pci_name(dev));
+               return 1;
        }
 }
 
 static const struct ide_port_info rz1000_chipset __devinitdata = {
        .name           = DRV_NAME,
-       .init_hwif      = init_hwif_rz1000,
-       .chipset        = ide_rz1000,
        .host_flags     = IDE_HFLAG_NO_DMA,
 };
 
 static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       return ide_pci_init_one(dev, &rz1000_chipset, NULL);
+       struct ide_port_info d = rz1000_chipset;
+       int rc;
+
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+
+       if (rz1000_disable_readahead(dev)) {
+               d.host_flags |= IDE_HFLAG_SERIALIZE;
+               d.host_flags |= IDE_HFLAG_NO_UNMASK_IRQS;
+       }
+
+       return ide_pci_init_one(dev, &d, NULL);
+}
+
+static void rz1000_remove(struct pci_dev *dev)
+{
+       ide_pci_remove(dev);
+       pci_disable_device(dev);
 }
 
 static const struct pci_device_id rz1000_pci_tbl[] = {
@@ -63,7 +77,7 @@ static struct pci_driver rz1000_pci_driver = {
        .name           = "RZ1000_IDE",
        .id_table       = rz1000_pci_tbl,
        .probe          = rz1000_init_one,
-       .remove         = ide_pci_remove,
+       .remove         = rz1000_remove,
 };
 
 static int __init rz1000_ide_init(void)
index 75ea6152656663b6673c536e7903e4d2eb6bafda..2a5ea90cf8b8c0e4aefbac4f4ac04ea2e11afce1 100644 (file)
@@ -328,10 +328,10 @@ static struct ide_dma_ops trm290_dma_ops = {
 static const struct ide_port_info trm290_chipset __devinitdata = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_trm290,
-       .chipset        = ide_trm290,
        .port_ops       = &trm290_port_ops,
        .dma_ops        = &trm290_dma_ops,
-       .host_flags     = IDE_HFLAG_NO_ATAPI_DMA |
+       .host_flags     = IDE_HFLAG_TRM290 |
+                         IDE_HFLAG_NO_ATAPI_DMA |
 #if 0 /* play it safe for now */
                          IDE_HFLAG_TRUST_BIOS_FOR_DMA |
 #endif
index 9120063e8f87d841534e93b5de7ef11f13be3ea9..13b63e7fa353df1075e1fdfdfffcf74929a1cdcf 100644 (file)
@@ -181,7 +181,7 @@ static void tx4938ide_input_data_swap(ide_drive_t *drive, struct request *rq,
 
        while (count--)
                *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
-       __ide_flush_dcache_range((unsigned long)buf, count * 2);
+       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
 }
 
 static void tx4938ide_output_data_swap(ide_drive_t *drive, struct request *rq,
@@ -195,7 +195,7 @@ static void tx4938ide_output_data_swap(ide_drive_t *drive, struct request *rq,
                __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
                ptr++;
        }
-       __ide_flush_dcache_range((unsigned long)buf, count * 2);
+       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
 }
 
 static const struct ide_tp_ops tx4938ide_tp_ops = {
index bafb7d1a22e22a78f0c3afd5f422ba53e3f07410..97cd9e0f66f692cdc1fe76a8e8f781f7e878e730 100644 (file)
@@ -259,6 +259,12 @@ static int tx4939ide_build_dmatable(ide_drive_t *drive, struct request *rq)
                        bcount = 0x10000 - (cur_addr & 0xffff);
                        if (bcount > cur_len)
                                bcount = cur_len;
+                       /*
+                        * This workaround for zero count seems required.
+                        * (standard ide_build_dmatable do it too)
+                        */
+                       if ((bcount & 0xffff) == 0x0000)
+                               bcount = 0x8000;
                        *table++ = bcount & 0xffff;
                        *table++ = cur_addr;
                        cur_addr += bcount;
@@ -558,7 +564,7 @@ static void tx4939ide_input_data_swap(ide_drive_t *drive, struct request *rq,
 
        while (count--)
                *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port));
-       __ide_flush_dcache_range((unsigned long)buf, count * 2);
+       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
 }
 
 static void tx4939ide_output_data_swap(ide_drive_t *drive, struct request *rq,
@@ -572,7 +578,7 @@ static void tx4939ide_output_data_swap(ide_drive_t *drive, struct request *rq,
                __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port);
                ptr++;
        }
-       __ide_flush_dcache_range((unsigned long)buf, count * 2);
+       __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2));
 }
 
 static const struct ide_tp_ops tx4939ide_tp_ops = {
index 1da076e0c917d7f024b8923f66d38fdb815ccabb..e29978cf619722ea694f72e3023ed4bcdea73f31 100644 (file)
@@ -107,18 +107,21 @@ static void umc_set_speeds(u8 speeds[])
 static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        ide_hwif_t *hwif = drive->hwif;
-       unsigned long flags;
+       ide_hwgroup_t *mate_hwgroup = hwif->mate ? hwif->mate->hwgroup : NULL;
+       unsigned long uninitialized_var(flags);
 
        printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
                drive->name, pio, pio_to_umc[pio]);
-       spin_lock_irqsave(&ide_lock, flags);
-       if (hwif->mate && hwif->mate->hwgroup->handler) {
+       if (mate_hwgroup)
+               spin_lock_irqsave(&mate_hwgroup->lock, flags);
+       if (mate_hwgroup && mate_hwgroup->handler) {
                printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
        } else {
                current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
                umc_set_speeds(current_speeds);
        }
-       spin_unlock_irqrestore(&ide_lock, flags);
+       if (mate_hwgroup)
+               spin_unlock_irqrestore(&mate_hwgroup->lock, flags);
 }
 
 static const struct ide_port_ops umc8672_port_ops = {
index 69e674ecf19a1b26ed9f0db46d9c176c5d43d273..db22fd9b4cf2ca29243035e48ae1312d1dd341ed 100644 (file)
@@ -101,7 +101,7 @@ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
        if (cpu_is_omap24xx()) {
                int i;
                for (i = 0; i < omap_kp->rows; i++)
-                       disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+                       disable_irq(gpio_to_irq(row_gpios[i]));
        } else
                /* disable keyboard interrupt and schedule for handling */
                omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
@@ -224,7 +224,7 @@ static void omap_kp_tasklet(unsigned long data)
                if (cpu_is_omap24xx()) {
                        int i;
                        for (i = 0; i < omap_kp_data->rows; i++)
-                               enable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+                               enable_irq(gpio_to_irq(row_gpios[i]));
                } else {
                        omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
                        kp_cur_group = -1;
@@ -397,7 +397,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
                omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
        } else {
                for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
-                       if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
+                       if (request_irq(gpio_to_irq(row_gpios[irq_idx]),
                                        omap_kp_interrupt,
                                        IRQF_TRIGGER_FALLING,
                                        "omap-keypad", omap_kp) < 0)
@@ -438,7 +438,7 @@ static int omap_kp_remove(struct platform_device *pdev)
                        gpio_free(col_gpios[i]);
                for (i = 0; i < omap_kp->rows; i++) {
                        gpio_free(row_gpios[i]);
-                       free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
+                       free_irq(gpio_to_irq(row_gpios[i]), 0);
                }
        } else {
                omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
index 6d30c6d334c38eca442b3e2902e338a8230d3733..0d2fc64a5e1cead895be0a0c22cd96a500faf1c0 100644 (file)
@@ -475,7 +475,7 @@ static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
                goto failed_free_mem;
        }
 
-       keypad->clk = clk_get(&pdev->dev, "KBDCLK");
+       keypad->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(keypad->clk)) {
                dev_err(&pdev->dev, "failed to get keypad clock\n");
                error = PTR_ERR(keypad->clk);
index 27d70d326ff3c3de7d3c4ef2683e6dbc3aae1969..da3c3a5d26892a5f763e754697ef36a12416bb27 100644 (file)
@@ -79,7 +79,7 @@ config SERIO_PARKBD
 
 config SERIO_RPCKBD
        tristate "Acorn RiscPC keyboard controller"
-       depends on ARCH_ACORN || ARCH_CLPS7500
+       depends on ARCH_ACORN
        default y
        help
          Say Y here if you have the Acorn RiscPC and want to use an AT
index b9b7fc6ff1ebcc657370701e9dcc53d3ce20bfdb..e1ece89fe9222b5ef810516ca0ea7384fd98eb2e 100644 (file)
@@ -697,7 +697,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
        struct ads7846  *ts = container_of(handle, struct ads7846, timer);
        int             status = 0;
 
-       spin_lock_irq(&ts->lock);
+       spin_lock(&ts->lock);
 
        if (unlikely(!get_pendown_state(ts) ||
                     device_suspended(&ts->spi->dev))) {
@@ -728,7 +728,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
                        dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
        }
 
-       spin_unlock_irq(&ts->lock);
+       spin_unlock(&ts->lock);
        return HRTIMER_NORESTART;
 }
 
index ba648750a8d927db4a4cade7e2df61cca5348059..1d11e2be9ef823ff3cb0076dc409e6f18f56224e 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/wm97xx.h>
 #include <linux/io.h>
-#include <mach/pxa-regs.h>
+#include <mach/regs-ac97.h>
 
 #define VERSION                "0.13"
 
index 5faefeaf679057b9c6b3e029dee4544343e5c132..f2c641e0bdde508887809176774badcc31519622 100644 (file)
@@ -164,7 +164,7 @@ void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt);
 void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);
 
 /* page_tables.c: */
-int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
+int init_guest_pagetable(struct lguest *lg);
 void free_guest_pagetable(struct lguest *lg);
 void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
 void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
index a661bbdae3d62f657fc801eceb80d9afefc3e4bf..915da6b8c924a87baeaab1edd924baff7a213f10 100644 (file)
@@ -250,7 +250,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
        /* Figure out how many pages the ring will take, and map that memory */
        lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
                                DIV_ROUND_UP(vring_size(lvq->config.num,
-                                                       PAGE_SIZE),
+                                                       LGUEST_VRING_ALIGN),
                                             PAGE_SIZE));
        if (!lvq->pages) {
                err = -ENOMEM;
@@ -259,8 +259,8 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
 
        /* OK, tell virtio_ring.c to set up a virtqueue now we know its size
         * and we've got a pointer to its pages. */
-       vq = vring_new_virtqueue(lvq->config.num, vdev, lvq->pages,
-                                lg_notify, callback);
+       vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN,
+                                vdev, lvq->pages, lg_notify, callback);
        if (!vq) {
                err = -ENOMEM;
                goto unmap;
@@ -272,7 +272,7 @@ static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
         * the interrupt as a source of randomness: it'd be nice to have that
         * back.. */
        err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
-                         vdev->dev.bus_id, vq);
+                         dev_name(&vdev->dev), vq);
        if (err)
                goto destroy_vring;
 
index e73a000473cc524cd16d9773da390047d362751e..34bc017b8b3cda17ac4ee8f6e720ea85eb782628 100644 (file)
@@ -146,7 +146,7 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
        return 0;
 }
 
-/*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit)
+/*L:020 The initialization write supplies 3 pointer sized (32 or 64 bit)
  * values (in addition to the LHREQ_INITIALIZE value).  These are:
  *
  * base: The start of the Guest-physical memory inside the Launcher memory.
@@ -155,9 +155,6 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
  * allowed to access.  The Guest memory lives inside the Launcher, so it sets
  * this to ensure the Guest can only reach its own memory.
  *
- * pgdir: The (Guest-physical) address of the top of the initial Guest
- * pagetables (which are set up by the Launcher).
- *
  * start: The first instruction to execute ("eip" in x86-speak).
  */
 static int initialize(struct file *file, const unsigned long __user *input)
@@ -166,7 +163,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
         * Guest. */
        struct lguest *lg;
        int err;
-       unsigned long args[4];
+       unsigned long args[3];
 
        /* We grab the Big Lguest lock, which protects against multiple
         * simultaneous initializations. */
@@ -192,14 +189,14 @@ static int initialize(struct file *file, const unsigned long __user *input)
        lg->mem_base = (void __user *)args[0];
        lg->pfn_limit = args[1];
 
-       /* This is the first cpu (cpu 0) and it will start booting at args[3] */
-       err = lg_cpu_start(&lg->cpus[0], 0, args[3]);
+       /* This is the first cpu (cpu 0) and it will start booting at args[2] */
+       err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
        if (err)
                goto release_guest;
 
        /* Initialize the Guest's shadow page tables, using the toplevel
         * address the Launcher gave us.  This allocates memory, so can fail. */
-       err = init_guest_pagetable(lg, args[2]);
+       err = init_guest_pagetable(lg);
        if (err)
                goto free_regs;
 
index 81d0c60534472de6e6ce9744820476058f4a5fe3..576a8318221c9dfe47dc28a660565094c9ef7753 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/percpu.h>
 #include <asm/tlbflush.h>
 #include <asm/uaccess.h>
+#include <asm/bootparam.h>
 #include "lg.h"
 
 /*M:008 We hold reference to pages, which prevents them from being swapped.
@@ -581,15 +582,82 @@ void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
                release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
 }
 
+/* Once we know how much memory we have we can construct simple identity
+ * (which set virtual == physical) and linear mappings
+ * which will get the Guest far enough into the boot to create its own.
+ *
+ * We lay them out of the way, just below the initrd (which is why we need to
+ * know its size here). */
+static unsigned long setup_pagetables(struct lguest *lg,
+                                     unsigned long mem,
+                                     unsigned long initrd_size)
+{
+       pgd_t __user *pgdir;
+       pte_t __user *linear;
+       unsigned int mapped_pages, i, linear_pages, phys_linear;
+       unsigned long mem_base = (unsigned long)lg->mem_base;
+
+       /* We have mapped_pages frames to map, so we need
+        * linear_pages page tables to map them. */
+       mapped_pages = mem / PAGE_SIZE;
+       linear_pages = (mapped_pages + PTRS_PER_PTE - 1) / PTRS_PER_PTE;
+
+       /* We put the toplevel page directory page at the top of memory. */
+       pgdir = (pgd_t *)(mem + mem_base - initrd_size - PAGE_SIZE);
+
+       /* Now we use the next linear_pages pages as pte pages */
+       linear = (void *)pgdir - linear_pages * PAGE_SIZE;
+
+       /* Linear mapping is easy: put every page's address into the
+        * mapping in order. */
+       for (i = 0; i < mapped_pages; i++) {
+               pte_t pte;
+               pte = pfn_pte(i, __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_USER));
+               if (copy_to_user(&linear[i], &pte, sizeof(pte)) != 0)
+                       return -EFAULT;
+       }
+
+       /* The top level points to the linear page table pages above.
+        * We setup the identity and linear mappings here. */
+       phys_linear = (unsigned long)linear - mem_base;
+       for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) {
+               pgd_t pgd;
+               pgd = __pgd((phys_linear + i * sizeof(pte_t)) |
+                           (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
+
+               if (copy_to_user(&pgdir[i / PTRS_PER_PTE], &pgd, sizeof(pgd))
+                   || copy_to_user(&pgdir[pgd_index(PAGE_OFFSET)
+                                          + i / PTRS_PER_PTE],
+                                   &pgd, sizeof(pgd)))
+                       return -EFAULT;
+       }
+
+       /* We return the top level (guest-physical) address: remember where
+        * this is. */
+       return (unsigned long)pgdir - mem_base;
+}
+
 /*H:500 (vii) Setting up the page tables initially.
  *
  * When a Guest is first created, the Launcher tells us where the toplevel of
  * its first page table is.  We set some things up here: */
-int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
+int init_guest_pagetable(struct lguest *lg)
 {
+       u64 mem;
+       u32 initrd_size;
+       struct boot_params __user *boot = (struct boot_params *)lg->mem_base;
+
+       /* Get the Guest memory size and the ramdisk size from the boot header
+        * located at lg->mem_base (Guest address 0). */
+       if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem))
+           || get_user(initrd_size, &boot->hdr.ramdisk_size))
+               return -EFAULT;
+
        /* We start on the first shadow page table, and give it a blank PGD
         * page. */
-       lg->pgdirs[0].gpgdir = pgtable;
+       lg->pgdirs[0].gpgdir = setup_pagetables(lg, mem, initrd_size);
+       if (IS_ERR_VALUE(lg->pgdirs[0].gpgdir))
+               return lg->pgdirs[0].gpgdir;
        lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
        if (!lg->pgdirs[0].pgdir)
                return -ENOMEM;
index ce26c84af064339f196a0a2eb62b0c55866408b2..3326750ec02c9d056329cb075842954012bc25cb 100644 (file)
@@ -1060,7 +1060,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_page_pool;
        }
 
-       cc->bs = bioset_create(MIN_IOS, MIN_IOS);
+       cc->bs = bioset_create(MIN_IOS, 0);
        if (!cc->bs) {
                ti->error = "Cannot allocate crypt bioset";
                goto bad_bs;
index 2fd6d4450637943963d88c948080cf4f0ed73a92..a34338567a2a601c3cdbda72441d54299301f89a 100644 (file)
@@ -56,7 +56,7 @@ struct dm_io_client *dm_io_client_create(unsigned num_pages)
        if (!client->pool)
                goto bad;
 
-       client->bios = bioset_create(16, 16);
+       client->bios = bioset_create(16, 0);
        if (!client->bios)
                goto bad;
 
index 343094c3feeb834c55f8aa1ecd3baa57890eca1d..421c9f02d8ca7329c41168e7beb5f1c2b3a6c6d1 100644 (file)
@@ -1093,7 +1093,7 @@ static struct mapped_device *alloc_dev(int minor)
        if (!md->tio_pool)
                goto bad_tio_pool;
 
-       md->bs = bioset_create(16, 16);
+       md->bs = bioset_create(16, 0);
        if (!md->bs)
                goto bad_no_bioset;
 
index 4952aeb5dd80583ba34c4bff94ee319ddf1a4731..d8229a0e9a9c4754603bb8cf0bfefd05e72ad36e 100644 (file)
@@ -2391,6 +2391,67 @@ IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
 };
 EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
 
+/* Kworld Plus TV Analog Lite PCI IR
+   Mauro Carvalho Chehab <mchehab@infradead.org>
+ */
+IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE] = {
+       [0x0c] = KEY_PROG1,             /* Kworld key */
+       [0x16] = KEY_CLOSECD,           /* -> ) */
+       [0x1d] = KEY_POWER2,
+
+       [0x00] = KEY_1,
+       [0x01] = KEY_2,
+       [0x02] = KEY_3,                 /* Two keys have the same code: 3 and left */
+       [0x03] = KEY_4,                 /* Two keys have the same code: 3 and right */
+       [0x04] = KEY_5,
+       [0x05] = KEY_6,
+       [0x06] = KEY_7,
+       [0x07] = KEY_8,
+       [0x08] = KEY_9,
+       [0x0a] = KEY_0,
+
+       [0x09] = KEY_AGAIN,
+       [0x14] = KEY_MUTE,
+
+       [0x20] = KEY_UP,
+       [0x21] = KEY_DOWN,
+       [0x0b] = KEY_ENTER,
+
+       [0x10] = KEY_CHANNELUP,
+       [0x11] = KEY_CHANNELDOWN,
+
+       /* Couldn't map key left/key right since those
+          conflict with '3' and '4' scancodes
+          I dunno what the original driver does
+        */
+
+       [0x13] = KEY_VOLUMEUP,
+       [0x12] = KEY_VOLUMEDOWN,
+
+       /* The lower part of the IR
+          There are several duplicated keycodes there.
+          Most of them conflict with digits.
+          Add mappings just to the unused scancodes.
+          Somehow, the original driver has a way to know,
+          but this doesn't seem to be on some GPIO.
+          Also, it is not related to the time between keyup
+          and keydown.
+        */
+       [0x19] = KEY_PAUSE,             /* Timeshift */
+       [0x1a] = KEY_STOP,
+       [0x1b] = KEY_RECORD,
+
+       [0x22] = KEY_TEXT,
+
+       [0x15] = KEY_AUDIO,             /* ((*)) */
+       [0x0f] = KEY_ZOOM,
+       [0x1c] = KEY_SHUFFLE,           /* snapshot */
+
+       [0x18] = KEY_RED,               /* B */
+       [0x23] = KEY_GREEN,             /* C */
+};
+EXPORT_SYMBOL_GPL(ir_codes_kworld_plus_tv_analog);
+
 IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE] = {
        [0x20] = KEY_LIST,
        [0x00] = KEY_POWER,
@@ -2511,3 +2572,35 @@ IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE] = {
 
 };
 EXPORT_SYMBOL_GPL(ir_codes_real_audio_220_32_keys);
+
+/* ATI TV Wonder HD 600 USB
+   Devin Heitmueller <devin.heitmueller@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE] = {
+       [0x00] = KEY_RECORD,            /* Row 1 */
+       [0x01] = KEY_PLAYPAUSE,
+       [0x02] = KEY_STOP,
+       [0x03] = KEY_POWER,
+       [0x04] = KEY_PREVIOUS,  /* Row 2 */
+       [0x05] = KEY_REWIND,
+       [0x06] = KEY_FORWARD,
+       [0x07] = KEY_NEXT,
+       [0x08] = KEY_EPG,               /* Row 3 */
+       [0x09] = KEY_HOME,
+       [0x0a] = KEY_MENU,
+       [0x0b] = KEY_CHANNELUP,
+       [0x0c] = KEY_BACK,              /* Row 4 */
+       [0x0d] = KEY_UP,
+       [0x0e] = KEY_INFO,
+       [0x0f] = KEY_CHANNELDOWN,
+       [0x10] = KEY_LEFT,              /* Row 5 */
+       [0x11] = KEY_SELECT,
+       [0x12] = KEY_RIGHT,
+       [0x13] = KEY_VOLUMEUP,
+       [0x14] = KEY_LAST,              /* Row 6 */
+       [0x15] = KEY_DOWN,
+       [0x16] = KEY_MUTE,
+       [0x17] = KEY_VOLUMEDOWN,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_ati_tv_wonder_hd_600);
index 127b0526a727f15ac9bf6f570e05ac0f352c08a7..7d844af883848a46c5eb99b8b25afbef6fbe46c3 100644 (file)
@@ -313,7 +313,7 @@ static int fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 /*
        DEB_EE(("inode:%p, file:%p, cmd:%d, arg:%li\n",inode, file, cmd, arg));
 */
-       return video_usercopy(inode, file, cmd, arg, saa7146_video_do_ioctl);
+       return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
 }
 
 static int fops_mmap(struct file *file, struct vm_area_struct * vma)
index fe0bd55977e32a1c1858597ffcbf53314eec2071..101b01dbb8eaf11b3c8960ea31e8ec42182e0cad 100644 (file)
@@ -834,7 +834,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
  * copying is done already, arg is a kernel pointer.
  */
 
-static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct saa7146_fh *fh  = file->private_data;
        struct saa7146_dev *dev = fh->dev;
@@ -1216,17 +1216,11 @@ static int __saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *a
 #endif
        default:
                return v4l_compat_translate_ioctl(file, cmd, arg,
-                                                 __saa7146_video_do_ioctl);
+                                                 saa7146_video_do_ioctl);
        }
        return 0;
 }
 
-int saa7146_video_do_ioctl(struct inode *inode, struct file *file,
-                                   unsigned int cmd, void *arg)
-{
-       return __saa7146_video_do_ioctl(file, cmd, arg);
-}
-
 /*********************************************************************************/
 /* buffer handling functions                                                  */
 
index a8878244bb3c40432fe6b3420e32e338ae32f0ad..31522d2e318ea23dbb9ca41c4fcba4b2e7141abf 100644 (file)
@@ -3598,7 +3598,7 @@ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum,
                76, 77, 91, 134, 135, 137, 147,
                156, 166, 167, 168, 25 };
 
-       *count = sizeof(RegAddr) / sizeof(u8);
+       *count = ARRAY_SIZE(RegAddr);
 
        status += MXL_BlockInit(fe);
 
@@ -3630,7 +3630,7 @@ static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal,
        */
 #endif
 
-       *count = sizeof(RegAddr) / sizeof(u8);
+       *count = ARRAY_SIZE(RegAddr);
 
        for (i = 0 ; i < *count; i++) {
                RegNum[i] = RegAddr[i];
@@ -3648,7 +3648,7 @@ static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum,
 
        u8 RegAddr[] = {43, 136};
 
-       *count = sizeof(RegAddr) / sizeof(u8);
+       *count = ARRAY_SIZE(RegAddr);
 
        for (i = 0; i < *count; i++) {
                RegNum[i] = RegAddr[i];
index 4a74f65e759aad5bc622ed7178cd13f1e2416f0c..f4d931f14fad5bae30b8fc73e94aeec3e9891199 100644 (file)
@@ -80,10 +80,11 @@ static void tda827x_set_std(struct dvb_frontend *fe,
                mode = "xx";
        }
 
-       if (params->mode == V4L2_TUNER_RADIO)
+       if (params->mode == V4L2_TUNER_RADIO) {
                priv->sgIF = 88; /* if frequency is 5.5 MHz */
-
-       dprintk("setting tda827x to system %s\n", mode);
+               dprintk("setting tda827x to radio FM\n");
+       } else
+               dprintk("setting tda827x to system %s\n", mode);
 }
 
 
@@ -199,7 +200,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = tuner_freq - if_freq; // FIXME
+       priv->frequency = params->frequency;
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
@@ -304,7 +305,7 @@ static int tda827xo_set_analog_params(struct dvb_frontend *fe,
        reg2[1] = 0x08;   /* Vsync en */
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = freq * 62500;
+       priv->frequency = params->frequency;
 
        return 0;
 }
@@ -591,7 +592,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
                fe->ops.i2c_gate_ctrl(fe, 1);
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = tuner_freq - if_freq; // FIXME
+       priv->frequency = params->frequency;
        priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
        return 0;
@@ -691,7 +692,7 @@ static int tda827xa_set_analog_params(struct dvb_frontend *fe,
        tuner_reg[1] = 0x19 + (priv->lpsel << 1);
        i2c_transfer(priv->i2c_adap, &msg, 1);
 
-       priv->frequency = freq * 62500;
+       priv->frequency = params->frequency;
 
        return 0;
 }
index c112bdd4e0f04a89a7ffe60fdaa143e6721339f8..0ee79fd7c7a95825b8903a21bc23ff01589d0652 100644 (file)
@@ -32,6 +32,9 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
+static int deemphasis_50;
+MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
+
 /* ---------------------------------------------------------------------- */
 
 struct tda8290_priv {
@@ -139,9 +142,34 @@ static void set_audio(struct dvb_frontend *fe,
                mode = "xx";
        }
 
-       tuner_dbg("setting tda829x to system %s\n", mode);
+       if (params->mode == V4L2_TUNER_RADIO) {
+               priv->tda8290_easy_mode = 0x01;         /* Start with MN values */
+               tuner_dbg("setting to radio FM\n");
+       } else {
+               tuner_dbg("setting tda829x to system %s\n", mode);
+       }
 }
 
+struct {
+       unsigned char seq[2];
+} fm_mode[] = {
+       { { 0x01, 0x81} },      /* Put device into expert mode */
+       { { 0x03, 0x48} },      /* Disable NOTCH and VIDEO filters */
+       { { 0x04, 0x04} },      /* Disable color carrier filter (SSIF) */
+       { { 0x05, 0x04} },      /* ADC headroom */
+       { { 0x06, 0x10} },      /* group delay flat */
+
+       { { 0x07, 0x00} },      /* use the same radio DTO values as a tda8295 */
+       { { 0x08, 0x00} },
+       { { 0x09, 0x80} },
+       { { 0x0a, 0xda} },
+       { { 0x0b, 0x4b} },
+       { { 0x0c, 0x68} },
+
+       { { 0x0d, 0x00} },      /* PLL off, no video carrier detect */
+       { { 0x14, 0x00} },      /* disable auto mute if no video */
+};
+
 static void tda8290_set_params(struct dvb_frontend *fe,
                               struct analog_parameters *params)
 {
@@ -178,15 +206,30 @@ static void tda8290_set_params(struct dvb_frontend *fe,
        tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
        msleep(1);
 
-       expert_mode[1] = priv->tda8290_easy_mode + 0x80;
-       tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
-       if (priv->tda8290_easy_mode & 0x60)
-               tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
-       else
-               tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
-       tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+       if (params->mode == V4L2_TUNER_RADIO) {
+               int i;
+               unsigned char deemphasis[]  = { 0x13, 1 };
+
+               /* FIXME: allow using a different deemphasis */
+
+               if (deemphasis_50)
+                       deemphasis[1] = 2;
+
+               for (i = 0; i < ARRAY_SIZE(fm_mode); i++)
+                       tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2);
+
+               tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2);
+       } else {
+               expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+               tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+               if (priv->tda8290_easy_mode & 0x60)
+                       tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
+               else
+                       tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+               tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
+       }
 
        tda8290_i2c_bridge(fe, 1);
 
index ff1788cc5d48ef6068a9759dd61061388e299445..544cdbe88a6c9220eef89326ee363739cb0f2434 100644 (file)
@@ -180,11 +180,10 @@ static struct tvnorm tvnorms[] = {
        },{
                .std   = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H,
                .name  = "SECAM-BGH",
-               .b     = ( cPositiveAmTV  |
+               .b     = ( cNegativeFmTV  |
                           cQSS           ),
                .c     = ( cTopDefault),
-               .e     = ( cGating_36     |
-                          cAudioIF_5_5   |
+               .e     = ( cAudioIF_5_5   |
                           cVideoIF_38_90 ),
        },{
                .std   = V4L2_STD_SECAM_L,
index b65e6803e6c64983d07f4d6c7a00d1e2fefbb96e..1adce9ff52ce0fea7daee80fa46f94e15f85d1b4 100644 (file)
@@ -28,6 +28,12 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+       "1 keep device energized and with tuner ready all the times.\n"
+       "  Faster, but consumes more power and keeps the device hotter\n");
+
 static char audio_std[8];
 module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
 MODULE_PARM_DESC(audio_std,
@@ -1091,6 +1097,34 @@ static int xc2028_set_params(struct dvb_frontend *fe,
                                T_DIGITAL_TV, type, 0, demod);
 }
 
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int rc = 0;
+
+       /* Avoid firmware reload on slow devices */
+       if (no_poweroff)
+               return 0;
+
+       tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
+       if (debug > 1) {
+               tuner_dbg("Printing sleep stack trace:\n");
+               dump_stack();
+       }
+
+       mutex_lock(&priv->lock);
+
+       if (priv->firm_version < 0x0202)
+               rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+       else
+               rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+
+       priv->cur_fw.type = 0;  /* need firmware reload */
+
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
 
 static int xc2028_dvb_release(struct dvb_frontend *fe)
 {
@@ -1171,6 +1205,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
        .get_frequency     = xc2028_get_frequency,
        .get_rf_strength   = xc2028_signal,
        .set_params        = xc2028_set_params,
+       .sleep             = xc2028_sleep,
 };
 
 struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
index e12d13e0cbe9744b790c3b1089ac485aced7a2a8..493ce93caf43538a2580854ab150648cf7dfb059 100644 (file)
@@ -36,10 +36,6 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
-static int xc5000_load_fw_on_attach;
-module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
-MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
-
 static DEFINE_MUTEX(xc5000_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
@@ -1017,9 +1013,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
                sizeof(struct dvb_tuner_ops));
 
-       if (xc5000_load_fw_on_attach)
-               xc5000_init(fe);
-
        return fe;
 fail:
        mutex_unlock(&xc5000_list_mutex);
index 0bcd852576d686a2b556b05e72467d687d49181d..40ebde53b3ce22443a60be62357c5722f64f256d 100644 (file)
@@ -2,6 +2,19 @@
 # DVB device configuration
 #
 
+config DVB_DYNAMIC_MINORS
+       bool "Dynamic DVB minor allocation"
+       depends on DVB_CORE
+       default n
+       help
+         If you say Y here, the DVB subsystem will use dynamic minor
+         allocation for any device that uses the DVB major number.
+         This means that you can have more than 4 of a single type
+         of device (like demuxes and frontends) per adapter, but udev
+         will be required to manage the device nodes.
+
+         If you are unsure about this, say N here.
+
 menuconfig DVB_CAPTURE_DRIVERS
        bool "DVB/ATSC adapters"
        depends on DVB_CORE
index b34301d56cd2859f7b248ee0df8c7899317d59d5..a8c6249c40999c22e8117f64ba3a967fb33088a7 100644 (file)
@@ -14,6 +14,7 @@ config DVB_B2C2_FLEXCOP
        select DVB_ISL6421 if !DVB_FE_CUSTOMISE
        select DVB_CX24123 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+       select DVB_TUNER_CX24113 if !DVB_FE_CUSTOMISE
        help
          Support for the digital TV receiver chip made by B2C2 Inc. included in
          Technisats PCI cards and USB boxes.
index a21ce9edcc7ee1f383567ed8bc48a0d5d452c143..f48f73aff195ae7d60a918288d15027983a62a8a 100644 (file)
@@ -19,7 +19,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -368,7 +367,7 @@ static int __devinit dm1105dvb_dma_map(struct dm1105dvb *dm1105dvb)
 {
        dm1105dvb->ts_buf = pci_alloc_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, &dm1105dvb->dma_addr);
 
-       return pci_dma_mapping_error(dm1105dvb->pdev, dm1105dvb->dma_addr);
+       return !dm1105dvb->ts_buf;
 }
 
 static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb)
index 7a421e9dba5aeef3e0ee51036dfe327359fbd273..171f9ca124f715d2bc05f3656e1b1892dd08ec1a 100644 (file)
@@ -128,6 +128,7 @@ struct dvb_frontend_private {
        unsigned int step_size;
        int quality;
        unsigned int check_wrapped;
+       enum dvbfe_search algo_status;
 };
 
 static void dvb_frontend_wakeup(struct dvb_frontend *fe);
@@ -516,6 +517,8 @@ static int dvb_frontend_thread(void *data)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        unsigned long timeout;
        fe_status_t s;
+       enum dvbfe_algo algo;
+
        struct dvb_frontend_parameters *params;
 
        dprintk("%s\n", __func__);
@@ -562,23 +565,80 @@ restart:
 
                /* do an iteration of the tuning loop */
                if (fe->ops.get_frontend_algo) {
-                       if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
-                               /* have we been asked to retune? */
-                               params = NULL;
+                       algo = fe->ops.get_frontend_algo(fe);
+                       switch (algo) {
+                       case DVBFE_ALGO_HW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
+                               params = NULL; /* have we been asked to RETUNE ? */
+
                                if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
                                        params = &fepriv->parameters;
                                        fepriv->state = FESTATE_TUNED;
                                }
 
-                               fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
-                               if (s != fepriv->status) {
+                               if (fe->ops.tune)
+                                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+
+                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+                                       dprintk("%s: state changed, adding current state\n", __func__);
                                        dvb_frontend_add_event(fe, s);
                                        fepriv->status = s;
                                }
-                       } else
+                               break;
+                       case DVBFE_ALGO_SW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
                                dvb_frontend_swzigzag(fe);
-               } else
+                               break;
+                       case DVBFE_ALGO_CUSTOM:
+                               params = NULL; /* have we been asked to RETUNE ?        */
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+                                       params = &fepriv->parameters;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               /* Case where we are going to search for a carrier
+                                * User asked us to retune again for some reason, possibly
+                                * requesting a search with a new set of parameters
+                                */
+                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+                                       if (fe->ops.search) {
+                                               fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
+                                               /* We did do a search as was requested, the flags are
+                                                * now unset as well and has the flags wrt to search.
+                                                */
+                                       } else {
+                                               fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
+                                       }
+                               }
+                               /* Track the carrier if the search was successful */
+                               if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
+                                       if (fe->ops.track)
+                                               fe->ops.track(fe, &fepriv->parameters);
+                               } else {
+                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       fepriv->delay = HZ / 2;
+                               }
+                               fe->ops.read_status(fe, &s);
+                               if (s != fepriv->status) {
+                                       dvb_frontend_add_event(fe, s); /* update event list */
+                                       fepriv->status = s;
+                                       if (!(s & FE_HAS_LOCK)) {
+                                               fepriv->delay = HZ / 10;
+                                               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       } else {
+                                               fepriv->delay = 60 * HZ;
+                                       }
+                               }
+                               break;
+                       default:
+                               dprintk("%s: UNDEFINED ALGO !\n", __func__);
+                               break;
+                       }
+               } else {
                        dvb_frontend_swzigzag(fe);
+               }
        }
 
        if (dvb_powerdown_on_sleep) {
@@ -1226,6 +1286,9 @@ int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
                dprintk("%s() Finalised property cache\n", __func__);
                dtv_property_cache_submit(fe);
 
+               /* Request the search algorithm to search */
+               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
                r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
                        &fepriv->parameters);
                break;
index db4a63b0a32e6e30a296e4b2ccae64f826ca8502..e176da472d7a716d69799546270d10e9979732f3 100644 (file)
@@ -69,6 +69,125 @@ struct analog_parameters {
        u64 std;
 };
 
+enum dvbfe_modcod {
+       DVBFE_MODCOD_DUMMY_PLFRAME      = 0,
+       DVBFE_MODCOD_QPSK_1_4,
+       DVBFE_MODCOD_QPSK_1_3,
+       DVBFE_MODCOD_QPSK_2_5,
+       DVBFE_MODCOD_QPSK_1_2,
+       DVBFE_MODCOD_QPSK_3_5,
+       DVBFE_MODCOD_QPSK_2_3,
+       DVBFE_MODCOD_QPSK_3_4,
+       DVBFE_MODCOD_QPSK_4_5,
+       DVBFE_MODCOD_QPSK_5_6,
+       DVBFE_MODCOD_QPSK_8_9,
+       DVBFE_MODCOD_QPSK_9_10,
+       DVBFE_MODCOD_8PSK_3_5,
+       DVBFE_MODCOD_8PSK_2_3,
+       DVBFE_MODCOD_8PSK_3_4,
+       DVBFE_MODCOD_8PSK_5_6,
+       DVBFE_MODCOD_8PSK_8_9,
+       DVBFE_MODCOD_8PSK_9_10,
+       DVBFE_MODCOD_16APSK_2_3,
+       DVBFE_MODCOD_16APSK_3_4,
+       DVBFE_MODCOD_16APSK_4_5,
+       DVBFE_MODCOD_16APSK_5_6,
+       DVBFE_MODCOD_16APSK_8_9,
+       DVBFE_MODCOD_16APSK_9_10,
+       DVBFE_MODCOD_32APSK_3_4,
+       DVBFE_MODCOD_32APSK_4_5,
+       DVBFE_MODCOD_32APSK_5_6,
+       DVBFE_MODCOD_32APSK_8_9,
+       DVBFE_MODCOD_32APSK_9_10,
+       DVBFE_MODCOD_RESERVED_1,
+       DVBFE_MODCOD_BPSK_1_3,
+       DVBFE_MODCOD_BPSK_1_4,
+       DVBFE_MODCOD_RESERVED_2
+};
+
+enum tuner_param {
+       DVBFE_TUNER_FREQUENCY           = (1 <<  0),
+       DVBFE_TUNER_TUNERSTEP           = (1 <<  1),
+       DVBFE_TUNER_IFFREQ              = (1 <<  2),
+       DVBFE_TUNER_BANDWIDTH           = (1 <<  3),
+       DVBFE_TUNER_REFCLOCK            = (1 <<  4),
+       DVBFE_TUNER_IQSENSE             = (1 <<  5),
+       DVBFE_TUNER_DUMMY               = (1 << 31)
+};
+
+/*
+ * ALGO_HW: (Hardware Algorithm)
+ * ----------------------------------------------------------------
+ * Devices that support this algorithm do everything in hardware
+ * and no software support is needed to handle them.
+ * Requesting these devices to LOCK is the only thing required,
+ * device is supposed to do everything in the hardware.
+ *
+ * ALGO_SW: (Software Algorithm)
+ * ----------------------------------------------------------------
+ * These are dumb devices, that require software to do everything
+ *
+ * ALGO_CUSTOM: (Customizable Agorithm)
+ * ----------------------------------------------------------------
+ * Devices having this algorithm can be customized to have specific
+ * algorithms in the frontend driver, rather than simply doing a
+ * software zig-zag. In this case the zigzag maybe hardware assisted
+ * or it maybe completely done in hardware. In all cases, usage of
+ * this algorithm, in conjunction with the search and track
+ * callbacks, utilizes the driver specific algorithm.
+ *
+ * ALGO_RECOVERY: (Recovery Algorithm)
+ * ----------------------------------------------------------------
+ * These devices have AUTO recovery capabilities from LOCK failure
+ */
+enum dvbfe_algo {
+       DVBFE_ALGO_HW                   = (1 <<  0),
+       DVBFE_ALGO_SW                   = (1 <<  1),
+       DVBFE_ALGO_CUSTOM               = (1 <<  2),
+       DVBFE_ALGO_RECOVERY             = (1 << 31)
+};
+
+struct tuner_state {
+       u32 frequency;
+       u32 tunerstep;
+       u32 ifreq;
+       u32 bandwidth;
+       u32 iqsense;
+       u32 refclock;
+};
+
+/*
+ * search callback possible return status
+ *
+ * DVBFE_ALGO_SEARCH_SUCCESS
+ * The frontend search algorithm completed and returned succesfully
+ *
+ * DVBFE_ALGO_SEARCH_ASLEEP
+ * The frontend search algorithm is sleeping
+ *
+ * DVBFE_ALGO_SEARCH_FAILED
+ * The frontend search for a signal failed
+ *
+ * DVBFE_ALGO_SEARCH_INVALID
+ * The frontend search algorith was probably supplied with invalid
+ * parameters and the search is an invalid one
+ *
+ * DVBFE_ALGO_SEARCH_ERROR
+ * The frontend search algorithm failed due to some error
+ *
+ * DVBFE_ALGO_SEARCH_AGAIN
+ * The frontend search algorithm was requested to search again
+ */
+enum dvbfe_search {
+       DVBFE_ALGO_SEARCH_SUCCESS       = (1 <<  0),
+       DVBFE_ALGO_SEARCH_ASLEEP        = (1 <<  1),
+       DVBFE_ALGO_SEARCH_FAILED        = (1 <<  2),
+       DVBFE_ALGO_SEARCH_INVALID       = (1 <<  3),
+       DVBFE_ALGO_SEARCH_AGAIN         = (1 <<  4),
+       DVBFE_ALGO_SEARCH_ERROR         = (1 << 31),
+};
+
+
 struct dvb_tuner_ops {
 
        struct dvb_tuner_info info;
@@ -99,6 +218,13 @@ struct dvb_tuner_ops {
         * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
        int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
        int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+
+       /*
+        * These are provided seperately from set_params in order to facilitate silicon
+        * tuners which require sophisticated tuning loops, controlling each parameter seperately.
+        */
+       int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+       int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
 };
 
 struct analog_demod_info {
@@ -142,7 +268,7 @@ struct dvb_frontend_ops {
                    unsigned int *delay,
                    fe_status_t *status);
        /* get frontend tuning algorithm from the module */
-       int (*get_frontend_algo)(struct dvb_frontend *fe);
+       enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
 
        /* these two are only used for the swzigzag code */
        int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -167,6 +293,12 @@ struct dvb_frontend_ops {
        int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
        int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
 
+       /* These callbacks are for devices that implement their own
+        * tuning algorithms, rather than a simple swzigzag
+        */
+       enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+       int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
        struct dvb_tuner_ops tuner_ops;
        struct analog_demod_ops analog_ops;
 
index a113744a56cc136c0355184b0af4504b0219970a..6c571d9f011c6df050c23230c399390e5c3e7334 100644 (file)
@@ -50,33 +50,27 @@ static const char * const dnames[] = {
        "net", "osd"
 };
 
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+#define MAX_DVB_MINORS         256
+#define DVB_MAX_IDS            MAX_DVB_MINORS
+#else
 #define DVB_MAX_IDS            4
 #define nums2minor(num,type,id)        ((num << 6) | (id << 4) | type)
 #define MAX_DVB_MINORS         (DVB_MAX_ADAPTERS*64)
+#endif
 
 static struct class *dvb_class;
 
-static struct dvb_device* dvbdev_find_device (int minor)
-{
-       struct dvb_adapter *adap;
-
-       list_for_each_entry(adap, &dvb_adapter_list, list_head) {
-               struct dvb_device *dev;
-               list_for_each_entry(dev, &adap->device_list, list_head)
-                       if (nums2minor(adap->num, dev->type, dev->id) == minor)
-                               return dev;
-       }
-
-       return NULL;
-}
-
+static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
 
 static int dvb_device_open(struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev;
 
        lock_kernel();
-       dvbdev = dvbdev_find_device (iminor(inode));
+       down_read(&minor_rwsem);
+       dvbdev = dvb_minors[iminor(inode)];
 
        if (dvbdev && dvbdev->fops) {
                int err = 0;
@@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
                        file->f_op = fops_get(old_fops);
                }
                fops_put(old_fops);
+               up_read(&minor_rwsem);
                unlock_kernel();
                return err;
        }
+       up_read(&minor_rwsem);
        unlock_kernel();
        return -ENODEV;
 }
@@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        struct dvb_device *dvbdev;
        struct file_operations *dvbdevfops;
        struct device *clsdev;
+       int minor;
        int id;
 
        mutex_lock(&dvbdev_register_lock);
@@ -231,11 +228,31 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
 
        list_add_tail (&dvbdev->list_head, &adap->device_list);
 
+       down_write(&minor_rwsem);
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+       for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+               if (dvb_minors[minor] == NULL)
+                       break;
+
+       if (minor == MAX_DVB_MINORS) {
+               kfree(dvbdevfops);
+               kfree(dvbdev);
+               mutex_unlock(&dvbdev_register_lock);
+               return -EINVAL;
+       }
+#else
+       minor = nums2minor(adap->num, type, id);
+#endif
+
+       dvbdev->minor = minor;
+       dvb_minors[minor] = dvbdev;
+       up_write(&minor_rwsem);
+
        mutex_unlock(&dvbdev_register_lock);
 
        clsdev = device_create(dvb_class, adap->device,
-                              MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
-                              NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+                              MKDEV(DVB_MAJOR, minor),
+                              dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
        if (IS_ERR(clsdev)) {
                printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
                       __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
        }
 
        dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
-               adap->num, dnames[type], id, nums2minor(adap->num, type, id),
-               nums2minor(adap->num, type, id));
+               adap->num, dnames[type], id, minor, minor);
 
        return 0;
 }
@@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
        if (!dvbdev)
                return;
 
-       device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
-                      dvbdev->type, dvbdev->id)));
+       down_write(&minor_rwsem);
+       dvb_minors[dvbdev->minor] = NULL;
+       up_write(&minor_rwsem);
+
+       device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
 
        list_del (&dvbdev->list_head);
        kfree (dvbdev->fops);
@@ -413,6 +432,15 @@ out:
        return err;
 }
 
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+       add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+       return 0;
+}
+
 static int __init init_dvbdev(void)
 {
        int retval;
@@ -434,6 +462,7 @@ static int __init init_dvbdev(void)
                retval = PTR_ERR(dvb_class);
                goto error;
        }
+       dvb_class->dev_uevent = dvb_uevent;
        return 0;
 
 error:
index 574e336bac35b7b8d81471a32fea7c2558fc530c..dca49cf962e864c37cefad089669187735f8c524 100644 (file)
@@ -74,6 +74,7 @@ struct dvb_device {
        struct file_operations *fops;
        struct dvb_adapter *adapter;
        int type;
+       int minor;
        u32 id;
 
        /* in theory, 'users' can vanish now,
index e9ab0249d13305435715bc5b4b7c03d9d9aef888..e1e9aa5c6b843991c13ba4286ed92d650b728e97 100644 (file)
@@ -733,9 +733,19 @@ static int af9015_read_config(struct usb_device *udev)
                                af9015_config.ir_table_size =
                                  ARRAY_SIZE(af9015_ir_table_mygictv);
                                break;
+                       case AF9015_REMOTE_DIGITTRADE_DVB_T:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_digittrade;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_digittrade);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_digittrade;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_digittrade);
+                               break;
                        }
                } else {
-                       switch (udev->descriptor.idVendor) {
+                       switch (le16_to_cpu(udev->descriptor.idVendor)) {
                        case USB_VID_LEADTEK:
                                af9015_properties[i].rc_key_map =
                                  af9015_rc_keys_leadtek;
@@ -748,7 +758,7 @@ static int af9015_read_config(struct usb_device *udev)
                                break;
                        case USB_VID_VISIONPLUS:
                                if (udev->descriptor.idProduct ==
-                               USB_PID_AZUREWAVE_AD_TU700) {
+                               cpu_to_le16(USB_PID_AZUREWAVE_AD_TU700)) {
                                        af9015_properties[i].rc_key_map =
                                          af9015_rc_keys_twinhan;
                                        af9015_properties[i].rc_key_map_size =
@@ -800,6 +810,16 @@ static int af9015_read_config(struct usb_device *udev)
                                          ARRAY_SIZE(af9015_ir_table_msi);
                                }
                                break;
+                       case USB_VID_AVERMEDIA:
+                               af9015_properties[i].rc_key_map =
+                                 af9015_rc_keys_avermedia;
+                               af9015_properties[i].rc_key_map_size =
+                                 ARRAY_SIZE(af9015_rc_keys_avermedia);
+                               af9015_config.ir_table =
+                                 af9015_ir_table_avermedia;
+                               af9015_config.ir_table_size =
+                                 ARRAY_SIZE(af9015_ir_table_avermedia);
+                               break;
                        }
                }
        }
@@ -1191,6 +1211,7 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
        {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
 /* 15 */{USB_DEVICE(USB_VID_MSI_2,     USB_PID_MSI_DIGI_VOX_MINI_III)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1343,7 +1364,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 6,
+               .num_device_descs = 7,
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1375,6 +1396,12 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .cold_ids = {&af9015_usb_table[15], NULL},
                                .warm_ids = {NULL},
                        },
+                       {
+                               .name = "KWorld USB DVB-T TV Stick II " \
+                                       "(VS-DVB-T 395U)",
+                               .cold_ids = {&af9015_usb_table[16], NULL},
+                               .warm_ids = {NULL},
+                       },
                }
        }
 };
index 6c3c97293316b29c2606eb29837b8b1c789a381c..21c7782f4889c32121d6ac1b3d668319d9e3d961 100644 (file)
@@ -123,6 +123,7 @@ enum af9015_remote {
        AF9015_REMOTE_A_LINK_DTU_M,
        AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
        AF9015_REMOTE_MYGICTV_U718,
+       AF9015_REMOTE_DIGITTRADE_DVB_T,
 };
 
 /* Leadtek WinFast DTV Dongle Gold */
@@ -520,4 +521,143 @@ static u8 af9015_ir_table_kworld[] = {
        0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
 };
 
+/* AverMedia Volar X */
+static struct dvb_usb_rc_key af9015_rc_keys_avermedia[] = {
+       { 0x05, 0x3d, KEY_PROG1 },       /* SOURCE */
+       { 0x05, 0x12, KEY_POWER },       /* POWER */
+       { 0x05, 0x1e, KEY_1 },           /* 1 */
+       { 0x05, 0x1f, KEY_2 },           /* 2 */
+       { 0x05, 0x20, KEY_3 },           /* 3 */
+       { 0x05, 0x21, KEY_4 },           /* 4 */
+       { 0x05, 0x22, KEY_5 },           /* 5 */
+       { 0x05, 0x23, KEY_6 },           /* 6 */
+       { 0x05, 0x24, KEY_7 },           /* 7 */
+       { 0x05, 0x25, KEY_8 },           /* 8 */
+       { 0x05, 0x26, KEY_9 },           /* 9 */
+       { 0x05, 0x3f, KEY_LEFT },        /* L / DISPLAY */
+       { 0x05, 0x27, KEY_0 },           /* 0 */
+       { 0x05, 0x0f, KEY_RIGHT },       /* R / CH RTN */
+       { 0x05, 0x18, KEY_PROG2 },       /* SNAP SHOT */
+       { 0x05, 0x1c, KEY_PROG3 },       /* 16-CH PREV */
+       { 0x05, 0x2d, KEY_VOLUMEDOWN },  /* VOL DOWN */
+       { 0x05, 0x3e, KEY_ZOOM },        /* FULL SCREEN */
+       { 0x05, 0x2e, KEY_VOLUMEUP },    /* VOL UP */
+       { 0x05, 0x10, KEY_MUTE },        /* MUTE */
+       { 0x05, 0x04, KEY_AUDIO },       /* AUDIO */
+       { 0x05, 0x15, KEY_RECORD },      /* RECORD */
+       { 0x05, 0x11, KEY_PLAY },        /* PLAY */
+       { 0x05, 0x16, KEY_STOP },        /* STOP */
+       { 0x05, 0x0c, KEY_PLAYPAUSE },   /* TIMESHIFT / PAUSE */
+       { 0x05, 0x05, KEY_BACK },        /* << / RED */
+       { 0x05, 0x09, KEY_FORWARD },     /* >> / YELLOW */
+       { 0x05, 0x17, KEY_TEXT },        /* TELETEXT */
+       { 0x05, 0x0a, KEY_EPG },         /* EPG */
+       { 0x05, 0x13, KEY_MENU },        /* MENU */
+
+       { 0x05, 0x0e, KEY_CHANNELUP },   /* CH UP */
+       { 0x05, 0x0d, KEY_CHANNELDOWN }, /* CH DOWN */
+       { 0x05, 0x19, KEY_FIRST },       /* |<< / GREEN */
+       { 0x05, 0x08, KEY_LAST },        /* >>| / BLUE */
+};
+
+static u8 af9015_ir_table_avermedia[] = {
+       0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
+       0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
+       0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
+       0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
+       0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
+       0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
+       0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
+       0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
+       0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
+       0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
+       0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
+       0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
+       0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
+       0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
+       0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
+       0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
+       0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
+       0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
+       0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
+       0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
+       0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
+       0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
+       0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
+       0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
+       0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
+       0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
+       0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
+       0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
+       0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
+       0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
+       0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
+       0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
+       0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
+       0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
+};
+
+/* Digittrade DVB-T USB Stick */
+static struct dvb_usb_rc_key af9015_rc_keys_digittrade[] = {
+       { 0x01, 0x0f, KEY_LAST },       /* RETURN */
+       { 0x05, 0x17, KEY_TEXT },       /* TELETEXT */
+       { 0x01, 0x08, KEY_EPG },        /* EPG */
+       { 0x05, 0x13, KEY_POWER },      /* POWER */
+       { 0x01, 0x09, KEY_ZOOM },       /* FULLSCREEN */
+       { 0x00, 0x40, KEY_AUDIO },      /* DUAL SOUND */
+       { 0x00, 0x2c, KEY_PRINT },      /* SNAPSHOT */
+       { 0x05, 0x16, KEY_SUBTITLE },   /* SUBTITLE */
+       { 0x00, 0x52, KEY_CHANNELUP },  /* CH Up */
+       { 0x00, 0x51, KEY_CHANNELDOWN },/* Ch Dn */
+       { 0x00, 0x57, KEY_VOLUMEUP },   /* Vol Up */
+       { 0x00, 0x56, KEY_VOLUMEDOWN }, /* Vol Dn */
+       { 0x01, 0x10, KEY_MUTE },       /* MUTE */
+       { 0x00, 0x27, KEY_0 },
+       { 0x00, 0x1e, KEY_1 },
+       { 0x00, 0x1f, KEY_2 },
+       { 0x00, 0x20, KEY_3 },
+       { 0x00, 0x21, KEY_4 },
+       { 0x00, 0x22, KEY_5 },
+       { 0x00, 0x23, KEY_6 },
+       { 0x00, 0x24, KEY_7 },
+       { 0x00, 0x25, KEY_8 },
+       { 0x00, 0x26, KEY_9 },
+       { 0x01, 0x17, KEY_PLAYPAUSE },  /* TIMESHIFT */
+       { 0x01, 0x15, KEY_RECORD },     /* RECORD */
+       { 0x03, 0x13, KEY_PLAY },       /* PLAY */
+       { 0x01, 0x16, KEY_STOP },       /* STOP */
+       { 0x01, 0x13, KEY_PAUSE },      /* PAUSE */
+};
+
+static u8 af9015_ir_table_digittrade[] = {
+       0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
+       0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
+       0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
+       0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
+       0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
+       0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
+       0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
+       0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
+       0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
+       0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
+       0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
+       0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
+       0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
+       0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
+       0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
+       0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
+       0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
+       0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
+       0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
+       0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
+       0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
+       0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
+       0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
+       0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
+       0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
+       0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
+       0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
+       0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
+};
+
 #endif
index cd2edbcaa09755e0c3d7e76b585f346731114983..5017f08b14a6a2de96771727cc9c254cad0d8e4e 100644 (file)
@@ -153,7 +153,7 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
        int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       int ret, inc, i = 0;
+       int ret = 0, inc, i = 0;
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
index 3ac9f74e9fbf30c1207e4aa34b6bf604e9fb7cc6..80e37a0d0892298c167356d5a0b1b2158c518f6a 100644 (file)
@@ -32,7 +32,6 @@
 
 /* debug */
 int dvb_usb_cinergyt2_debug;
-int disable_remote;
 
 module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 "
@@ -45,7 +44,7 @@ struct cinergyt2_state {
 };
 
 /* We are missing a release hook with usb_device data */
-struct dvb_usb_device *cinergyt2_usb_device;
+static struct dvb_usb_device *cinergyt2_usb_device;
 
 static struct dvb_usb_device_properties cinergyt2_properties;
 
index 11d79eb384c882c23556ae69e1005ed29ef2d10a..84efe03771eb1da8278cf613fd051f2b58f17b35 100644 (file)
@@ -70,11 +70,11 @@ struct dvbt_get_status_msg {
        uint8_t bandwidth;
        uint16_t tps;
        uint8_t flags;
-       uint16_t gain;
+       __le16 gain;
        uint8_t snr;
-       uint32_t viterbi_error_rate;
+       __le32 viterbi_error_rate;
        uint32_t rs_error_rate;
-       uint32_t uncorrected_block_count;
+       __le32 uncorrected_block_count;
        uint8_t lock_bits;
        uint8_t prev_lock_bits;
 } __attribute__((packed));
@@ -82,9 +82,9 @@ struct dvbt_get_status_msg {
 
 struct dvbt_set_parameters_msg {
        uint8_t cmd;
-       uint32_t freq;
+       __le32 freq;
        uint8_t bandwidth;
-       uint16_t tps;
+       __le16 tps;
        uint8_t flags;
 } __attribute__((packed));
 
index 7380b94b3b36065af00051e7f5f965fb18f3afc1..a4fca3fca5eede1e7c1c4913a7905d72738b804b 100644 (file)
@@ -96,6 +96,7 @@
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_KWORLD_399U                            0xe399
+#define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
index 6286fbbe7fb5bd1178065d5618c817ab2da5a45d..c65f273ff313cda9d874f3183f343949da953169 100644 (file)
@@ -9,7 +9,6 @@
 *
 * see Documentation/dvb/README.dvb-usb for more information
 */
-#include <linux/version.h>
 #include "dw2102.h"
 #include "si21xx.h"
 #include "stv0299.h"
 #define USB_PID_DW2104 0x2104
 #endif
 
+#ifndef USB_PID_CINERGY_S
+#define USB_PID_CINERGY_S 0x0064
+#endif
+
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
 
@@ -578,6 +581,7 @@ static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
        {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
        {USB_DEVICE(0x9022, 0xd650)},
+       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
        { }
 };
 
@@ -647,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
                        break;
+               case USB_PID_CINERGY_S:
                case USB_PID_DW2102:
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
@@ -655,7 +660,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                        /* check STV0299 frontend  */
                        dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
                                        DW210X_READ_MSG);
-                       if (reset16[0] == 0xa1) {
+                       if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
                                dw2102_properties.i2c_algo = &dw2102_i2c_algo;
                                dw2102_properties.adapter->tuner_attach = &dw2102_tuner_attach;
                                break;
@@ -726,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
                        },
                }
        },
-       .num_device_descs = 2,
+       .num_device_descs = 3,
        .devices = {
                {"DVBWorld DVB-S 2102 USB2.0",
                        {&dw2102_table[0], NULL},
@@ -736,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = {
                        {&dw2102_table[1], NULL},
                        {NULL},
                },
+               {"TerraTec Cinergy S USB",
+                       {&dw2102_table[4], NULL},
+                       {NULL},
+               },
        }
 };
 
index 262a858c30684e28e0798034e776ed9138f3f255..20eadf9318e08eca422c11f68ab96d4b2557a0c6 100644 (file)
@@ -25,6 +25,20 @@ struct gp8psk_fe_state {
        unsigned long status_check_interval;
 };
 
+static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe)
+{
+       struct gp8psk_fe_state *st = fe->demodulator_priv;
+       u8 status;
+       gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1);
+       return status & bmDCtuned;
+}
+
+static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode)
+{
+       struct gp8psk_fe_state *state = fe->demodulator_priv;
+       return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0);
+}
+
 static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
 {
        u8 buf[6];
@@ -99,39 +113,114 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front
        return 0;
 }
 
+static int gp8psk_fe_set_property(struct dvb_frontend *fe,
+       struct dtv_property *tvp)
+{
+       deb_fe("%s(..)\n", __func__);
+       return 0;
+}
+
+static int gp8psk_fe_get_property(struct dvb_frontend *fe,
+       struct dtv_property *tvp)
+{
+       deb_fe("%s(..)\n", __func__);
+       return 0;
+}
+
+
 static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
                                  struct dvb_frontend_parameters *fep)
 {
        struct gp8psk_fe_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        u8 cmd[10];
        u32 freq = fep->frequency * 1000;
+       int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
+
+       deb_fe("%s()\n", __func__);
 
        cmd[4] = freq         & 0xff;
        cmd[5] = (freq >> 8)  & 0xff;
        cmd[6] = (freq >> 16) & 0xff;
        cmd[7] = (freq >> 24) & 0xff;
 
-       switch(fe->ops.info.type) {
-       case FE_QPSK:
-               cmd[0] =  fep->u.qpsk.symbol_rate        & 0xff;
-               cmd[1] = (fep->u.qpsk.symbol_rate >>  8) & 0xff;
-               cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
-               cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
-               cmd[8] = ADV_MOD_DVB_QPSK;
-               cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               /* Only QPSK is supported for DVB-S */
+               if (c->modulation != QPSK) {
+                       deb_fe("%s: unsupported modulation selected (%d)\n",
+                               __func__, c->modulation);
+                       return -EOPNOTSUPP;
+               }
+               c->fec_inner = FEC_AUTO;
                break;
+       case SYS_DVBS2:
+               deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
+               break;
+
        default:
-               // other modes are unsuported right now
-               cmd[0] = 0;
-               cmd[1] = 0;
-               cmd[2] = 0;
-               cmd[3] = 0;
-               cmd[8] = 0;
+               deb_fe("%s: unsupported delivery system selected (%d)\n",
+                       __func__, c->delivery_system);
+               return -EOPNOTSUPP;
+       }
+
+       cmd[0] =  c->symbol_rate        & 0xff;
+       cmd[1] = (c->symbol_rate >>  8) & 0xff;
+       cmd[2] = (c->symbol_rate >> 16) & 0xff;
+       cmd[3] = (c->symbol_rate >> 24) & 0xff;
+       switch (c->modulation) {
+       case QPSK:
+               if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+                       if (gp8psk_tuned_to_DCII(fe))
+                               gp8psk_bcm4500_reload(state->d);
+               switch (c->fec_inner) {
+               case FEC_1_2:
+                       cmd[9] = 0; break;
+               case FEC_2_3:
+                       cmd[9] = 1; break;
+               case FEC_3_4:
+                       cmd[9] = 2; break;
+               case FEC_5_6:
+                       cmd[9] = 3; break;
+               case FEC_7_8:
+                       cmd[9] = 4; break;
+               case FEC_AUTO:
+                       cmd[9] = 5; break;
+               default:
+                       cmd[9] = 5; break;
+               }
+               cmd[8] = ADV_MOD_DVB_QPSK;
+               break;
+       case PSK_8: /* PSK_8 is for compatibility with DN */
+               cmd[8] = ADV_MOD_TURBO_8PSK;
+               switch (c->fec_inner) {
+               case FEC_2_3:
+                       cmd[9] = 0; break;
+               case FEC_3_4:
+                       cmd[9] = 1; break;
+               case FEC_3_5:
+                       cmd[9] = 2; break;
+               case FEC_5_6:
+                       cmd[9] = 3; break;
+               case FEC_8_9:
+                       cmd[9] = 4; break;
+               default:
+                       cmd[9] = 0; break;
+               }
+               break;
+       case QAM_16: /* QAM_16 is for compatibility with DN */
+               cmd[8] = ADV_MOD_TURBO_16QAM;
                cmd[9] = 0;
                break;
+       default: /* Unknown modulation */
+               deb_fe("%s: unsupported modulation selected (%d)\n",
+                       __func__, c->modulation);
+               return -EOPNOTSUPP;
        }
 
-       gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+       if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+               gp8psk_set_tuner_mode(fe, 0);
+       gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
 
        state->lock = 0;
        state->next_status_check = jiffies;
@@ -140,13 +229,6 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
        return 0;
 }
 
-static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
-                                 struct dvb_frontend_parameters *fep)
-{
-       return 0;
-}
-
-
 static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
                                    struct dvb_diseqc_master_cmd *m)
 {
@@ -261,9 +343,13 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
                .symbol_rate_max        = 45000000,
                .symbol_rate_tolerance  = 500,  /* ppm */
                .caps = FE_CAN_INVERSION_AUTO |
-                               FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
-                               FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
-                               FE_CAN_QPSK
+                       FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+                       /*
+                        * FE_CAN_QAM_16 is for compatibility
+                        * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
+                        */
+                       FE_CAN_QPSK | FE_CAN_QAM_16
        },
 
        .release = gp8psk_fe_release,
@@ -271,8 +357,10 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
        .init = NULL,
        .sleep = NULL,
 
+       .set_property = gp8psk_fe_set_property,
+       .get_property = gp8psk_fe_get_property,
        .set_frontend = gp8psk_fe_set_frontend,
-       .get_frontend = gp8psk_fe_get_frontend,
+
        .get_tune_settings = gp8psk_fe_get_tune_settings,
 
        .read_status = gp8psk_fe_read_status,
index d965a923f3914e626d3f1cfe35a417ceb417b5dd..c1da962cc8863261fa5a833c72451055b79b4c6b 100644 (file)
@@ -174,6 +174,22 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
        return 0;
 }
 
+int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+{
+       u8 buf;
+       int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+       /* Turn off 8psk power */
+       if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+               return -EINVAL;
+       /* Turn On 8psk power */
+       if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+               return -EINVAL;
+       /* load BCM4500 firmware */
+       if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+               if (gp8psk_load_bcm4500fw(d))
+                       return EINVAL;
+       return 0;
+}
 
 static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
index e5cd8149c23dc3ea37bf6dcc5d2cea82ea97962e..e83a57506cfa945b2f97d16fb8fc9808221f981d 100644 (file)
@@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
 extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
 extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
                             u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
 
 #endif
index da93b9e982c04e3c67dbc0db671d43ca313a41ee..9da2cc95ca133990115ffeaab2a4f89f931e95a3 100644 (file)
@@ -156,7 +156,8 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream)
                                stream->props.u.bulk.buffersize,
                                usb_urb_complete, stream);
 
-               stream->urb_list[i]->transfer_flags = 0;
+               stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
                stream->urbs_initialized++;
        }
        return 0;
index 96b93e21a84bdbb6ddeb9ea2e3635b50ca0da149..00269560793ae7849d6c320efbd7cfb200a89740 100644 (file)
@@ -12,6 +12,25 @@ config DVB_FE_CUSTOMISE
 
          If unsure say N.
 
+comment "Multistandard (satellite) frontends"
+       depends on DVB_CORE
+
+config DVB_STB0899
+       tristate "STB0899 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want
+         to support this demodulator based frontends
+
+config DVB_STB6100
+       tristate "STB6100 based tuners"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A Silicon tuner from ST used in conjunction with the STB0899
+         demodulator. Say Y when you want to support this tuner.
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
@@ -78,6 +97,13 @@ config DVB_TDA10086
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_TDA8261
+       tristate "Philips TDA8261 based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
 config DVB_VES1X93
        tristate "VLSI VES1893 or VES1993 based"
        depends on DVB_CORE && I2C
@@ -92,6 +118,14 @@ config DVB_TUNER_ITD1000
        help
          A DVB-S tuner module. Say Y when you want to support this frontend.
 
+config DVB_TUNER_CX24113
+       tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A DVB-S tuner module. Say Y when you want to support this frontend.
+
+
 config DVB_TDA826X
        tristate "Philips TDA826X silicon tuner"
        depends on DVB_CORE && I2C
@@ -345,6 +379,14 @@ config DVB_LGDT330X
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+config DVB_LGDT3304
+       tristate "LG Electronics LGDT3304"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+         to support this frontend.
+
 config DVB_S5H1409
        tristate "Samsung S5H1409 based"
        depends on DVB_CORE && I2C
@@ -369,6 +411,17 @@ config DVB_S5H1411
          An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
          to support this frontend.
 
+comment "ISDB-T (terrestrial) frontends"
+       depends on DVB_CORE
+
+config DVB_S921
+       tristate "Sharp S921 tuner"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module.
+         Say Y when you want to support this frontend.
+
 comment "Digital terrestrial only tuners/PLL"
        depends on DVB_CORE
 
index aba79f4a63a7217475079e694cb9fc4fbb052d34..af7bdf0ad4c79ae7390d8ae7525e5e04c6f7a51f 100644 (file)
@@ -5,8 +5,13 @@
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 EXTRA_CFLAGS += -Idrivers/media/common/tuners/
 
+s921-objs := s921_module.o s921_core.o
+stb0899-objs = stb0899_drv.o stb0899_algo.o
+
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
+obj-$(CONFIG_DVB_STB0899) += stb0899.o
+obj-$(CONFIG_DVB_STB6100) += stb6100.o
 obj-$(CONFIG_DVB_SP8870) += sp8870.o
 obj-$(CONFIG_DVB_CX22700) += cx22700.o
 obj-$(CONFIG_DVB_CX24110) += cx24110.o
@@ -35,18 +40,21 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
 obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
 obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
 obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
+obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
 obj-$(CONFIG_DVB_CX24123) += cx24123.o
 obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
 obj-$(CONFIG_DVB_ISL6405) += isl6405.o
 obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+obj-$(CONFIG_DVB_TDA8261) += tda8261.o
 obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
 obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
 obj-$(CONFIG_DVB_AU8522) += au8522.o
 obj-$(CONFIG_DVB_TDA10048) += tda10048.o
+obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
 obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
 obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
 obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@@ -55,3 +63,5 @@ obj-$(CONFIG_DVB_CX24116) += cx24116.o
 obj-$(CONFIG_DVB_SI21XX) += si21xx.o
 obj-$(CONFIG_DVB_STV0288) += stv0288.o
 obj-$(CONFIG_DVB_STB6000) += stb6000.o
+obj-$(CONFIG_DVB_S921) += s921.o
+
index 692b68a9e73bd2f5af1bc465e6298e0dc218c630..b2b50fb4cfd338002102b868e87b0cac1032954a 100644 (file)
@@ -223,12 +223,12 @@ static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
        int ret = 0;
        u8 i = 0;
        u8 buf[24];
-       u32 ns_coeff1_2048nu;
-       u32 ns_coeff1_8191nu;
-       u32 ns_coeff1_8192nu;
-       u32 ns_coeff1_8193nu;
-       u32 ns_coeff2_2k;
-       u32 ns_coeff2_8k;
+       u32 uninitialized_var(ns_coeff1_2048nu);
+       u32 uninitialized_var(ns_coeff1_8191nu);
+       u32 uninitialized_var(ns_coeff1_8192nu);
+       u32 uninitialized_var(ns_coeff1_8193nu);
+       u32 uninitialized_var(ns_coeff2_2k);
+       u32 uninitialized_var(ns_coeff2_8k);
 
        deb_info("%s: adc_clock:%d bw:%d\n", __func__,
                state->config.adc_clock, bw);
@@ -1009,7 +1009,7 @@ static int af9013_update_snr(struct dvb_frontend *fe)
        int ret;
        u8 buf[3], i, len;
        u32 quant = 0;
-       struct snr_table *snr_table;
+       struct snr_table *uninitialized_var(snr_table);
 
        /* check if quantizer ready (for snr) */
        ret = af9013_read_reg_bits(state, 0xd2e1, 3, 1, &buf[0]);
diff --git a/drivers/media/dvb/frontends/cx24113.c b/drivers/media/dvb/frontends/cx24113.c
new file mode 100644 (file)
index 0000000..f6e7b03
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ *  Driver for Conexant CX24113/CX24128 Tuner (Satellite)
+ *
+ *  Copyright (C) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ *  Developed for BBTI / Technisat
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "dvb_frontend.h"
+#include "cx24113.h"
+
+static int debug;
+
+#define info(args...) do { printk(KERN_INFO "CX24113: " args); } while (0)
+#define err(args...)  do { printk(KERN_ERR  "CX24113: " args); } while (0)
+
+#define dprintk(args...) \
+       do { \
+               if (debug) { \
+                       printk(KERN_DEBUG "CX24113: %s: ", __func__); \
+                       printk(args); \
+               } \
+       } while (0)
+
+struct cx24113_state {
+       struct i2c_adapter *i2c;
+       const struct cx24113_config *config;
+
+#define REV_CX24113 0x23
+       u8 rev;
+       u8 ver;
+
+       u8 icp_mode:1;
+
+#define ICP_LEVEL1 0
+#define ICP_LEVEL2 1
+#define ICP_LEVEL3 2
+#define ICP_LEVEL4 3
+       u8 icp_man:2;
+       u8 icp_auto_low:2;
+       u8 icp_auto_mlow:2;
+       u8 icp_auto_mhi:2;
+       u8 icp_auto_hi:2;
+       u8 icp_dig;
+
+#define LNA_MIN_GAIN 0
+#define LNA_MID_GAIN 1
+#define LNA_MAX_GAIN 2
+       u8 lna_gain:2;
+
+       u8 acp_on:1;
+
+       u8 vco_mode:2;
+       u8 vco_shift:1;
+#define VCOBANDSEL_6 0x80
+#define VCOBANDSEL_5 0x01
+#define VCOBANDSEL_4 0x02
+#define VCOBANDSEL_3 0x04
+#define VCOBANDSEL_2 0x08
+#define VCOBANDSEL_1 0x10
+       u8 vco_band;
+
+#define VCODIV4 4
+#define VCODIV2 2
+       u8 vcodiv;
+
+       u8 bs_delay:4;
+       u16 bs_freqcnt:13;
+       u16 bs_rdiv;
+       u8 prescaler_mode:1;
+
+       u8 rfvga_bias_ctrl;
+
+       s16 tuner_gain_thres;
+       u8  gain_level;
+
+       u32 frequency;
+
+       u8 refdiv;
+
+       u8 Fwindow_enabled;
+};
+
+static int cx24113_writereg(struct cx24113_state *state, int reg, int data)
+{
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = state->config->i2c_addr,
+               .flags = 0, .buf = buf, .len = 2 };
+       int err = i2c_transfer(state->i2c, &msg, 1);
+       if (err != 1) {
+               printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x,"
+                        " data == 0x%02x)\n", __func__, err, reg, data);
+               return err;
+       }
+
+       return 0;
+}
+
+static int cx24113_readreg(struct cx24113_state *state, u8 reg)
+{
+       int ret;
+       u8 b;
+       struct i2c_msg msg[] = {
+               { .addr = state->config->i2c_addr,
+                       .flags = 0, .buf = &reg, .len = 1 },
+               { .addr = state->config->i2c_addr,
+                       .flags = I2C_M_RD, .buf = &b, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+
+       if (ret != 2) {
+               printk(KERN_DEBUG "%s: reg=0x%x (error=%d)\n",
+                       __func__, reg, ret);
+               return ret;
+       }
+
+       return b;
+}
+
+static void cx24113_set_parameters(struct cx24113_state *state)
+{
+       u8 r;
+
+       r = cx24113_readreg(state, 0x10) & 0x82;
+       r |= state->icp_mode;
+       r |= state->icp_man << 4;
+       r |= state->icp_dig << 2;
+       r |= state->prescaler_mode << 5;
+       cx24113_writereg(state, 0x10, r);
+
+       r = (state->icp_auto_low  << 0) | (state->icp_auto_mlow << 2)
+               | (state->icp_auto_mhi << 4) | (state->icp_auto_hi << 6);
+       cx24113_writereg(state, 0x11, r);
+
+       if (state->rev == REV_CX24113) {
+               r = cx24113_readreg(state, 0x20) & 0xec;
+               r |= state->lna_gain;
+               r |= state->rfvga_bias_ctrl << 4;
+               cx24113_writereg(state, 0x20, r);
+       }
+
+       r = cx24113_readreg(state, 0x12) & 0x03;
+       r |= state->acp_on << 2;
+       r |= state->bs_delay << 4;
+       cx24113_writereg(state, 0x12, r);
+
+       r = cx24113_readreg(state, 0x18) & 0x40;
+       r |= state->vco_shift;
+       if (state->vco_band == VCOBANDSEL_6)
+               r |= (1 << 7);
+       else
+               r |= (state->vco_band << 1);
+       cx24113_writereg(state, 0x18, r);
+
+       r  = cx24113_readreg(state, 0x14) & 0x20;
+       r |= (state->vco_mode << 6) | ((state->bs_freqcnt >> 8) & 0x1f);
+       cx24113_writereg(state, 0x14, r);
+       cx24113_writereg(state, 0x15, (state->bs_freqcnt        & 0xff));
+
+       cx24113_writereg(state, 0x16, (state->bs_rdiv >> 4) & 0xff);
+       r = (cx24113_readreg(state, 0x17) & 0x0f) |
+               ((state->bs_rdiv & 0x0f) << 4);
+       cx24113_writereg(state, 0x17, r);
+}
+
+#define VGA_0 0x00
+#define VGA_1 0x04
+#define VGA_2 0x02
+#define VGA_3 0x06
+#define VGA_4 0x01
+#define VGA_5 0x05
+#define VGA_6 0x03
+#define VGA_7 0x07
+
+#define RFVGA_0 0x00
+#define RFVGA_1 0x01
+#define RFVGA_2 0x02
+#define RFVGA_3 0x03
+
+static int cx24113_set_gain_settings(struct cx24113_state *state,
+               s16 power_estimation)
+{
+       u8 ampout = cx24113_readreg(state, 0x1d) & 0xf0,
+          vga    = cx24113_readreg(state, 0x1f) & 0x3f,
+          rfvga  = cx24113_readreg(state, 0x20) & 0xf3;
+       u8 gain_level = power_estimation >= state->tuner_gain_thres;
+
+       dprintk("power estimation: %d, thres: %d, gain_level: %d/%d\n",
+                       power_estimation, state->tuner_gain_thres,
+                       state->gain_level, gain_level);
+
+       if (gain_level == state->gain_level)
+               return 0; /* nothing to be done */
+
+       ampout |= 0xf;
+
+       if (gain_level) {
+               rfvga |= RFVGA_0 << 2;
+               vga   |= (VGA_7 << 3) | VGA_7;
+       } else {
+               rfvga |= RFVGA_2 << 2;
+               vga  |= (VGA_6 << 3) | VGA_2;
+       }
+       state->gain_level = gain_level;
+
+       cx24113_writereg(state, 0x1d, ampout);
+       cx24113_writereg(state, 0x1f, vga);
+       cx24113_writereg(state, 0x20, rfvga);
+
+       return 1; /* did something */
+}
+
+static int cx24113_set_Fref(struct cx24113_state *state, u8 high)
+{
+       u8 xtal = cx24113_readreg(state, 0x02);
+       if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+               high = 1;
+
+       xtal &= ~0x2;
+       if (high)
+               xtal |= high << 1;
+       return cx24113_writereg(state, 0x02, xtal);
+}
+
+static int cx24113_enable(struct cx24113_state *state, u8 enable)
+{
+       u8 r21 = (cx24113_readreg(state, 0x21) & 0xc0) | enable;
+       if (state->rev == REV_CX24113)
+               r21 |= (1 << 1);
+       return cx24113_writereg(state, 0x21, r21);
+}
+
+static int cx24113_set_bandwidth(struct cx24113_state *state, u32 bandwidth_khz)
+{
+       u8 r;
+
+       if (bandwidth_khz <= 19000)
+               r = 0x03 << 6;
+       else if (bandwidth_khz <= 25000)
+               r = 0x02 << 6;
+       else
+               r = 0x01 << 6;
+
+       dprintk("bandwidth to be set: %d\n", bandwidth_khz);
+       bandwidth_khz *= 10;
+       bandwidth_khz -= 10000;
+       bandwidth_khz /= 1000;
+       bandwidth_khz += 5;
+       bandwidth_khz /= 10;
+
+       dprintk("bandwidth: %d %d\n", r >> 6, bandwidth_khz);
+
+       r |= bandwidth_khz & 0x3f;
+
+       return cx24113_writereg(state, 0x1e, r);
+}
+
+static int cx24113_set_clk_inversion(struct cx24113_state *state, u8 on)
+{
+       u8 r = (cx24113_readreg(state, 0x10) & 0x7f) | ((on & 0x1) << 7);
+       return cx24113_writereg(state, 0x10, r);
+}
+
+static int cx24113_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       u8 r = (cx24113_readreg(state, 0x10) & 0x02) >> 1;
+       if (r)
+               *status |= TUNER_STATUS_LOCKED;
+       dprintk("PLL locked: %d\n", r);
+       return 0;
+}
+
+static u8 cx24113_set_ref_div(struct cx24113_state *state, u8 refdiv)
+{
+       if (state->rev == 0x43 && state->vcodiv == VCODIV4)
+               refdiv = 2;
+       return state->refdiv = refdiv;
+}
+
+static void cx24113_calc_pll_nf(struct cx24113_state *state, u16 *n, s32 *f)
+{
+       s32 N;
+       s64 F;
+       u8 R, r;
+       u8 vcodiv;
+       u8 factor;
+       s32 freq_hz = state->frequency * 1000;
+
+       if (state->config->xtal_khz < 20000)
+               factor = 1;
+       else
+               factor = 2;
+
+       if (state->rev == REV_CX24113) {
+               if (state->frequency >= 1100000)
+                       vcodiv = VCODIV2;
+               else
+                       vcodiv = VCODIV4;
+       } else {
+               if (state->frequency >= 1165000)
+                       vcodiv = VCODIV2;
+               else
+                       vcodiv = VCODIV4;
+       }
+       state->vcodiv = vcodiv;
+
+       dprintk("calculating N/F for %dHz with vcodiv %d\n", freq_hz, vcodiv);
+       R = 0;
+       do {
+               R = cx24113_set_ref_div(state, R + 1);
+
+               /* calculate tuner PLL settings: */
+               N =  (freq_hz / 100 * vcodiv) * R;
+               N /= (state->config->xtal_khz) * factor * 2;
+               N += 5;     /* For round up. */
+               N /= 10;
+               N -= 32;
+       } while (N < 6 && R < 3);
+
+       if (N < 6) {
+               err("strange frequency: N < 6\n");
+               return;
+       }
+       F = freq_hz;
+       F *= (u64) (R * vcodiv * 262144);
+       dprintk("1 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+       do_div(F, state->config->xtal_khz*1000 * factor * 2);
+       dprintk("2 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+       F -= (N + 32) * 262144;
+
+       dprintk("3 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+       if (state->Fwindow_enabled) {
+               if (F > (262144 / 2 - 1638))
+                       F = 262144 / 2 - 1638;
+               if (F < (-262144 / 2 + 1638))
+                       F = -262144 / 2 + 1638;
+               if ((F < 3277 && F > 0) || (F > -3277 && F < 0)) {
+                       F = 0;
+                       r = cx24113_readreg(state, 0x10);
+                       cx24113_writereg(state, 0x10, r | (1 << 6));
+               }
+       }
+       dprintk("4 N: %d, F: %lld, R: %d\n", N, (long long)F, R);
+
+       *n = (u16) N;
+       *f = (s32) F;
+}
+
+
+static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r)
+{
+       u8 reg;
+       cx24113_writereg(state, 0x19, (n >> 1) & 0xff);
+
+       reg = ((n & 0x1) << 7) | ((f >> 11) & 0x7f);
+       cx24113_writereg(state, 0x1a, reg);
+
+       cx24113_writereg(state, 0x1b, (f >> 3) & 0xff);
+
+       reg = cx24113_readreg(state, 0x1c) & 0x1f;
+       cx24113_writereg(state, 0x1c, reg | ((f & 0x7) << 5));
+
+       cx24113_set_Fref(state, r - 1);
+}
+
+static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency)
+{
+       u8 r = 1; /* or 2 */
+       u16 n = 6;
+       s32 f = 0;
+
+       r = cx24113_readreg(state, 0x14);
+       cx24113_writereg(state, 0x14, r & 0x3f);
+
+       r = cx24113_readreg(state, 0x10);
+       cx24113_writereg(state, 0x10, r & 0xbf);
+
+       state->frequency = frequency;
+
+       dprintk("tuning to frequency: %d\n", frequency);
+
+       cx24113_calc_pll_nf(state, &n, &f);
+       cx24113_set_nfr(state, n, f, state->refdiv);
+
+       r = cx24113_readreg(state, 0x18) & 0xbf;
+       if (state->vcodiv != VCODIV2)
+               r |= 1 << 6;
+       cx24113_writereg(state, 0x18, r);
+
+       /* The need for this sleep is not clear. But helps in some cases */
+       msleep(5);
+
+       r = cx24113_readreg(state, 0x1c) & 0xef;
+       cx24113_writereg(state, 0x1c, r | (1 << 4));
+       return 0;
+}
+
+static int cx24113_init(struct dvb_frontend *fe)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       int ret;
+
+       state->tuner_gain_thres = -50;
+       state->gain_level = 255; /* to force a gain-setting initialization */
+       state->icp_mode = 0;
+
+       if (state->config->xtal_khz < 11000) {
+               state->icp_auto_hi  = ICP_LEVEL4;
+               state->icp_auto_mhi  = ICP_LEVEL4;
+               state->icp_auto_mlow = ICP_LEVEL3;
+               state->icp_auto_low = ICP_LEVEL3;
+       } else {
+               state->icp_auto_hi  = ICP_LEVEL4;
+               state->icp_auto_mhi  = ICP_LEVEL4;
+               state->icp_auto_mlow = ICP_LEVEL3;
+               state->icp_auto_low = ICP_LEVEL2;
+       }
+
+       state->icp_dig = ICP_LEVEL3;
+       state->icp_man = ICP_LEVEL1;
+       state->acp_on  = 1;
+       state->vco_mode = 0;
+       state->vco_shift = 0;
+       state->vco_band = VCOBANDSEL_1;
+       state->bs_delay = 8;
+       state->bs_freqcnt = 0x0fff;
+       state->bs_rdiv = 0x0fff;
+       state->prescaler_mode = 0;
+       state->lna_gain = LNA_MAX_GAIN;
+       state->rfvga_bias_ctrl = 1;
+       state->Fwindow_enabled = 1;
+
+       cx24113_set_Fref(state, 0);
+       cx24113_enable(state, 0x3d);
+       cx24113_set_parameters(state);
+
+       cx24113_set_gain_settings(state, -30);
+
+       cx24113_set_bandwidth(state, 18025);
+       cx24113_set_clk_inversion(state, 1);
+
+       if (state->config->xtal_khz >= 40000)
+               ret = cx24113_writereg(state, 0x02,
+                       (cx24113_readreg(state, 0x02) & 0xfb) | (1 << 2));
+       else
+               ret = cx24113_writereg(state, 0x02,
+                       (cx24113_readreg(state, 0x02) & 0xfb) | (0 << 2));
+
+       return ret;
+}
+
+static int cx24113_set_params(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *p)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       /* for a ROLL-OFF factor of 0.35, 0.2: 600, 0.25: 625 */
+       u32 roll_off = 675;
+       u32 bw;
+
+       bw  = ((p->u.qpsk.symbol_rate/100) * roll_off) / 1000;
+       bw += (10000000/100) + 5;
+       bw /= 10;
+       bw += 1000;
+       cx24113_set_bandwidth(state, bw);
+
+       cx24113_set_frequency(state, p->frequency);
+       msleep(5);
+       return cx24113_get_status(fe, &bw);
+}
+
+static s8 cx24113_agc_table[2][10] = {
+       {-54, -41, -35, -30, -25, -21, -16, -10,  -6,  -2},
+       {-39, -35, -30, -25, -19, -15, -11,  -5,   1,   9},
+};
+
+void cx24113_agc_callback(struct dvb_frontend *fe)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       s16 s, i;
+       if (!fe->ops.read_signal_strength)
+               return;
+
+       do {
+               /* this only works with the current CX24123 implementation */
+               fe->ops.read_signal_strength(fe, (u16 *) &s);
+               s >>= 8;
+               dprintk("signal strength: %d\n", s);
+               for (i = 0; i < sizeof(cx24113_agc_table[0]); i++)
+                       if (cx24113_agc_table[state->gain_level][i] > s)
+                               break;
+               s = -25 - i*5;
+       } while (cx24113_set_gain_settings(state, s));
+}
+EXPORT_SYMBOL(cx24113_agc_callback);
+
+static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       *frequency = state->frequency;
+       return 0;
+}
+
+static int cx24113_release(struct dvb_frontend *fe)
+{
+       struct cx24113_state *state = fe->tuner_priv;
+       dprintk("\n");
+       fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+static const struct dvb_tuner_ops cx24113_tuner_ops = {
+       .info = {
+               .name           = "Conexant CX24113",
+               .frequency_min  = 950000,
+               .frequency_max  = 2150000,
+               .frequency_step = 125,
+       },
+
+       .release       = cx24113_release,
+
+       .init          = cx24113_init,
+       .sleep         = NULL,
+
+       .set_params    = cx24113_set_params,
+       .get_frequency = cx24113_get_frequency,
+       .get_bandwidth = NULL,
+       .get_status    = cx24113_get_status,
+};
+
+struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
+               const struct cx24113_config *config, struct i2c_adapter *i2c)
+{
+       /* allocate memory for the internal state */
+       struct cx24113_state *state =
+               kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
+       int rc;
+       if (state == NULL) {
+               err("Unable to kmalloc\n");
+               goto error;
+       }
+
+       /* setup the state */
+       state->config = config;
+       state->i2c = i2c;
+
+       info("trying to detect myself\n");
+
+       /* making a dummy read, because of some expected troubles
+        * after power on */
+       cx24113_readreg(state, 0x00);
+
+       rc = cx24113_readreg(state, 0x00);
+       if (rc < 0) {
+               info("CX24113 not found.\n");
+               goto error;
+       }
+       state->rev = rc;
+
+       switch (rc) {
+       case 0x43:
+               info("detected CX24113 variant\n");
+               break;
+       case REV_CX24113:
+               info("sucessfully detected\n");
+               break;
+       default:
+               err("unsupported device id: %x\n", state->rev);
+               goto error;
+       }
+       state->ver = cx24113_readreg(state, 0x01);
+       info("version: %x\n", state->ver);
+
+       /* create dvb_frontend */
+       memcpy(&fe->ops.tuner_ops, &cx24113_tuner_ops,
+                       sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = state;
+       return fe;
+
+error:
+       kfree(state);
+
+       return NULL;
+}
+EXPORT_SYMBOL(cx24113_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant CX24113/CX24128hardware");
+MODULE_LICENSE("GPL");
+
index 5ab3dd11076bd7ebe6824c8136e7f9c8b689db08..5de0f7ffd8d2491014a14c09f6d6daa5b62a76db 100644 (file)
@@ -16,7 +16,7 @@
  *
  *  You 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.=
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef CX24113_H
@@ -30,9 +30,13 @@ struct cx24113_config {
        u32 xtal_khz;
 };
 
-/* TODO: #if defined(CONFIG_DVB_TUNER_CX24113) || \
- * (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) */
+#if defined(CONFIG_DVB_TUNER_CX24113) || \
+       (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
+       const struct cx24113_config *config, struct i2c_adapter *i2c);
 
+extern void cx24113_agc_callback(struct dvb_frontend *fe);
+#else
 static inline struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
        const struct cx24113_config *config, struct i2c_adapter *i2c)
 {
@@ -44,5 +48,6 @@ static inline void cx24113_agc_callback(struct dvb_frontend *fe)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
 }
+#endif
 
 #endif /* CX24113_H */
index b144b308a4dd336854226eb1c5ef2484b598b0c2..9b6c89e93f1696570c7bc7194d6deb04a5b21846 100644 (file)
@@ -106,7 +106,7 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
 #define CX24116_HAS_SYNCLOCK (0x08)
 #define CX24116_HAS_UNKNOWN1 (0x10)
 #define CX24116_HAS_UNKNOWN2 (0x20)
-#define CX24116_STATUS_MASK  (0x3f)
+#define CX24116_STATUS_MASK  (0x0f)
 #define CX24116_SIGNAL_MASK  (0xc0)
 
 #define CX24116_DISEQC_TONEOFF   (0)    /* toneburst never sent */
@@ -160,6 +160,7 @@ struct cx24116_tuning {
        fe_spectral_inversion_t inversion;
        fe_code_rate_t fec;
 
+       fe_delivery_system_t delsys;
        fe_modulation_t modulation;
        fe_pilot_t pilot;
        fe_rolloff_t rolloff;
@@ -411,14 +412,15 @@ struct cx24116_modfec {
 };
 
 static int cx24116_lookup_fecmod(struct cx24116_state *state,
-       fe_modulation_t m, fe_code_rate_t f)
+       fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
 {
        int i, ret = -EOPNOTSUPP;
 
        dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
 
        for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
-               if ((m == CX24116_MODFEC_MODES[i].modulation) &&
+               if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
+                       (m == CX24116_MODFEC_MODES[i].modulation) &&
                        (f == CX24116_MODFEC_MODES[i].fec)) {
                                ret = i;
                                break;
@@ -429,13 +431,13 @@ static int cx24116_lookup_fecmod(struct cx24116_state *state,
 }
 
 static int cx24116_set_fec(struct cx24116_state *state,
-       fe_modulation_t mod, fe_code_rate_t fec)
+       fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
 {
        int ret = 0;
 
        dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
 
-       ret = cx24116_lookup_fecmod(state, mod, fec);
+       ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
 
        if (ret < 0)
                return ret;
@@ -679,7 +681,8 @@ static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
 {
        struct cx24116_state *state = fe->demodulator_priv;
 
-       int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
+       int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
+               CX24116_STATUS_MASK;
 
        dprintk("%s: status = 0x%02x\n", __func__, lock);
 
@@ -1205,7 +1208,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct cx24116_cmd cmd;
        fe_status_t tunerstat;
-       int i, status, ret, retune;
+       int i, status, ret, retune = 1;
 
        dprintk("%s()\n", __func__);
 
@@ -1222,7 +1225,6 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
 
                /* Pilot doesn't exist in DVB-S, turn bit off */
                state->dnxt.pilot_val = CX24116_PILOT_OFF;
-               retune = 1;
 
                /* DVB-S only supports 0.35 */
                if (c->rolloff != ROLLOFF_35) {
@@ -1250,7 +1252,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
                case PILOT_AUTO:        /* Not supported but emulated */
                        state->dnxt.pilot_val = (c->modulation == QPSK)
                                ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
-                       retune = 2;
+                       retune++;
                        break;
                case PILOT_OFF:
                        state->dnxt.pilot_val = CX24116_PILOT_OFF;
@@ -1287,6 +1289,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
                        __func__, c->delivery_system);
                return -EOPNOTSUPP;
        }
+       state->dnxt.delsys = c->delivery_system;
        state->dnxt.modulation = c->modulation;
        state->dnxt.frequency = c->frequency;
        state->dnxt.pilot = c->pilot;
@@ -1297,7 +1300,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
                return ret;
 
        /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
-       ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
+       ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
        if (ret !=  0)
                return ret;
 
@@ -1308,6 +1311,7 @@ static int cx24116_set_frontend(struct dvb_frontend *fe,
        /* discard the 'current' tuning parameters and prepare to tune */
        cx24116_clone_params(fe);
 
+       dprintk("%s:   delsys      = %d\n", __func__, state->dcur.delsys);
        dprintk("%s:   modulation  = %d\n", __func__, state->dcur.modulation);
        dprintk("%s:   frequency   = %d\n", __func__, state->dcur.frequency);
        dprintk("%s:   pilot       = %d (val = 0x%02x)\n", __func__,
@@ -1427,6 +1431,23 @@ tuned:  /* Set/Reset B/W */
        return ret;
 }
 
+static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
+       unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
+{
+       *delay = HZ / 5;
+       if (params) {
+               int ret = cx24116_set_frontend(fe, params);
+               if (ret)
+                       return ret;
+       }
+       return cx24116_read_status(fe, status);
+}
+
+static int cx24116_get_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_HW;
+}
+
 static struct dvb_frontend_ops cx24116_ops = {
 
        .info = {
@@ -1458,6 +1479,8 @@ static struct dvb_frontend_ops cx24116_ops = {
        .set_voltage = cx24116_set_voltage,
        .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
        .diseqc_send_burst = cx24116_diseqc_send_burst,
+       .get_frontend_algo = cx24116_get_algo,
+       .tune = cx24116_tune,
 
        .set_property = cx24116_set_property,
        .get_property = cx24116_get_property,
index 3e81268571276f895e2c1d6075d2ba44209953f7..aab8112e2db20f6658c66c0c83cee0e9ae6fd4f7 100644 (file)
@@ -66,7 +66,8 @@ struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe,
        return NULL;
 }
 
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
+static inline
+int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
                                    int no_of_demods, u8 default_addr,
                                    struct dib7000p_config cfg[])
 {
@@ -74,13 +75,15 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
        return -ENODEV;
 }
 
-extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static inline
+int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
 }
 
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static inline
+int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
 {
        printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
        return -ENODEV;
index b9ca5c8d2dd9400814f64566a24952b541126a0a..ec4e08dbc699c78a31432a470d1292d1261ca312 100644 (file)
@@ -39,7 +39,7 @@ static const char mod_name[] = "drx397xD";
 #define F_SET_0D4h     2
 
 enum fw_ix {
-#define _FW_ENTRY(a, b)                b
+#define _FW_ENTRY(a, b, c)     b
 #include "drx397xD_fw.h"
 };
 
@@ -72,11 +72,11 @@ static struct {
        int refcnt;
        const u8 *data[ARRAY_SIZE(blob_name)];
 } fw[] = {
-#define _FW_ENTRY(a, b)                {                       \
-                       .name   = a,                    \
-                       .file   = 0,                    \
-                       .lock   = RW_LOCK_UNLOCKED,     \
-                       .refcnt = 0,                    \
+#define _FW_ENTRY(a, b, c)     {                                       \
+                       .name   = a,                                    \
+                       .file   = 0,                                    \
+                       .lock   = __RW_LOCK_UNLOCKED(fw[c].lock),       \
+                       .refcnt = 0,                                    \
                        .data   = { }           }
 #include "drx397xD_fw.h"
 };
index 01de02a81cd41ea27f30405d8a33119eaf1450d4..c8b44c1e807f892866f0c3e3cdb2963dee576422 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 #ifdef _FW_ENTRY
-       _FW_ENTRY("drx397xD.A2.fw",     DRXD_FW_A2 = 0          ),
-       _FW_ENTRY("drx397xD.B1.fw",     DRXD_FW_B1              ),
+       _FW_ENTRY("drx397xD.A2.fw",     DRXD_FW_A2 = 0, DRXD_FW_A2      ),
+       _FW_ENTRY("drx397xD.B1.fw",     DRXD_FW_B1,     DRXD_FW_B1      ),
 #undef _FW_ENTRY
 #endif /* _FW_ENTRY */
 
index ea058153ebfa3dfd8e88660662fd7e4fa3f9ee50..9f6349964cdafa53b49525b494e4c7066e4ed903 100644 (file)
@@ -311,7 +311,7 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
        .count = 4,
        .entries = {
                { 1250000, 500, 0xc4, 0x00},
-               { 1550000, 500, 0xc4, 0x40},
+               { 1450000, 500, 0xc4, 0x40},
                { 2050000, 500, 0xc4, 0x80},
                { 2150000, 500, 0xc4, 0xc0},
        },
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
new file mode 100644 (file)
index 0000000..469ace5
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Driver for LG ATSC lgdt3304 driver
+ *
+ * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "lgdt3304.h"
+
+static  unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
+
+#define dprintk(fmt, args...) if (debug) do {\
+                       printk("lgdt3304 debug: " fmt, ##args); } while (0)
+
+struct lgdt3304_state
+{
+       struct dvb_frontend frontend;
+       fe_modulation_t current_modulation;
+       __u32 snr;
+       __u32 current_frequency;
+       __u8 addr;
+       struct i2c_adapter *i2c;
+};
+
+static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       struct i2c_msg i2cmsgs = {
+               .addr = state->addr,
+               .flags = 0,
+               .len = 3,
+               .buf = buf
+       };
+       int i;
+       int err;
+
+       for (i=0; i<len-1; i+=3){
+               if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
+                       printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
+                       if (err < 0)
+                               return err;
+                       else
+                               return -EREMOTEIO;
+               }
+               i2cmsgs.buf += 3;
+       }
+       return 0;
+}
+
+static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       struct i2c_msg i2cmsgs[2];
+       int ret;
+       __u8 buf;
+
+       __u8 regbuf[2] = { reg>>8, reg&0xff };
+
+       i2cmsgs[0].addr = state->addr;
+       i2cmsgs[0].flags = 0;
+       i2cmsgs[0].len = 2;
+       i2cmsgs[0].buf = regbuf;
+
+       i2cmsgs[1].addr = state->addr;
+       i2cmsgs[1].flags = I2C_M_RD;
+       i2cmsgs[1].len = 1;
+       i2cmsgs[1].buf = &buf;
+
+       if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
+               printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+               return ret;
+       }
+
+       return buf;
+}
+
+static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       char buffer[3] = { reg>>8, reg&0xff, val };
+       int ret;
+
+       struct i2c_msg i2cmsgs = {
+               .addr = state->addr,
+               .flags = 0,
+               .len = 3,
+               .buf=buffer
+       };
+       ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
+       if (ret != 1) {
+               printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+
+static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
+{
+       lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
+       lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
+       mdelay(200);
+       return 0;
+}
+
+static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
+       int err = 0;
+
+       static __u8 lgdt3304_vsb8_data[] = {
+               /* 16bit  , 8bit */
+               /* regs   , val  */
+               0x00, 0x00, 0x02,
+               0x00, 0x00, 0x13,
+               0x00, 0x0d, 0x02,
+               0x00, 0x0e, 0x02,
+               0x00, 0x12, 0x32,
+               0x00, 0x13, 0xc4,
+               0x01, 0x12, 0x17,
+               0x01, 0x13, 0x15,
+               0x01, 0x14, 0x18,
+               0x01, 0x15, 0xff,
+               0x01, 0x16, 0x2c,
+               0x02, 0x14, 0x67,
+               0x02, 0x24, 0x8d,
+               0x04, 0x27, 0x12,
+               0x04, 0x28, 0x4f,
+               0x03, 0x08, 0x80,
+               0x03, 0x09, 0x00,
+               0x03, 0x0d, 0x00,
+               0x03, 0x0e, 0x1c,
+               0x03, 0x14, 0xe1,
+               0x05, 0x0e, 0x5b,
+       };
+
+       /* not yet tested .. */
+       static __u8 lgdt3304_qam64_data[] = {
+               /* 16bit  , 8bit */
+               /* regs   , val  */
+               0x00, 0x00, 0x18,
+               0x00, 0x0d, 0x02,
+               //0x00, 0x0e, 0x02,
+               0x00, 0x12, 0x2a,
+               0x00, 0x13, 0x00,
+               0x03, 0x14, 0xe3,
+               0x03, 0x0e, 0x1c,
+               0x03, 0x08, 0x66,
+               0x03, 0x09, 0x66,
+               0x03, 0x0a, 0x08,
+               0x03, 0x0b, 0x9b,
+               0x05, 0x0e, 0x5b,
+       };
+
+
+       /* tested with KWorld a340 */
+       static __u8 lgdt3304_qam256_data[] = {
+               /* 16bit  , 8bit */
+               /* regs   , val  */
+               0x00, 0x00, 0x01,  //0x19,
+               0x00, 0x12, 0x2a,
+               0x00, 0x13, 0x80,
+               0x00, 0x0d, 0x02,
+               0x03, 0x14, 0xe3,
+
+               0x03, 0x0e, 0x1c,
+               0x03, 0x08, 0x66,
+               0x03, 0x09, 0x66,
+               0x03, 0x0a, 0x08,
+               0x03, 0x0b, 0x9b,
+
+               0x03, 0x0d, 0x14,
+               //0x05, 0x0e, 0x5b,
+               0x01, 0x06, 0x4a,
+               0x01, 0x07, 0x3d,
+               0x01, 0x08, 0x70,
+               0x01, 0x09, 0xa3,
+
+               0x05, 0x04, 0xfd,
+
+               0x00, 0x0d, 0x82,
+
+               0x05, 0x0e, 0x5b,
+
+               0x05, 0x0e, 0x5b,
+
+               0x00, 0x02, 0x9a,
+
+               0x00, 0x02, 0x9b,
+
+               0x00, 0x00, 0x01,
+               0x00, 0x12, 0x2a,
+               0x00, 0x13, 0x80,
+               0x00, 0x0d, 0x02,
+               0x03, 0x14, 0xe3,
+
+               0x03, 0x0e, 0x1c,
+               0x03, 0x08, 0x66,
+               0x03, 0x09, 0x66,
+               0x03, 0x0a, 0x08,
+               0x03, 0x0b, 0x9b,
+
+               0x03, 0x0d, 0x14,
+               0x01, 0x06, 0x4a,
+               0x01, 0x07, 0x3d,
+               0x01, 0x08, 0x70,
+               0x01, 0x09, 0xa3,
+
+               0x05, 0x04, 0xfd,
+
+               0x00, 0x0d, 0x82,
+
+               0x05, 0x0e, 0x5b,
+       };
+
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       if (state->current_modulation != param->u.vsb.modulation) {
+               switch(param->u.vsb.modulation) {
+               case VSB_8:
+                       err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
+                                       sizeof(lgdt3304_vsb8_data));
+                       break;
+               case QAM_64:
+                       err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
+                                       sizeof(lgdt3304_qam64_data));
+                       break;
+               case QAM_256:
+                       err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
+                                       sizeof(lgdt3304_qam256_data));
+                       break;
+               default:
+                       break;
+               }
+
+               if (err) {
+                       printk("%s error setting modulation\n", __FUNCTION__);
+               } else {
+                       state->current_modulation = param->u.vsb.modulation;
+               }
+       }
+       state->current_frequency = param->frequency;
+
+       lgdt3304_soft_Reset(fe);
+
+
+       if (fe->ops.tuner_ops.set_params)
+               fe->ops.tuner_ops.set_params(fe, param);
+
+       return 0;
+}
+
+static int lgdt3304_init(struct dvb_frontend *fe) {
+       return 0;
+}
+
+static int lgdt3304_sleep(struct dvb_frontend *fe) {
+       return 0;
+}
+
+
+static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct lgdt3304_state *state = fe->demodulator_priv;
+       int r011d;
+       int qam_lck;
+
+       *status = 0;
+       dprintk("lgdt read status\n");
+
+       r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
+
+       dprintk("%02x\n", r011d);
+
+       switch(state->current_modulation) {
+       case VSB_8:
+               if (r011d & 0x80) {
+                       dprintk("VSB Locked\n");
+                       *status |= FE_HAS_CARRIER;
+                       *status |= FE_HAS_LOCK;
+                       *status |= FE_HAS_SYNC;
+                       *status |= FE_HAS_SIGNAL;
+               }
+               break;
+       case QAM_64:
+       case QAM_256:
+               qam_lck = r011d & 0x7;
+               switch(qam_lck) {
+                       case 0x0: dprintk("Unlock\n");
+                                 break;
+                       case 0x4: dprintk("1st Lock in acquisition state\n");
+                                 break;
+                       case 0x6: dprintk("2nd Lock in acquisition state\n");
+                                 break;
+                       case 0x7: dprintk("Final Lock in good reception state\n");
+                                 *status |= FE_HAS_CARRIER;
+                                 *status |= FE_HAS_LOCK;
+                                 *status |= FE_HAS_SYNC;
+                                 *status |= FE_HAS_SIGNAL;
+                                 break;
+               }
+               break;
+       default:
+               printk("%s unhandled modulation\n", __FUNCTION__);
+       }
+
+
+       return 0;
+}
+
+static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
+{
+       dprintk("read ber\n");
+       return 0;
+}
+
+static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
+{
+       dprintk("read snr\n");
+       return 0;
+}
+
+static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
+{
+       dprintk("read ucblocks\n");
+       return 0;
+}
+
+static void lgdt3304_release(struct dvb_frontend *fe)
+{
+       struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops demod_lgdt3304={
+       .info = {
+               .name = "LG 3304",
+               .type = FE_ATSC,
+               .frequency_min = 54000000,
+               .frequency_max = 858000000,
+               .frequency_stepsize = 62500,
+               .symbol_rate_min = 5056941,
+               .symbol_rate_max = 10762000,
+               .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+       },
+       .init = lgdt3304_init,
+       .sleep = lgdt3304_sleep,
+       .set_frontend = lgdt3304_set_parameters,
+       .read_snr = lgdt3304_read_snr,
+       .read_ber = lgdt3304_read_ber,
+       .read_status = lgdt3304_read_status,
+       .read_ucblocks = lgdt3304_read_ucblocks,
+       .release = lgdt3304_release,
+};
+
+struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+                                          struct i2c_adapter *i2c)
+{
+
+       struct lgdt3304_state *state;
+       state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
+       memset(state, 0x0, sizeof(struct lgdt3304_state));
+       state->addr = config->i2c_address;
+       state->i2c = i2c;
+
+       memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+}
+
+EXPORT_SYMBOL_GPL(lgdt3304_attach);
+MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
+MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgdt3304.h b/drivers/media/dvb/frontends/lgdt3304.h
new file mode 100644 (file)
index 0000000..fc409fe
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  Driver for DVB-T lgdt3304 demodulator
+ *
+ *  Copyright (C) 2008 Markus Rechberger <mrechberger@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.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You 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 LGDT3304_H
+#define LGDT3304_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgdt3304_config
+{
+       /* demodulator's I2C address */
+       u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
+extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
+                                          struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_LGDT */
+
+#endif /* LGDT3304_H */
index 40644aacffcb218dbbee77ee8a8b80e15b2b0164..66e2dd6d6fe4eb725b21f203b21e180081c8ef45 100644 (file)
@@ -874,6 +874,9 @@ struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
        /* Note: Leaving the I2C gate open here. */
        s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0xf5, 1);
 
+       /* Put the device into low-power mode until first use */
+       s5h1411_set_powerstate(&state->frontend, 1);
+
        return &state->frontend;
 
 error:
diff --git a/drivers/media/dvb/frontends/s921_core.c b/drivers/media/dvb/frontends/s921_core.c
new file mode 100644 (file)
index 0000000..974b52b
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Driver for Sharp s921 driver
+ *
+ * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "s921_core.h"
+
+static int s921_isdb_init(struct s921_isdb_t *dev);
+static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params);
+static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params);
+static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data);
+
+static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01,
+                        0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
+                        0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00,
+                        0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80,
+                        0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12,
+                        0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00,
+                        0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff,
+                        0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00,
+                        0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88,
+                        0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00,
+                        0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06,
+                        0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00,
+                        0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00,
+                        0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20,
+                        0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70,
+                        0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f,
+                        0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00,
+                        0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00,
+                        0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30,
+                        0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d,
+                        0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f,
+                        0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00,
+                        0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84,
+                        0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e,
+                        0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba,
+                        0xf8, 0xd7 };
+
+static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b,
+                     0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b,
+                     0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b,
+                     0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b,
+                     0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b,
+                     0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b,
+                     0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b,
+                     0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb,
+                     0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb,
+                     0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb,
+                     0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb,
+                     0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb,
+                     0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb,
+                     0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b,
+                     0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b,
+                     0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b,
+                     0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b };
+
+int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) {
+       switch(cmd) {
+       case ISDB_T_CMD_INIT:
+               s921_isdb_init(dev);
+               break;
+       case ISDB_T_CMD_SET_PARAM:
+               s921_isdb_set_parameters(dev, data);
+               break;
+       case ISDB_T_CMD_TUNE:
+               s921_isdb_tune(dev, data);
+               break;
+       case ISDB_T_CMD_GET_STATUS:
+               s921_isdb_get_status(dev, data);
+               break;
+       default:
+               printk("unhandled command\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int s921_isdb_init(struct s921_isdb_t *dev) {
+       unsigned int i;
+       unsigned int ret;
+       printk("isdb_init\n");
+       for (i = 0; i < sizeof(init_table); i+=2) {
+               ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]);
+               if (ret != 0) {
+                       printk("i2c write failed\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) {
+
+       int ret;
+       /* auto is sufficient for now, lateron this should be reflected in an extra interface */
+
+
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2);
+       ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2);
+
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7);
+       if (ret < 0)
+               return -EINVAL;
+
+       return E_OK;
+}
+
+static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) {
+
+       int ret;
+       int index;
+
+       index = (params->frequency - 473143000)/6000000;
+
+       if (index > 48) {
+               return -EINVAL;
+       }
+
+       dev->i2c_write(dev->priv_dev, 0x47, 0x60);
+
+       ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a);
+       if (ret < 0)
+               return -EINVAL;
+
+       ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09);
+       if (ret < 0)
+               return -EINVAL;
+
+       dev->i2c_write(dev->priv_dev, 0x01, 0x40);
+       return 0;
+}
+
+static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) {
+       unsigned int *ret = (unsigned int*)data;
+       u8 ifagc_dt;
+       u8 rfagc_dt;
+
+       mdelay(10);
+       ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81);
+       rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82);
+       if (rfagc_dt == 0x40) {
+               *ret = 1;
+       }
+       return 0;
+}
diff --git a/drivers/media/dvb/frontends/s921_core.h b/drivers/media/dvb/frontends/s921_core.h
new file mode 100644 (file)
index 0000000..de2f10a
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef _S921_CORE_H
+#define _S921_CORE_H
+//#define u8 unsigned int
+//#define u32 unsigned int
+
+
+
+//#define EINVAL -1
+#define E_OK 0
+
+struct s921_isdb_t {
+       void *priv_dev;
+       int (*i2c_write)(void *dev, u8 reg, u8 val);
+       int (*i2c_read)(void *dev, u8 reg);
+};
+
+#define ISDB_T_CMD_INIT       0
+#define ISDB_T_CMD_SET_PARAM  1
+#define ISDB_T_CMD_TUNE       2
+#define ISDB_T_CMD_GET_STATUS 3
+
+struct s921_isdb_t_tune_params {
+       u32 frequency;
+};
+
+struct s921_isdb_t_status {
+};
+
+struct s921_isdb_t_transmission_mode_params {
+       u8 mode;
+       u8 layer_a_mode;
+#define ISDB_T_LA_MODE_1 0
+#define ISDB_T_LA_MODE_2 1
+#define ISDB_T_LA_MODE_3 2
+       u8 layer_a_carrier_modulation;
+#define ISDB_T_LA_CM_DQPSK 0
+#define ISDB_T_LA_CM_QPSK  1
+#define ISDB_T_LA_CM_16QAM 2
+#define ISDB_T_LA_CM_64QAM 3
+#define ISDB_T_LA_CM_NOLAYER 4
+       u8 layer_a_code_rate;
+#define ISDB_T_LA_CR_1_2   0
+#define ISDB_T_LA_CR_2_3   1
+#define ISDB_T_LA_CR_3_4   2
+#define ISDB_T_LA_CR_5_6   4
+#define ISDB_T_LA_CR_7_8   8
+#define ISDB_T_LA_CR_NOLAYER   16
+       u8 layer_a_time_interleave;
+#define ISDB_T_LA_TI_0  0
+#define ISDB_T_LA_TI_1  1
+#define ISDB_T_LA_TI_2  2
+#define ISDB_T_LA_TI_4  4
+#define ISDB_T_LA_TI_8  8
+#define ISDB_T_LA_TI_16 16
+#define ISDB_T_LA_TI_32 32
+       u8 layer_a_nseg;
+
+       u8 layer_b_mode;
+#define ISDB_T_LB_MODE_1 0
+#define ISDB_T_LB_MODE_2 1
+#define ISDB_T_LB_MODE_3 2
+       u8 layer_b_carrier_modulation;
+#define ISDB_T_LB_CM_DQPSK 0
+#define ISDB_T_LB_CM_QPSK  1
+#define ISDB_T_LB_CM_16QAM 2
+#define ISDB_T_LB_CM_64QAM 3
+#define ISDB_T_LB_CM_NOLAYER 4
+       u8 layer_b_code_rate;
+#define ISDB_T_LB_CR_1_2   0
+#define ISDB_T_LB_CR_2_3   1
+#define ISDB_T_LB_CR_3_4   2
+#define ISDB_T_LB_CR_5_6   4
+#define ISDB_T_LB_CR_7_8   8
+#define ISDB_T_LB_CR_NOLAYER   16
+       u8 layer_b_time_interleave;
+#define ISDB_T_LB_TI_0  0
+#define ISDB_T_LB_TI_1  1
+#define ISDB_T_LB_TI_2  2
+#define ISDB_T_LB_TI_4  4
+#define ISDB_T_LB_TI_8  8
+#define ISDB_T_LB_TI_16 16
+#define ISDB_T_LB_TI_32 32
+       u8 layer_b_nseg;
+
+       u8 layer_c_mode;
+#define ISDB_T_LC_MODE_1 0
+#define ISDB_T_LC_MODE_2 1
+#define ISDB_T_LC_MODE_3 2
+       u8 layer_c_carrier_modulation;
+#define ISDB_T_LC_CM_DQPSK 0
+#define ISDB_T_LC_CM_QPSK  1
+#define ISDB_T_LC_CM_16QAM 2
+#define ISDB_T_LC_CM_64QAM 3
+#define ISDB_T_LC_CM_NOLAYER 4
+       u8 layer_c_code_rate;
+#define ISDB_T_LC_CR_1_2   0
+#define ISDB_T_LC_CR_2_3   1
+#define ISDB_T_LC_CR_3_4   2
+#define ISDB_T_LC_CR_5_6   4
+#define ISDB_T_LC_CR_7_8   8
+#define ISDB_T_LC_CR_NOLAYER   16
+       u8 layer_c_time_interleave;
+#define ISDB_T_LC_TI_0  0
+#define ISDB_T_LC_TI_1  1
+#define ISDB_T_LC_TI_2  2
+#define ISDB_T_LC_TI_4  4
+#define ISDB_T_LC_TI_8  8
+#define ISDB_T_LC_TI_16 16
+#define ISDB_T_LC_TI_32 32
+       u8 layer_c_nseg;
+};
+
+int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
+#endif
diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c
new file mode 100644 (file)
index 0000000..3cbb9cb
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Driver for Sharp s921 driver
+ *
+ * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ * All rights reserved.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s921_module.h"
+#include "s921_core.h"
+
+static  unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"s921 debugging (default off)");
+
+#define dprintk(fmt, args...) if (debug) do {\
+                       printk("s921 debug: " fmt, ##args); } while (0)
+
+struct s921_state
+{
+       struct dvb_frontend frontend;
+       fe_modulation_t current_modulation;
+       __u32 snr;
+       __u32 current_frequency;
+       __u8 addr;
+       struct s921_isdb_t dev;
+       struct i2c_adapter *i2c;
+};
+
+static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
+       struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
+       struct s921_isdb_t_transmission_mode_params params;
+       struct s921_isdb_t_tune_params tune_params;
+
+       tune_params.frequency = param->frequency;
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, &params);
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
+       mdelay(100);
+       return 0;
+}
+
+static int s921_init(struct dvb_frontend *fe) {
+       printk("s921 init\n");
+       return 0;
+}
+
+static int s921_sleep(struct dvb_frontend *fe) {
+       printk("s921 sleep\n");
+       return 0;
+}
+
+static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
+       unsigned int ret;
+       mdelay(5);
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
+       *status = 0;
+
+       printk("status: %02x\n", ret);
+       if (ret == 1) {
+               *status |= FE_HAS_CARRIER;
+               *status |= FE_HAS_VITERBI;
+               *status |= FE_HAS_LOCK;
+               *status |= FE_HAS_SYNC;
+               *status |= FE_HAS_SIGNAL;
+       }
+
+       return 0;
+}
+
+static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
+{
+       dprintk("read ber\n");
+       return 0;
+}
+
+static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
+{
+       dprintk("read snr\n");
+       return 0;
+}
+
+static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
+{
+       dprintk("read ucblocks\n");
+       return 0;
+}
+
+static void s921_release(struct dvb_frontend *fe)
+{
+       struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
+       kfree(state);
+}
+
+static struct dvb_frontend_ops demod_s921={
+       .info = {
+               .name                   = "SHARP S921",
+               .type                   = FE_OFDM,
+               .frequency_min          = 473143000,
+               .frequency_max          = 767143000,
+               .frequency_stepsize     =   6000000,
+               .frequency_tolerance    = 0,
+               .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+                       FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+                       FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
+                       FE_CAN_MUTE_TS
+       },
+       .init = s921_init,
+       .sleep = s921_sleep,
+       .set_frontend = s921_set_parameters,
+       .read_snr = s921_read_snr,
+       .read_ber = s921_read_ber,
+       .read_status = s921_read_status,
+       .read_ucblocks = s921_read_ucblocks,
+       .release = s921_release,
+};
+
+static int s921_write(void *dev, u8 reg, u8 val) {
+       struct s921_state *state = dev;
+       char buf[2]={reg,val};
+       int err;
+       struct i2c_msg i2cmsgs = {
+               .addr = state->addr,
+               .flags = 0,
+               .len = 2,
+               .buf = buf
+       };
+
+       if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
+               printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
+               if (err < 0)
+                       return err;
+               else
+                       return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int s921_read(void *dev, u8 reg) {
+       struct s921_state *state = dev;
+       u8 b1;
+       int ret;
+       struct i2c_msg msg[2] = { { .addr = state->addr,
+                                   .flags = 0,
+                                   .buf = &reg, .len = 1 },
+                                 { .addr = state->addr,
+                                   .flags = I2C_M_RD,
+                                   .buf = &b1, .len = 1 } };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2)
+               return ret;
+       return b1;
+}
+
+struct dvb_frontend* s921_attach(const struct s921_config *config,
+                                          struct i2c_adapter *i2c)
+{
+
+       struct s921_state *state;
+       state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
+       memset(state, 0x0, sizeof(struct s921_state));
+
+       state->addr = config->i2c_address;
+       state->i2c = i2c;
+       state->dev.i2c_write = &s921_write;
+       state->dev.i2c_read = &s921_read;
+       state->dev.priv_dev = state;
+
+       s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);
+
+       memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
+       state->frontend.demodulator_priv = state;
+       return &state->frontend;
+}
+
+EXPORT_SYMBOL_GPL(s921_attach);
+MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
+MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921_module.h b/drivers/media/dvb/frontends/s921_module.h
new file mode 100644 (file)
index 0000000..7866042
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Driver for DVB-T s921 demodulator
+ *
+ *  Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU 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.=
+ */
+
+#ifndef S921_MODULE_H
+#define S921_MODULE_H
+
+#include <linux/dvb/frontend.h>
+#include "s921_core.h"
+
+int s921_isdb_init(struct s921_isdb_t *dev);
+int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
+
+struct s921_config
+{
+       /* demodulator's I2C address */
+       u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE))
+extern struct dvb_frontend* s921_attach(const struct s921_config *config,
+                                          struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* s921_attach(const struct s921_config *config,
+                                          struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_S921 */
+
+#endif /* S921_H */
index 3ddbe69c45ce486673dbd3553ac07f0a579b7cc1..0bd16af8a6cd0723ab127f5a8de3c8d99e81e581 100644 (file)
@@ -8,7 +8,6 @@
 *      (at your option) any later version.
 *
 */
-#include <linux/version.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c
new file mode 100644 (file)
index 0000000..ced9b7a
--- /dev/null
@@ -0,0 +1,1519 @@
+/*
+       STB0899 Multistandard Frontend driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#include "stb0899_drv.h"
+#include "stb0899_priv.h"
+#include "stb0899_reg.h"
+
+inline u32 stb0899_do_div(u64 n, u32 d)
+{
+       /* wrap do_div() for ease of use */
+
+       do_div(n, d);
+       return n;
+}
+
+/*
+ * stb0899_calc_srate
+ * Compute symbol rate
+ */
+static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr)
+{
+       u64 tmp;
+
+       /* srate = (SFR * master_clk) >> 20 */
+
+       /* sfr is of size 20 bit, stored with an offset of 4 bit */
+       tmp = (((u32)sfr[0]) << 16) | (((u32)sfr[1]) << 8) | sfr[2];
+       tmp &= ~0xf;
+       tmp *= master_clk;
+       tmp >>= 24;
+
+       return tmp;
+}
+
+/*
+ * stb0899_get_srate
+ * Get the current symbol rate
+ */
+u32 stb0899_get_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u8 sfr[3];
+
+       stb0899_read_regs(state, STB0899_SFRH, sfr, 3);
+
+       return stb0899_calc_srate(internal->master_clk, sfr);
+}
+
+/*
+ * stb0899_set_srate
+ * Set symbol frequency
+ * MasterClock: master clock frequency (hz)
+ * SymbolRate: symbol rate (bauds)
+ * return symbol frequency
+ */
+static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 srate)
+{
+       u32 tmp;
+       u8 sfr[3];
+
+       dprintk(state->verbose, FE_DEBUG, 1, "-->");
+       /*
+        * in order to have the maximum precision, the symbol rate entered into
+        * the chip is computed as the closest value of the "true value".
+        * In this purpose, the symbol rate value is rounded (1 is added on the bit
+        * below the LSB )
+        *
+        * srate = (SFR * master_clk) >> 20
+        *      <=>
+        *   SFR = srate << 20 / master_clk
+        *
+        * rounded:
+        *   SFR = (srate << 21 + master_clk) / (2 * master_clk)
+        *
+        * stored as 20 bit number with an offset of 4 bit:
+        *   sfr = SFR << 4;
+        */
+
+       tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk);
+       tmp <<= 4;
+
+       sfr[0] = tmp >> 16;
+       sfr[1] = tmp >>  8;
+       sfr[2] = tmp;
+
+       stb0899_write_regs(state, STB0899_SFRH, sfr, 3);
+
+       return srate;
+}
+
+/*
+ * stb0899_calc_derot_time
+ * Compute the amount of time needed by the derotator to lock
+ * SymbolRate: Symbol rate
+ * return: derotator time constant (ms)
+ */
+static long stb0899_calc_derot_time(long srate)
+{
+       if (srate > 0)
+               return (100000 / (srate / 1000));
+       else
+               return 0;
+}
+
+/*
+ * stb0899_carr_width
+ * Compute the width of the carrier
+ * return: width of carrier (kHz or Mhz)
+ */
+long stb0899_carr_width(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       return (internal->srate + (internal->srate * internal->rolloff) / 100);
+}
+
+/*
+ * stb0899_first_subrange
+ * Compute the first subrange of the search
+ */
+static void stb0899_first_subrange(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_params *params           = &state->params;
+       struct stb0899_config *config           =  state->config;
+
+       int range = 0;
+       u32 bandwidth = 0;
+
+       if (config->tuner_get_bandwidth) {
+               stb0899_i2c_gate_ctrl(&state->frontend, 1);
+               config->tuner_get_bandwidth(&state->frontend, &bandwidth);
+               stb0899_i2c_gate_ctrl(&state->frontend, 0);
+               range = bandwidth - stb0899_carr_width(state) / 2;
+       }
+
+       if (range > 0)
+               internal->sub_range = MIN(internal->srch_range, range);
+       else
+               internal->sub_range = 0;
+
+       internal->freq = params->freq;
+       internal->tuner_offst = 0L;
+       internal->sub_dir = 1;
+}
+
+/*
+ * stb0899_check_tmg
+ * check for timing lock
+ * internal.Ttiming: time to wait for loop lock
+ */
+static enum stb0899_status stb0899_check_tmg(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       int lock;
+       u8 reg;
+       s8 timing;
+
+       msleep(internal->t_derot);
+
+       stb0899_write_reg(state, STB0899_RTF, 0xf2);
+       reg = stb0899_read_reg(state, STB0899_TLIR);
+       lock = STB0899_GETFIELD(TLIR_TMG_LOCK_IND, reg);
+       timing = stb0899_read_reg(state, STB0899_RTF);
+
+       if (lock >= 42) {
+               if ((lock > 48) && (ABS(timing) >= 110)) {
+                       internal->status = ANALOGCARRIER;
+                       dprintk(state->verbose, FE_DEBUG, 1, "-->ANALOG Carrier !");
+               } else {
+                       internal->status = TIMINGOK;
+                       dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK !");
+               }
+       } else {
+               internal->status = NOTIMING;
+               dprintk(state->verbose, FE_DEBUG, 1, "-->NO TIMING !");
+       }
+       return internal->status;
+}
+
+/*
+ * stb0899_search_tmg
+ * perform a fs/2 zig-zag to find timing
+ */
+static enum stb0899_status stb0899_search_tmg(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       short int derot_step, derot_freq = 0, derot_limit, next_loop = 3;
+       int index = 0;
+       u8 cfr[2];
+
+       internal->status = NOTIMING;
+
+       /* timing loop computation & symbol rate optimisation   */
+       derot_limit = (internal->sub_range / 2L) / internal->mclk;
+       derot_step = (params->srate / 2L) / internal->mclk;
+
+       while ((stb0899_check_tmg(state) != TIMINGOK) && next_loop) {
+               index++;
+               derot_freq += index * internal->direction * derot_step; /* next derot zig zag position  */
+
+               if (ABS(derot_freq) > derot_limit)
+                       next_loop--;
+
+               if (next_loop) {
+                       STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+                       STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                       stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency         */
+               }
+               internal->direction = -internal->direction;     /* Change zigzag direction              */
+       }
+
+       if (internal->status == TIMINGOK) {
+               stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency              */
+               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               dprintk(state->verbose, FE_DEBUG, 1, "------->TIMING OK ! Derot Freq = %d", internal->derot_freq);
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_check_carrier
+ * Check for carrier found
+ */
+static enum stb0899_status stb0899_check_carrier(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u8 reg;
+
+       msleep(internal->t_derot); /* wait for derotator ok     */
+
+       reg = stb0899_read_reg(state, STB0899_CFD);
+       STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+       stb0899_write_reg(state, STB0899_CFD, reg);
+
+       reg = stb0899_read_reg(state, STB0899_DSTATUS);
+       dprintk(state->verbose, FE_DEBUG, 1, "--------------------> STB0899_DSTATUS=[0x%02x]", reg);
+       if (STB0899_GETFIELD(CARRIER_FOUND, reg)) {
+               internal->status = CARRIEROK;
+               dprintk(state->verbose, FE_DEBUG, 1, "-------------> CARRIEROK !");
+       } else {
+               internal->status = NOCARRIER;
+               dprintk(state->verbose, FE_DEBUG, 1, "-------------> NOCARRIER !");
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_search_carrier
+ * Search for a QPSK carrier with the derotator
+ */
+static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
+       int index = 0;
+       u8 cfr[2];
+       u8 reg;
+
+       internal->status = NOCARRIER;
+       derot_limit = (internal->sub_range / 2L) / internal->mclk;
+       derot_freq = internal->derot_freq;
+
+       reg = stb0899_read_reg(state, STB0899_CFD);
+       STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+       stb0899_write_reg(state, STB0899_CFD, reg);
+
+       do {
+               dprintk(state->verbose, FE_DEBUG, 1, "Derot Freq=%d, mclk=%d", derot_freq, internal->mclk);
+               if (stb0899_check_carrier(state) == NOCARRIER) {
+                       index++;
+                       last_derot_freq = derot_freq;
+                       derot_freq += index * internal->direction * internal->derot_step; /* next zig zag derotator position */
+
+                       if(ABS(derot_freq) > derot_limit)
+                               next_loop--;
+
+                       if (next_loop) {
+                               reg = stb0899_read_reg(state, STB0899_CFD);
+                               STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+                               stb0899_write_reg(state, STB0899_CFD, reg);
+
+                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                               stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
+                       }
+               }
+
+               internal->direction = -internal->direction; /* Change zigzag direction */
+       } while ((internal->status != CARRIEROK) && next_loop);
+
+       if (internal->status == CARRIEROK) {
+               stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
+               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               dprintk(state->verbose, FE_DEBUG, 1, "----> CARRIER OK !, Derot Freq=%d", internal->derot_freq);
+       } else {
+               internal->derot_freq = last_derot_freq;
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_check_data
+ * Check for data found
+ */
+static enum stb0899_status stb0899_check_data(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       int lock = 0, index = 0, dataTime = 500, loop;
+       u8 reg;
+
+       internal->status = NODATA;
+
+       /* RESET FEC    */
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESACS, reg, 1);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+       msleep(1);
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESACS, reg, 0);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+       if (params->srate <= 2000000)
+               dataTime = 2000;
+       else if (params->srate <= 5000000)
+               dataTime = 1500;
+       else if (params->srate <= 15000000)
+               dataTime = 1000;
+       else
+               dataTime = 500;
+
+       stb0899_write_reg(state, STB0899_DSTATUS2, 0x00); /* force search loop  */
+       while (1) {
+               /* WARNING! VIT LOCKED has to be tested before VIT_END_LOOOP    */
+               reg = stb0899_read_reg(state, STB0899_VSTATUS);
+               lock = STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg);
+               loop = STB0899_GETFIELD(VSTATUS_END_LOOPVIT, reg);
+
+               if (lock || loop || (index > dataTime))
+                       break;
+               index++;
+       }
+
+       if (lock) {     /* DATA LOCK indicator  */
+               internal->status = DATAOK;
+               dprintk(state->verbose, FE_DEBUG, 1, "-----------------> DATA OK !");
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_search_data
+ * Search for a QPSK carrier with the derotator
+ */
+static enum stb0899_status stb0899_search_data(struct stb0899_state *state)
+{
+       short int derot_freq, derot_step, derot_limit, next_loop = 3;
+       u8 cfr[2];
+       u8 reg;
+       int index = 1;
+
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       derot_step = (params->srate / 4L) / internal->mclk;
+       derot_limit = (internal->sub_range / 2L) / internal->mclk;
+       derot_freq = internal->derot_freq;
+
+       do {
+               if ((internal->status != CARRIEROK) || (stb0899_check_data(state) != DATAOK)) {
+
+                       derot_freq += index * internal->direction * derot_step; /* next zig zag derotator position */
+                       if (ABS(derot_freq) > derot_limit)
+                               next_loop--;
+
+                       if (next_loop) {
+                               dprintk(state->verbose, FE_DEBUG, 1, "Derot freq=%d, mclk=%d", derot_freq, internal->mclk);
+                               reg = stb0899_read_reg(state, STB0899_CFD);
+                               STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+                               stb0899_write_reg(state, STB0899_CFD, reg);
+
+                               STB0899_SETFIELD_VAL(CFRM, cfr[0], MSB(state->config->inversion * derot_freq));
+                               STB0899_SETFIELD_VAL(CFRL, cfr[1], LSB(state->config->inversion * derot_freq));
+                               stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* derotator frequency */
+
+                               stb0899_check_carrier(state);
+                               index++;
+                       }
+               }
+               internal->direction = -internal->direction; /* change zig zag direction */
+       } while ((internal->status != DATAOK) && next_loop);
+
+       if (internal->status == DATAOK) {
+               stb0899_read_regs(state, STB0899_CFRM, cfr, 2); /* get derotator frequency */
+               internal->derot_freq = state->config->inversion * MAKEWORD16(cfr[0], cfr[1]);
+               dprintk(state->verbose, FE_DEBUG, 1, "------> DATAOK ! Derot Freq=%d", internal->derot_freq);
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_check_range
+ * check if the found frequency is in the correct range
+ */
+static enum stb0899_status stb0899_check_range(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       int range_offst, tp_freq;
+
+       range_offst = internal->srch_range / 2000;
+       tp_freq = internal->freq + (internal->derot_freq * internal->mclk) / 1000;
+
+       if ((tp_freq >= params->freq - range_offst) && (tp_freq <= params->freq + range_offst)) {
+               internal->status = RANGEOK;
+               dprintk(state->verbose, FE_DEBUG, 1, "----> RANGEOK !");
+       } else {
+               internal->status = OUTOFRANGE;
+               dprintk(state->verbose, FE_DEBUG, 1, "----> OUT OF RANGE !");
+       }
+
+       return internal->status;
+}
+
+/*
+ * NextSubRange
+ * Compute the next subrange of the search
+ */
+static void next_sub_range(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_params *params = &state->params;
+
+       long old_sub_range;
+
+       if (internal->sub_dir > 0) {
+               old_sub_range = internal->sub_range;
+               internal->sub_range = MIN((internal->srch_range / 2) -
+                                         (internal->tuner_offst + internal->sub_range / 2),
+                                          internal->sub_range);
+
+               if (internal->sub_range < 0)
+                       internal->sub_range = 0;
+
+               internal->tuner_offst += (old_sub_range + internal->sub_range) / 2;
+       }
+
+       internal->freq = params->freq + (internal->sub_dir * internal->tuner_offst) / 1000;
+       internal->sub_dir = -internal->sub_dir;
+}
+
+/*
+ * stb0899_dvbs_algo
+ * Search for a signal, timing, carrier and data for a
+ * given frequency in a given range
+ */
+enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state)
+{
+       struct stb0899_params *params           = &state->params;
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_config *config           = state->config;
+
+       u8 bclc, reg;
+       u8 cfr[2];
+       u8 eq_const[10];
+       s32 clnI = 3;
+       u32 bandwidth = 0;
+
+       /* BETA values rated @ 99MHz    */
+       s32 betaTab[5][4] = {
+              /*  5   10   20   30MBps */
+               { 37,  34,  32,  31 }, /* QPSK 1/2      */
+               { 37,  35,  33,  31 }, /* QPSK 2/3      */
+               { 37,  35,  33,  31 }, /* QPSK 3/4      */
+               { 37,  36,  33,  32 }, /* QPSK 5/6      */
+               { 37,  36,  33,  32 }  /* QPSK 7/8      */
+       };
+
+       internal->direction = 1;
+
+       stb0899_set_srate(state, internal->master_clk, params->srate);
+       /* Carrier loop optimization versus symbol rate for acquisition*/
+       if (params->srate <= 5000000) {
+               stb0899_write_reg(state, STB0899_ACLC, 0x89);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x1c);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 0;
+       } else if (params->srate <= 15000000) {
+               stb0899_write_reg(state, STB0899_ACLC, 0xc9);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x22);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 1;
+       } else if(params->srate <= 25000000) {
+               stb0899_write_reg(state, STB0899_ACLC, 0x89);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x27);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 2;
+       } else {
+               stb0899_write_reg(state, STB0899_ACLC, 0xc8);
+               bclc = stb0899_read_reg(state, STB0899_BCLC);
+               STB0899_SETFIELD_VAL(BETA, bclc, 0x29);
+               stb0899_write_reg(state, STB0899_BCLC, bclc);
+               clnI = 3;
+       }
+
+       dprintk(state->verbose, FE_DEBUG, 1, "Set the timing loop to acquisition");
+       /* Set the timing loop to acquisition   */
+       stb0899_write_reg(state, STB0899_RTC, 0x46);
+       stb0899_write_reg(state, STB0899_CFD, 0xee);
+
+       /* !! WARNING !!
+        * Do not read any status variables while acquisition,
+        * If any needed, read before the acquisition starts
+        * querying status while acquiring causes the
+        * acquisition to go bad and hence no locks.
+        */
+       dprintk(state->verbose, FE_DEBUG, 1, "Derot Percent=%d Srate=%d mclk=%d",
+               internal->derot_percent, params->srate, internal->mclk);
+
+       /* Initial calculations */
+       internal->derot_step = internal->derot_percent * (params->srate / 1000L) / internal->mclk; /* DerotStep/1000 * Fsymbol  */
+       internal->t_derot = stb0899_calc_derot_time(params->srate);
+       internal->t_data = 500;
+
+       dprintk(state->verbose, FE_DEBUG, 1, "RESET stream merger");
+       /* RESET Stream merger  */
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESRS, reg, 1);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+       /*
+        * Set KDIVIDER to an intermediate value between
+        * 1/2 and 7/8 for acquisition
+        */
+       reg = stb0899_read_reg(state, STB0899_DEMAPVIT);
+       STB0899_SETFIELD_VAL(DEMAPVIT_KDIVIDER, reg, 60);
+       stb0899_write_reg(state, STB0899_DEMAPVIT, reg);
+
+       stb0899_write_reg(state, STB0899_EQON, 0x01); /* Equalizer OFF while acquiring */
+       stb0899_write_reg(state, STB0899_VITSYNC, 0x19);
+
+       stb0899_first_subrange(state);
+       do {
+               /* Initialisations */
+               cfr[0] = cfr[1] = 0;
+               stb0899_write_regs(state, STB0899_CFRM, cfr, 2); /* RESET derotator frequency   */
+
+               stb0899_write_reg(state, STB0899_RTF, 0);
+               reg = stb0899_read_reg(state, STB0899_CFD);
+               STB0899_SETFIELD_VAL(CFD_ON, reg, 1);
+               stb0899_write_reg(state, STB0899_CFD, reg);
+
+               internal->derot_freq = 0;
+               internal->status = NOAGC1;
+
+               /* enable tuner I/O */
+               stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+               /* Move tuner to frequency */
+               dprintk(state->verbose, FE_DEBUG, 1, "Tuner set frequency");
+               if (state->config->tuner_set_frequency)
+                       state->config->tuner_set_frequency(&state->frontend, internal->freq);
+
+               if (state->config->tuner_get_frequency)
+                       state->config->tuner_get_frequency(&state->frontend, &internal->freq);
+
+               msleep(internal->t_agc1 + internal->t_agc2 + internal->t_derot); /* AGC1, AGC2 and timing loop  */
+               dprintk(state->verbose, FE_DEBUG, 1, "current derot freq=%d", internal->derot_freq);
+               internal->status = AGC1OK;
+
+               /* There is signal in the band  */
+               if (config->tuner_get_bandwidth)
+                       config->tuner_get_bandwidth(&state->frontend, &bandwidth);
+
+               /* disable tuner I/O */
+               stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+               if (params->srate <= bandwidth / 2)
+                       stb0899_search_tmg(state); /* For low rates (SCPC)      */
+               else
+                       stb0899_check_tmg(state); /* For high rates (MCPC)      */
+
+               if (internal->status == TIMINGOK) {
+                       dprintk(state->verbose, FE_DEBUG, 1,
+                               "TIMING OK ! Derot freq=%d, mclk=%d",
+                               internal->derot_freq, internal->mclk);
+
+                       if (stb0899_search_carrier(state) == CARRIEROK) {       /* Search for carrier   */
+                               dprintk(state->verbose, FE_DEBUG, 1,
+                                       "CARRIER OK ! Derot freq=%d, mclk=%d",
+                                       internal->derot_freq, internal->mclk);
+
+                               if (stb0899_search_data(state) == DATAOK) {     /* Check for data       */
+                                       dprintk(state->verbose, FE_DEBUG, 1,
+                                               "DATA OK ! Derot freq=%d, mclk=%d",
+                                               internal->derot_freq, internal->mclk);
+
+                                       if (stb0899_check_range(state) == RANGEOK) {
+                                               dprintk(state->verbose, FE_DEBUG, 1,
+                                                       "RANGE OK ! derot freq=%d, mclk=%d",
+                                                       internal->derot_freq, internal->mclk);
+
+                                               internal->freq = params->freq + ((internal->derot_freq * internal->mclk) / 1000);
+                                               reg = stb0899_read_reg(state, STB0899_PLPARM);
+                                               internal->fecrate = STB0899_GETFIELD(VITCURPUN, reg);
+                                               dprintk(state->verbose, FE_DEBUG, 1,
+                                                       "freq=%d, internal resultant freq=%d",
+                                                       params->freq, internal->freq);
+
+                                               dprintk(state->verbose, FE_DEBUG, 1,
+                                                       "internal puncture rate=%d",
+                                                       internal->fecrate);
+                                       }
+                               }
+                       }
+               }
+               if (internal->status != RANGEOK)
+                       next_sub_range(state);
+
+       } while (internal->sub_range && internal->status != RANGEOK);
+
+       /* Set the timing loop to tracking      */
+       stb0899_write_reg(state, STB0899_RTC, 0x33);
+       stb0899_write_reg(state, STB0899_CFD, 0xf7);
+       /* if locked and range ok, set Kdiv     */
+       if (internal->status == RANGEOK) {
+               dprintk(state->verbose, FE_DEBUG, 1, "Locked & Range OK !");
+               stb0899_write_reg(state, STB0899_EQON, 0x41);           /* Equalizer OFF while acquiring        */
+               stb0899_write_reg(state, STB0899_VITSYNC, 0x39);        /* SN to b'11 for acquisition           */
+
+               /*
+                * Carrier loop optimization versus
+                * symbol Rate/Puncture Rate for Tracking
+                */
+               reg = stb0899_read_reg(state, STB0899_BCLC);
+               switch (internal->fecrate) {
+               case STB0899_FEC_1_2:           /* 13   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 0x1a);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[0][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_2_3:           /* 18   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 44);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[1][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_3_4:           /* 21   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 60);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[2][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_5_6:           /* 24   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 75);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[3][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               case STB0899_FEC_6_7:           /* 25   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 88);
+                       stb0899_write_reg(state, STB0899_ACLC, 0x88);
+                       stb0899_write_reg(state, STB0899_BCLC, 0x9a);
+                       break;
+               case STB0899_FEC_7_8:           /* 26   */
+                       stb0899_write_reg(state, STB0899_DEMAPVIT, 94);
+                       STB0899_SETFIELD_VAL(BETA, reg, betaTab[4][clnI]);
+                       stb0899_write_reg(state, STB0899_BCLC, reg);
+                       break;
+               default:
+                       dprintk(state->verbose, FE_DEBUG, 1, "Unsupported Puncture Rate");
+                       break;
+               }
+               /* release stream merger RESET  */
+               reg = stb0899_read_reg(state, STB0899_TSTRES);
+               STB0899_SETFIELD_VAL(FRESRS, reg, 0);
+               stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+               /* disable carrier detector     */
+               reg = stb0899_read_reg(state, STB0899_CFD);
+               STB0899_SETFIELD_VAL(CFD_ON, reg, 0);
+               stb0899_write_reg(state, STB0899_CFD, reg);
+
+               stb0899_read_regs(state, STB0899_EQUAI1, eq_const, 10);
+       }
+
+       return internal->status;
+}
+
+/*
+ * stb0899_dvbs2_config_uwp
+ * Configure UWP state machine
+ */
+static void stb0899_dvbs2_config_uwp(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_config *config = state->config;
+       u32 uwp1, uwp2, uwp3, reg;
+
+       uwp1 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
+       uwp2 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL2);
+       uwp3 = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL3);
+
+       STB0899_SETFIELD_VAL(UWP_ESN0_AVE, uwp1, config->esno_ave);
+       STB0899_SETFIELD_VAL(UWP_ESN0_QUANT, uwp1, config->esno_quant);
+       STB0899_SETFIELD_VAL(UWP_TH_SOF, uwp1, config->uwp_threshold_sof);
+
+       STB0899_SETFIELD_VAL(FE_COARSE_TRK, uwp2, internal->av_frame_coarse);
+       STB0899_SETFIELD_VAL(FE_FINE_TRK, uwp2, internal->av_frame_fine);
+       STB0899_SETFIELD_VAL(UWP_MISS_TH, uwp2, config->miss_threshold);
+
+       STB0899_SETFIELD_VAL(UWP_TH_ACQ, uwp3, config->uwp_threshold_acq);
+       STB0899_SETFIELD_VAL(UWP_TH_TRACK, uwp3, config->uwp_threshold_track);
+
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL1, STB0899_OFF0_UWP_CNTRL1, uwp1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL2, STB0899_OFF0_UWP_CNTRL2, uwp2);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_UWP_CNTRL3, STB0899_OFF0_UWP_CNTRL3, uwp3);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, SOF_SRCH_TO);
+       STB0899_SETFIELD_VAL(SOF_SEARCH_TIMEOUT, reg, config->sof_search_timeout);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_SOF_SRCH_TO, STB0899_OFF0_SOF_SRCH_TO, reg);
+}
+
+/*
+ * stb0899_dvbs2_config_csm_auto
+ * Set CSM to AUTO mode
+ */
+static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state)
+{
+       u32 reg;
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+       STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, reg, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg);
+}
+
+long Log2Int(int number)
+{
+       int i;
+
+       i = 0;
+       while ((1 << i) <= ABS(number))
+               i++;
+
+       if (number == 0)
+               i = 1;
+
+       return i - 1;
+}
+
+/*
+ * stb0899_dvbs2_calc_srate
+ * compute BTR_NOM_FREQ for the symbol rate
+ */
+static u32 stb0899_dvbs2_calc_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_config *config           = state->config;
+
+       u32 dec_ratio, dec_rate, decim, remain, intval, btr_nom_freq;
+       u32 master_clk, srate;
+
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+       dec_rate = Log2Int(dec_ratio);
+       decim = 1 << dec_rate;
+       master_clk = internal->master_clk / 1000;
+       srate = internal->srate / 1000;
+
+       if (decim <= 4) {
+               intval = (decim * (1 << (config->btr_nco_bits - 1))) / master_clk;
+               remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
+       } else {
+               intval = (1 << (config->btr_nco_bits - 1)) / (master_clk / 100) * decim / 100;
+               remain = (decim * (1 << (config->btr_nco_bits - 1))) % master_clk;
+       }
+       btr_nom_freq = (intval * srate) + ((remain * srate) / master_clk);
+
+       return btr_nom_freq;
+}
+
+/*
+ * stb0899_dvbs2_calc_dev
+ * compute the correction to be applied to symbol rate
+ */
+static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u32 dec_ratio, correction, master_clk, srate;
+
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+
+       master_clk = internal->master_clk / 1000;       /* for integer Caculation*/
+       srate = internal->srate / 1000; /* for integer Caculation*/
+       correction = (512 * master_clk) / (2 * dec_ratio * srate);
+
+       return  correction;
+}
+
+/*
+ * stb0899_dvbs2_set_srate
+ * Set DVBS2 symbol rate
+ */
+static void stb0899_dvbs2_set_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       u32 dec_ratio, dec_rate, win_sel, decim, f_sym, btr_nom_freq;
+       u32 correction, freq_adj, band_lim, decim_cntrl, reg;
+       u8 anti_alias;
+
+       /*set decimation to 1*/
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+       dec_rate = Log2Int(dec_ratio);
+
+       win_sel = 0;
+       if (dec_rate >= 5)
+               win_sel = dec_rate - 4;
+
+       decim = (1 << dec_rate);
+       /* (FSamp/Fsymbol *100) for integer Caculation */
+       f_sym = internal->master_clk / ((decim * internal->srate) / 1000);
+
+       if (f_sym <= 2250)      /* don't band limit signal going into btr block*/
+               band_lim = 1;
+       else
+               band_lim = 0;   /* band limit signal going into btr block*/
+
+       decim_cntrl = ((win_sel << 3) & 0x18) + ((band_lim << 5) & 0x20) + (dec_rate & 0x7);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DECIM_CNTRL, STB0899_OFF0_DECIM_CNTRL, decim_cntrl);
+
+       if (f_sym <= 3450)
+               anti_alias = 0;
+       else if (f_sym <= 4250)
+               anti_alias = 1;
+       else
+               anti_alias = 2;
+
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ANTI_ALIAS_SEL, STB0899_OFF0_ANTI_ALIAS_SEL, anti_alias);
+       btr_nom_freq = stb0899_dvbs2_calc_srate(state);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_NOM_FREQ, STB0899_OFF0_BTR_NOM_FREQ, btr_nom_freq);
+
+       correction = stb0899_dvbs2_calc_dev(state);
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
+       STB0899_SETFIELD_VAL(BTR_FREQ_CORR, reg, correction);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
+
+       /* scale UWP+CSM frequency to sample rate*/
+       freq_adj =  internal->srate / (internal->master_clk / 4096);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_FREQ_ADJ_SCALE, STB0899_OFF0_FREQ_ADJ_SCALE, freq_adj);
+}
+
+/*
+ * stb0899_dvbs2_set_btr_loopbw
+ * set bit timing loop bandwidth as a percentage of the symbol rate
+ */
+static void stb0899_dvbs2_set_btr_loopbw(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal       = &state->internal;
+       struct stb0899_config *config           = state->config;
+
+       u32 sym_peak = 23, zeta = 707, loopbw_percent = 60;
+       s32 dec_ratio, dec_rate, k_btr1_rshft, k_btr1, k_btr0_rshft;
+       s32 k_btr0, k_btr2_rshft, k_direct_shift, k_indirect_shift;
+       u32 decim, K, wn, k_direct, k_indirect;
+       u32 reg;
+
+       dec_ratio = (internal->master_clk * 2) / (5 * internal->srate);
+       dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio;
+       dec_rate = Log2Int(dec_ratio);
+       decim = (1 << dec_rate);
+
+       sym_peak *= 576000;
+       K = (1 << config->btr_nco_bits) / (internal->master_clk / 1000);
+       K *= (internal->srate / 1000000) * decim; /*k=k 10^-8*/
+
+       if (K != 0) {
+               K = sym_peak / K;
+               wn = (4 * zeta * zeta) + 1000000;
+               wn = (2 * (loopbw_percent * 1000) * 40 * zeta) /wn;  /*wn =wn 10^-8*/
+
+               k_indirect = (wn * wn) / K;
+               k_indirect = k_indirect;          /*kindirect = kindirect 10^-6*/
+               k_direct   = (2 * wn * zeta) / K;       /*kDirect = kDirect 10^-2*/
+               k_direct  *= 100;
+
+               k_direct_shift = Log2Int(k_direct) - Log2Int(10000) - 2;
+               k_btr1_rshft = (-1 * k_direct_shift) + config->btr_gain_shift_offset;
+               k_btr1 = k_direct / (1 << k_direct_shift);
+               k_btr1 /= 10000;
+
+               k_indirect_shift = Log2Int(k_indirect + 15) - 20 /*- 2*/;
+               k_btr0_rshft = (-1 * k_indirect_shift) + config->btr_gain_shift_offset;
+               k_btr0 = k_indirect * (1 << (-k_indirect_shift));
+               k_btr0 /= 1000000;
+
+               k_btr2_rshft = 0;
+               if (k_btr0_rshft > 15) {
+                       k_btr2_rshft = k_btr0_rshft - 15;
+                       k_btr0_rshft = 15;
+               }
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_LOOP_GAIN);
+               STB0899_SETFIELD_VAL(KBTR0_RSHFT, reg, k_btr0_rshft);
+               STB0899_SETFIELD_VAL(KBTR0, reg, k_btr0);
+               STB0899_SETFIELD_VAL(KBTR1_RSHFT, reg, k_btr1_rshft);
+               STB0899_SETFIELD_VAL(KBTR1, reg, k_btr1);
+               STB0899_SETFIELD_VAL(KBTR2_RSHFT, reg, k_btr2_rshft);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, reg);
+       } else
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_LOOP_GAIN, STB0899_OFF0_BTR_LOOP_GAIN, 0xc4c4f);
+}
+
+/*
+ * stb0899_dvbs2_set_carr_freq
+ * set nominal frequency for carrier search
+ */
+static void stb0899_dvbs2_set_carr_freq(struct stb0899_state *state, s32 carr_freq, u32 master_clk)
+{
+       struct stb0899_config *config = state->config;
+       s32 crl_nom_freq;
+       u32 reg;
+
+       crl_nom_freq = (1 << config->crl_nco_bits) / master_clk;
+       crl_nom_freq *= carr_freq;
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+       STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, crl_nom_freq);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+}
+
+/*
+ * stb0899_dvbs2_init_calc
+ * Initialize DVBS2 UWP, CSM, carrier and timing loops
+ */
+static void stb0899_dvbs2_init_calc(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       s32 steps, step_size;
+       u32 range, reg;
+
+       /* config uwp and csm */
+       stb0899_dvbs2_config_uwp(state);
+       stb0899_dvbs2_config_csm_auto(state);
+
+       /* initialize BTR       */
+       stb0899_dvbs2_set_srate(state);
+       stb0899_dvbs2_set_btr_loopbw(state);
+
+       if (internal->srate / 1000000 >= 15)
+               step_size = (1 << 17) / 5;
+       else if (internal->srate / 1000000 >= 10)
+               step_size = (1 << 17) / 7;
+       else if (internal->srate / 1000000 >= 5)
+               step_size = (1 << 17) / 10;
+       else
+               step_size = (1 << 17) / 4;
+
+       range = internal->srch_range / 1000000;
+       steps = (10 * range * (1 << 17)) / (step_size * (internal->srate / 1000000));
+       steps = (steps + 6) / 10;
+       steps = (steps == 0) ? 1 : steps;
+       if (steps % 2 == 0)
+               stb0899_dvbs2_set_carr_freq(state, internal->center_freq -
+                                          (internal->step_size * (internal->srate / 20000000)),
+                                          (internal->master_clk) / 1000000);
+       else
+               stb0899_dvbs2_set_carr_freq(state, internal->center_freq, (internal->master_clk) / 1000000);
+
+       /*Set Carrier Search params (zigzag, num steps and freq step size*/
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, ACQ_CNTRL2);
+       STB0899_SETFIELD_VAL(ZIGZAG, reg, 1);
+       STB0899_SETFIELD_VAL(NUM_STEPS, reg, steps);
+       STB0899_SETFIELD_VAL(FREQ_STEPSIZE, reg, step_size);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQ_CNTRL2, STB0899_OFF0_ACQ_CNTRL2, reg);
+}
+
+/*
+ * stb0899_dvbs2_btr_init
+ * initialize the timing loop
+ */
+static void stb0899_dvbs2_btr_init(struct stb0899_state *state)
+{
+       u32 reg;
+
+       /* set enable BTR loopback      */
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_CNTRL);
+       STB0899_SETFIELD_VAL(INTRP_PHS_SENSE, reg, 1);
+       STB0899_SETFIELD_VAL(BTR_ERR_ENA, reg, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_CNTRL, STB0899_OFF0_BTR_CNTRL, reg);
+
+       /* fix btr freq accum at 0      */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x10000000);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_FREQ_INIT, STB0899_OFF0_BTR_FREQ_INIT, 0x00000000);
+
+       /* fix btr freq accum at 0      */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x10000000);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_BTR_PHS_INIT, STB0899_OFF0_BTR_PHS_INIT, 0x00000000);
+}
+
+/*
+ * stb0899_dvbs2_reacquire
+ * trigger a DVB-S2 acquisition
+ */
+static void stb0899_dvbs2_reacquire(struct stb0899_state *state)
+{
+       u32 reg = 0;
+
+       /* demod soft reset     */
+       STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
+
+       /*Reset Timing Loop     */
+       stb0899_dvbs2_btr_init(state);
+
+       /* reset Carrier loop   */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, (1 << 30));
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_FREQ_INIT, STB0899_OFF0_CRL_FREQ_INIT, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_LOOP_GAIN, STB0899_OFF0_CRL_LOOP_GAIN, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, (1 << 30));
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_PHS_INIT, STB0899_OFF0_CRL_PHS_INIT, 0);
+
+       /*release demod soft reset      */
+       reg = 0;
+       STB0899_SETFIELD_VAL(DVBS2_RESET, reg, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_RESET_CNTRL, STB0899_OFF0_RESET_CNTRL, reg);
+
+       /* start acquisition process    */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_ACQUIRE_TRIG, STB0899_OFF0_ACQUIRE_TRIG, 1);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_LOCK_LOST, STB0899_OFF0_LOCK_LOST, 0);
+
+       /* equalizer Init       */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 1);
+
+       /*Start equilizer       */
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQUALIZER_INIT, STB0899_OFF0_EQUALIZER_INIT, 0);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+       STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0);
+       STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 0);
+       STB0899_SETFIELD_VAL(EQ_DELAY, reg, 0x05);
+       STB0899_SETFIELD_VAL(EQ_ADAPT_MODE, reg, 0x01);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+
+       /* RESET Packet delineator      */
+       stb0899_write_reg(state, STB0899_PDELCTRL, 0x4a);
+}
+
+/*
+ * stb0899_dvbs2_get_dmd_status
+ * get DVB-S2 Demod LOCK status
+ */
+static enum stb0899_status stb0899_dvbs2_get_dmd_status(struct stb0899_state *state, int timeout)
+{
+       int time = -10, lock = 0, uwp, csm;
+       u32 reg;
+
+       do {
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STATUS);
+               dprintk(state->verbose, FE_DEBUG, 1, "DMD_STATUS=[0x%02x]", reg);
+               if (STB0899_GETFIELD(IF_AGC_LOCK, reg))
+                       dprintk(state->verbose, FE_DEBUG, 1, "------------->IF AGC LOCKED !");
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
+               dprintk(state->verbose, FE_DEBUG, 1, "----------->DMD STAT2=[0x%02x]", reg);
+               uwp = STB0899_GETFIELD(UWP_LOCK, reg);
+               csm = STB0899_GETFIELD(CSM_LOCK, reg);
+               if (uwp && csm)
+                       lock = 1;
+
+               time += 10;
+               msleep(10);
+
+       } while ((!lock) && (time <= timeout));
+
+       if (lock) {
+               dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 LOCK !");
+               return DVBS2_DEMOD_LOCK;
+       } else {
+               return DVBS2_DEMOD_NOLOCK;
+       }
+}
+
+/*
+ * stb0899_dvbs2_get_data_lock
+ * get FEC status
+ */
+static int stb0899_dvbs2_get_data_lock(struct stb0899_state *state, int timeout)
+{
+       int time = 0, lock = 0;
+       u8 reg;
+
+       while ((!lock) && (time < timeout)) {
+               reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
+               dprintk(state->verbose, FE_DEBUG, 1, "---------> CFGPDELSTATUS=[0x%02x]", reg);
+               lock = STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg);
+               time++;
+       }
+
+       return lock;
+}
+
+/*
+ * stb0899_dvbs2_get_fec_status
+ * get DVB-S2 FEC LOCK status
+ */
+static enum stb0899_status stb0899_dvbs2_get_fec_status(struct stb0899_state *state, int timeout)
+{
+       int time = 0, Locked;
+
+       do {
+               Locked = stb0899_dvbs2_get_data_lock(state, 1);
+               time++;
+               msleep(1);
+
+       } while ((!Locked) && (time < timeout));
+
+       if (Locked) {
+               dprintk(state->verbose, FE_DEBUG, 1, "---------->DVB-S2 FEC LOCK !");
+               return DVBS2_FEC_LOCK;
+       } else {
+               return DVBS2_FEC_NOLOCK;
+       }
+}
+
+
+/*
+ * stb0899_dvbs2_init_csm
+ * set parameters for manual mode
+ */
+static void stb0899_dvbs2_init_csm(struct stb0899_state *state, int pilots, enum stb0899_modcod modcod)
+{
+       struct stb0899_internal *internal = &state->internal;
+
+       s32 dvt_tbl = 1, two_pass = 0, agc_gain = 6, agc_shift = 0, loop_shift = 0, phs_diff_thr = 0x80;
+       s32 gamma_acq, gamma_rho_acq, gamma_trk, gamma_rho_trk, lock_count_thr;
+       u32 csm1, csm2, csm3, csm4;
+
+       if (((internal->master_clk / internal->srate) <= 4) && (modcod <= 11) && (pilots == 1)) {
+               switch (modcod) {
+               case STB0899_QPSK_12:
+                       gamma_acq               = 25;
+                       gamma_rho_acq           = 2700;
+                       gamma_trk               = 12;
+                       gamma_rho_trk           = 180;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_35:
+                       gamma_acq               = 38;
+                       gamma_rho_acq           = 7182;
+                       gamma_trk               = 14;
+                       gamma_rho_trk           = 308;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_23:
+                       gamma_acq               = 42;
+                       gamma_rho_acq           = 9408;
+                       gamma_trk               = 17;
+                       gamma_rho_trk           = 476;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_34:
+                       gamma_acq               = 53;
+                       gamma_rho_acq           = 16642;
+                       gamma_trk               = 19;
+                       gamma_rho_trk           = 646;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_45:
+                       gamma_acq               = 53;
+                       gamma_rho_acq           = 17119;
+                       gamma_trk               = 22;
+                       gamma_rho_trk           = 880;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_56:
+                       gamma_acq               = 55;
+                       gamma_rho_acq           = 19250;
+                       gamma_trk               = 23;
+                       gamma_rho_trk           = 989;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_89:
+                       gamma_acq               = 60;
+                       gamma_rho_acq           = 24240;
+                       gamma_trk               = 24;
+                       gamma_rho_trk           = 1176;
+                       lock_count_thr          = 8;
+                       break;
+               case STB0899_QPSK_910:
+                       gamma_acq               = 66;
+                       gamma_rho_acq           = 29634;
+                       gamma_trk               = 24;
+                       gamma_rho_trk           = 1176;
+                       lock_count_thr          = 8;
+                       break;
+               default:
+                       gamma_acq               = 66;
+                       gamma_rho_acq           = 29634;
+                       gamma_trk               = 24;
+                       gamma_rho_trk           = 1176;
+                       lock_count_thr          = 8;
+                       break;
+               }
+
+               csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+               STB0899_SETFIELD_VAL(CSM_AUTO_PARAM, csm1, 0);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+
+               csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+               csm2 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL2);
+               csm3 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL3);
+               csm4 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL4);
+
+               STB0899_SETFIELD_VAL(CSM_DVT_TABLE, csm1, dvt_tbl);
+               STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, two_pass);
+               STB0899_SETFIELD_VAL(CSM_AGC_GAIN, csm1, agc_gain);
+               STB0899_SETFIELD_VAL(CSM_AGC_SHIFT, csm1, agc_shift);
+               STB0899_SETFIELD_VAL(FE_LOOP_SHIFT, csm1, loop_shift);
+               STB0899_SETFIELD_VAL(CSM_GAMMA_ACQ, csm2, gamma_acq);
+               STB0899_SETFIELD_VAL(CSM_GAMMA_RHOACQ, csm2, gamma_rho_acq);
+               STB0899_SETFIELD_VAL(CSM_GAMMA_TRACK, csm3, gamma_trk);
+               STB0899_SETFIELD_VAL(CSM_GAMMA_RHOTRACK, csm3, gamma_rho_trk);
+               STB0899_SETFIELD_VAL(CSM_LOCKCOUNT_THRESH, csm4, lock_count_thr);
+               STB0899_SETFIELD_VAL(CSM_PHASEDIFF_THRESH, csm4, phs_diff_thr);
+
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL2, STB0899_OFF0_CSM_CNTRL2, csm2);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL3, STB0899_OFF0_CSM_CNTRL3, csm3);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL4, STB0899_OFF0_CSM_CNTRL4, csm4);
+       }
+}
+
+/*
+ * stb0899_dvbs2_get_srate
+ * get DVB-S2 Symbol Rate
+ */
+static u32 stb0899_dvbs2_get_srate(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_config *config = state->config;
+
+       u32 bTrNomFreq, srate, decimRate, intval1, intval2, reg;
+       int div1, div2, rem1, rem2;
+
+       div1 = config->btr_nco_bits / 2;
+       div2 = config->btr_nco_bits - div1 - 1;
+
+       bTrNomFreq = STB0899_READ_S2REG(STB0899_S2DEMOD, BTR_NOM_FREQ);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DECIM_CNTRL);
+       decimRate = STB0899_GETFIELD(DECIM_RATE, reg);
+       decimRate = (1 << decimRate);
+
+       intval1 = internal->master_clk / (1 << div1);
+       intval2 = bTrNomFreq / (1 << div2);
+
+       rem1 = internal->master_clk % (1 << div1);
+       rem2 = bTrNomFreq % (1 << div2);
+       /* only for integer calculation */
+       srate = (intval1 * intval2) + ((intval1 * rem2) / (1 << div2)) + ((intval2 * rem1) / (1 << div1));
+       srate /= decimRate;     /*symbrate = (btrnomfreq_register_val*MasterClock)/2^(27+decim_rate_field) */
+
+       return  srate;
+}
+
+/*
+ * stb0899_dvbs2_algo
+ * Search for signal, timing, carrier and data for a given
+ * frequency in a given range
+ */
+enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       enum stb0899_modcod modcod;
+
+       s32 offsetfreq, searchTime, FecLockTime, pilots, iqSpectrum;
+       int i = 0;
+       u32 reg, csm1;
+
+       if (internal->srate <= 2000000) {
+               searchTime      = 5000; /* 5000 ms max time to lock UWP and CSM, SYMB <= 2Mbs           */
+               FecLockTime     = 350;  /* 350  ms max time to lock FEC, SYMB <= 2Mbs                   */
+       } else if (internal->srate <= 5000000) {
+               searchTime      = 2500; /* 2500 ms max time to lock UWP and CSM, 2Mbs < SYMB <= 5Mbs    */
+               FecLockTime     = 170;  /* 170  ms max time to lock FEC, 2Mbs< SYMB <= 5Mbs             */
+       } else if (internal->srate <= 10000000) {
+               searchTime      = 1500; /* 1500 ms max time to lock UWP and CSM, 5Mbs <SYMB <= 10Mbs    */
+               FecLockTime     = 80;   /* 80  ms max time to lock FEC, 5Mbs< SYMB <= 10Mbs             */
+       } else if (internal->srate <= 15000000) {
+               searchTime      = 500;  /* 500 ms max time to lock UWP and CSM, 10Mbs <SYMB <= 15Mbs    */
+               FecLockTime     = 50;   /* 50  ms max time to lock FEC, 10Mbs< SYMB <= 15Mbs            */
+       } else if (internal->srate <= 20000000) {
+               searchTime      = 300;  /* 300 ms max time to lock UWP and CSM, 15Mbs < SYMB <= 20Mbs   */
+               FecLockTime     = 30;   /* 50  ms max time to lock FEC, 15Mbs< SYMB <= 20Mbs            */
+       } else if (internal->srate <= 25000000) {
+               searchTime      = 250;  /* 250 ms max time to lock UWP and CSM, 20 Mbs < SYMB <= 25Mbs  */
+               FecLockTime     = 25;   /* 25 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs             */
+       } else {
+               searchTime      = 150;  /* 150 ms max time to lock UWP and CSM, SYMB > 25Mbs            */
+               FecLockTime     = 20;   /* 20 ms max time to lock FEC, 20Mbs< SYMB <= 25Mbs             */
+       }
+
+       /* Maintain Stream Merger in reset during acquisition   */
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESRS, reg, 1);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+       /* enable tuner I/O */
+       stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+       /* Move tuner to frequency      */
+       if (state->config->tuner_set_frequency)
+               state->config->tuner_set_frequency(&state->frontend, internal->freq);
+       if (state->config->tuner_get_frequency)
+               state->config->tuner_get_frequency(&state->frontend, &internal->freq);
+
+       /* disable tuner I/O */
+       stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+       /* Set IF AGC to acquisition    */
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
+       STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  4);
+       STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 32);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
+       STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 0);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
+
+       /* Initialisation       */
+       stb0899_dvbs2_init_calc(state);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+       switch (internal->inversion) {
+       case IQ_SWAP_OFF:
+               STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 0);
+               break;
+       case IQ_SWAP_ON:
+               STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
+               break;
+       case IQ_SWAP_AUTO:      /* use last successful search first     */
+               STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, 1);
+               break;
+       }
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
+       stb0899_dvbs2_reacquire(state);
+
+       /* Wait for demod lock (UWP and CSM)    */
+       internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
+
+       if (internal->status == DVBS2_DEMOD_LOCK) {
+               dprintk(state->verbose, FE_DEBUG, 1, "------------> DVB-S2 DEMOD LOCK !");
+               i = 0;
+               /* Demod Locked, check FEC status       */
+               internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+
+               /*If false lock (UWP and CSM Locked but no FEC) try 3 time max*/
+               while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+                       /*      Read the frequency offset*/
+                       offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+
+                       /* Set the Nominal frequency to the found frequency offset for the next reacquire*/
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+                       STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
+                       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+                       stb0899_dvbs2_reacquire(state);
+                       internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
+                       i++;
+               }
+       }
+
+       if (internal->status != DVBS2_FEC_LOCK) {
+               if (internal->inversion == IQ_SWAP_AUTO) {
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+                       iqSpectrum = STB0899_GETFIELD(SPECTRUM_INVERT, reg);
+                       /* IQ Spectrum Inversion        */
+                       STB0899_SETFIELD_VAL(SPECTRUM_INVERT, reg, !iqSpectrum);
+                       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_DMD_CNTRL2, STB0899_OFF0_DMD_CNTRL2, reg);
+                       /* start acquistion process     */
+                       stb0899_dvbs2_reacquire(state);
+
+                       /* Wait for demod lock (UWP and CSM)    */
+                       internal->status = stb0899_dvbs2_get_dmd_status(state, searchTime);
+                       if (internal->status == DVBS2_DEMOD_LOCK) {
+                               i = 0;
+                               /* Demod Locked, check FEC      */
+                               internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+                               /*try thrice for false locks, (UWP and CSM Locked but no FEC)   */
+                               while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+                                       /*      Read the frequency offset*/
+                                       offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+
+                                       /* Set the Nominal frequency to the found frequency offset for the next reacquire*/
+                                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_NOM_FREQ);
+                                       STB0899_SETFIELD_VAL(CRL_NOM_FREQ, reg, offsetfreq);
+                                       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CRL_NOM_FREQ, STB0899_OFF0_CRL_NOM_FREQ, reg);
+
+                                       stb0899_dvbs2_reacquire(state);
+                                       internal->status = stb0899_dvbs2_get_fec_status(state, searchTime);
+                                       i++;
+                               }
+                       }
+/*
+                       if (pParams->DVBS2State == FE_DVBS2_FEC_LOCKED)
+                               pParams->IQLocked = !iqSpectrum;
+*/
+               }
+       }
+       if (internal->status == DVBS2_FEC_LOCK) {
+               dprintk(state->verbose, FE_DEBUG, 1, "----------------> DVB-S2 FEC Lock !");
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
+               modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
+               pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
+
+               if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
+                     (INRANGE(STB0899_QPSK_23, modcod, STB0899_QPSK_910)) &&
+                     (pilots == 1)) {
+
+                       stb0899_dvbs2_init_csm(state, pilots, modcod);
+                       /* Wait for UWP,CSM and data LOCK 20ms max      */
+                       internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+
+                       i = 0;
+                       while ((internal->status != DVBS2_FEC_LOCK) && (i < 3)) {
+                               csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+                               STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 1);
+                               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+                               csm1 = STB0899_READ_S2REG(STB0899_S2DEMOD, CSM_CNTRL1);
+                               STB0899_SETFIELD_VAL(CSM_TWO_PASS, csm1, 0);
+                               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, csm1);
+
+                               internal->status = stb0899_dvbs2_get_fec_status(state, FecLockTime);
+                               i++;
+                       }
+               }
+
+               if ((((10 * internal->master_clk) / (internal->srate / 10)) <= 410) &&
+                     (INRANGE(STB0899_QPSK_12, modcod, STB0899_QPSK_35)) &&
+                     (pilots == 1)) {
+
+                       /* Equalizer Disable update      */
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+                       STB0899_SETFIELD_VAL(EQ_DISABLE_UPDATE, reg, 1);
+                       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+               }
+
+               /* slow down the Equalizer once locked  */
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, EQ_CNTRL);
+               STB0899_SETFIELD_VAL(EQ_SHIFT, reg, 0x02);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_EQ_CNTRL, STB0899_OFF0_EQ_CNTRL, reg);
+
+               /* Store signal parameters      */
+               offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
+
+               offsetfreq = offsetfreq / ((1 << 30) / 1000);
+               offsetfreq *= (internal->master_clk / 1000000);
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CNTRL2);
+               if (STB0899_GETFIELD(SPECTRUM_INVERT, reg))
+                       offsetfreq *= -1;
+
+               internal->freq = internal->freq - offsetfreq;
+               internal->srate = stb0899_dvbs2_get_srate(state);
+
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
+               internal->modcod = STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 2;
+               internal->pilots = STB0899_GETFIELD(UWP_DECODE_MOD, reg) & 0x01;
+               internal->frame_length = (STB0899_GETFIELD(UWP_DECODE_MOD, reg) >> 1) & 0x01;
+
+                /* Set IF AGC to tracking      */
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
+               STB0899_SETFIELD_VAL(IF_LOOP_GAIN, reg,  3);
+
+               /* if QPSK 1/2,QPSK 3/5 or QPSK 2/3 set IF AGC reference to 16 otherwise 32*/
+               if (INRANGE(STB0899_QPSK_12, internal->modcod, STB0899_QPSK_23))
+                       STB0899_SETFIELD_VAL(IF_AGC_REF, reg, 16);
+
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
+
+               reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL2);
+               STB0899_SETFIELD_VAL(IF_AGC_DUMP_PER, reg, 7);
+               stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL2, STB0899_OFF0_IF_AGC_CNTRL2, reg);
+       }
+
+       /* Release Stream Merger Reset          */
+       reg = stb0899_read_reg(state, STB0899_TSTRES);
+       STB0899_SETFIELD_VAL(FRESRS, reg, 0);
+       stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+       return internal->status;
+}
diff --git a/drivers/media/dvb/frontends/stb0899_cfg.h b/drivers/media/dvb/frontends/stb0899_cfg.h
new file mode 100644 (file)
index 0000000..0867906
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+       STB0899 Multistandard Frontend driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#ifndef __STB0899_CFG_H
+#define __STB0899_CFG_H
+
+static const struct stb0899_s2_reg  stb0899_s2_init_2[] = {
+
+       { STB0899_OFF0_DMD_STATUS       , STB0899_BASE_DMD_STATUS       , 0x00000103 }, /* DMDSTATUS    */
+       { STB0899_OFF0_CRL_FREQ         , STB0899_BASE_CRL_FREQ         , 0x3ed1da56 }, /* CRLFREQ      */
+       { STB0899_OFF0_BTR_FREQ         , STB0899_BASE_BTR_FREQ         , 0x00004000 }, /* BTRFREQ      */
+       { STB0899_OFF0_IF_AGC_GAIN      , STB0899_BASE_IF_AGC_GAIN      , 0x00002ade }, /* IFAGCGAIN    */
+       { STB0899_OFF0_BB_AGC_GAIN      , STB0899_BASE_BB_AGC_GAIN      , 0x000001bc }, /* BBAGCGAIN    */
+       { STB0899_OFF0_DC_OFFSET        , STB0899_BASE_DC_OFFSET        , 0x00000200 }, /* DCOFFSET     */
+       { STB0899_OFF0_DMD_CNTRL        , STB0899_BASE_DMD_CNTRL        , 0x0000000f }, /* DMDCNTRL     */
+
+       { STB0899_OFF0_IF_AGC_CNTRL     , STB0899_BASE_IF_AGC_CNTRL     , 0x03fb4a20 }, /* IFAGCCNTRL   */
+       { STB0899_OFF0_BB_AGC_CNTRL     , STB0899_BASE_BB_AGC_CNTRL     , 0x00200c97 }, /* BBAGCCNTRL   */
+
+       { STB0899_OFF0_CRL_CNTRL        , STB0899_BASE_CRL_CNTRL        , 0x00000016 }, /* CRLCNTRL     */
+       { STB0899_OFF0_CRL_PHS_INIT     , STB0899_BASE_CRL_PHS_INIT     , 0x00000000 }, /* CRLPHSINIT   */
+       { STB0899_OFF0_CRL_FREQ_INIT    , STB0899_BASE_CRL_FREQ_INIT    , 0x00000000 }, /* CRLFREQINIT  */
+       { STB0899_OFF0_CRL_LOOP_GAIN    , STB0899_BASE_CRL_LOOP_GAIN    , 0x00000000 }, /* CRLLOOPGAIN  */
+       { STB0899_OFF0_CRL_NOM_FREQ     , STB0899_BASE_CRL_NOM_FREQ     , 0x3ed097b6 }, /* CRLNOMFREQ   */
+       { STB0899_OFF0_CRL_SWP_RATE     , STB0899_BASE_CRL_SWP_RATE     , 0x00000000 }, /* CRLSWPRATE   */
+       { STB0899_OFF0_CRL_MAX_SWP      , STB0899_BASE_CRL_MAX_SWP      , 0x00000000 }, /* CRLMAXSWP    */
+       { STB0899_OFF0_CRL_LK_CNTRL     , STB0899_BASE_CRL_LK_CNTRL     , 0x0f6cdc01 }, /* CRLLKCNTRL   */
+       { STB0899_OFF0_DECIM_CNTRL      , STB0899_BASE_DECIM_CNTRL      , 0x00000000 }, /* DECIMCNTRL   */
+       { STB0899_OFF0_BTR_CNTRL        , STB0899_BASE_BTR_CNTRL        , 0x00003993 }, /* BTRCNTRL     */
+       { STB0899_OFF0_BTR_LOOP_GAIN    , STB0899_BASE_BTR_LOOP_GAIN    , 0x000d3c6f }, /* BTRLOOPGAIN  */
+       { STB0899_OFF0_BTR_PHS_INIT     , STB0899_BASE_BTR_PHS_INIT     , 0x00000000 }, /* BTRPHSINIT   */
+       { STB0899_OFF0_BTR_FREQ_INIT    , STB0899_BASE_BTR_FREQ_INIT    , 0x00000000 }, /* BTRFREQINIT  */
+       { STB0899_OFF0_BTR_NOM_FREQ     , STB0899_BASE_BTR_NOM_FREQ     , 0x0238e38e }, /* BTRNOMFREQ   */
+       { STB0899_OFF0_BTR_LK_CNTRL     , STB0899_BASE_BTR_LK_CNTRL     , 0x00000000 }, /* BTRLKCNTRL   */
+       { STB0899_OFF0_DECN_CNTRL       , STB0899_BASE_DECN_CNTRL       , 0x00000000 }, /* DECNCNTRL    */
+       { STB0899_OFF0_TP_CNTRL         , STB0899_BASE_TP_CNTRL         , 0x00000000 }, /* TPCNTRL      */
+       { STB0899_OFF0_TP_BUF_STATUS    , STB0899_BASE_TP_BUF_STATUS    , 0x00000000 }, /* TPBUFSTATUS  */
+       { STB0899_OFF0_DC_ESTIM         , STB0899_BASE_DC_ESTIM         , 0x00000000 }, /* DCESTIM      */
+       { STB0899_OFF0_FLL_CNTRL        , STB0899_BASE_FLL_CNTRL        , 0x00000000 }, /* FLLCNTRL     */
+       { STB0899_OFF0_FLL_FREQ_WD      , STB0899_BASE_FLL_FREQ_WD      , 0x40070000 }, /* FLLFREQWD    */
+       { STB0899_OFF0_ANTI_ALIAS_SEL   , STB0899_BASE_ANTI_ALIAS_SEL   , 0x00000001 }, /* ANTIALIASSEL */
+       { STB0899_OFF0_RRC_ALPHA        , STB0899_BASE_RRC_ALPHA        , 0x00000002 }, /* RRCALPHA     */
+       { STB0899_OFF0_DC_ADAPT_LSHFT   , STB0899_BASE_DC_ADAPT_LSHFT   , 0x00000000 }, /* DCADAPTISHFT */
+       { STB0899_OFF0_IMB_OFFSET       , STB0899_BASE_IMB_OFFSET       , 0x0000fe01 }, /* IMBOFFSET    */
+       { STB0899_OFF0_IMB_ESTIMATE     , STB0899_BASE_IMB_ESTIMATE     , 0x00000000 }, /* IMBESTIMATE  */
+       { STB0899_OFF0_IMB_CNTRL        , STB0899_BASE_IMB_CNTRL        , 0x00000001 }, /* IMBCNTRL     */
+       { STB0899_OFF0_IF_AGC_CNTRL2    , STB0899_BASE_IF_AGC_CNTRL2    , 0x00005007 }, /* IFAGCCNTRL2  */
+       { STB0899_OFF0_DMD_CNTRL2       , STB0899_BASE_DMD_CNTRL2       , 0x00000002 }, /* DMDCNTRL2    */
+       { STB0899_OFF0_TP_BUFFER        , STB0899_BASE_TP_BUFFER        , 0x00000000 }, /* TPBUFFER     */
+       { STB0899_OFF0_TP_BUFFER1       , STB0899_BASE_TP_BUFFER1       , 0x00000000 }, /* TPBUFFER1    */
+       { STB0899_OFF0_TP_BUFFER2       , STB0899_BASE_TP_BUFFER2       , 0x00000000 }, /* TPBUFFER2    */
+       { STB0899_OFF0_TP_BUFFER3       , STB0899_BASE_TP_BUFFER3       , 0x00000000 }, /* TPBUFFER3    */
+       { STB0899_OFF0_TP_BUFFER4       , STB0899_BASE_TP_BUFFER4       , 0x00000000 }, /* TPBUFFER4    */
+       { STB0899_OFF0_TP_BUFFER5       , STB0899_BASE_TP_BUFFER5       , 0x00000000 }, /* TPBUFFER5    */
+       { STB0899_OFF0_TP_BUFFER6       , STB0899_BASE_TP_BUFFER6       , 0x00000000 }, /* TPBUFFER6    */
+       { STB0899_OFF0_TP_BUFFER7       , STB0899_BASE_TP_BUFFER7       , 0x00000000 }, /* TPBUFFER7    */
+       { STB0899_OFF0_TP_BUFFER8       , STB0899_BASE_TP_BUFFER8       , 0x00000000 }, /* TPBUFFER8    */
+       { STB0899_OFF0_TP_BUFFER9       , STB0899_BASE_TP_BUFFER9       , 0x00000000 }, /* TPBUFFER9    */
+       { STB0899_OFF0_TP_BUFFER10      , STB0899_BASE_TP_BUFFER10      , 0x00000000 }, /* TPBUFFER10   */
+       { STB0899_OFF0_TP_BUFFER11      , STB0899_BASE_TP_BUFFER11      , 0x00000000 }, /* TPBUFFER11   */
+       { STB0899_OFF0_TP_BUFFER12      , STB0899_BASE_TP_BUFFER12      , 0x00000000 }, /* TPBUFFER12   */
+       { STB0899_OFF0_TP_BUFFER13      , STB0899_BASE_TP_BUFFER13      , 0x00000000 }, /* TPBUFFER13   */
+       { STB0899_OFF0_TP_BUFFER14      , STB0899_BASE_TP_BUFFER14      , 0x00000000 }, /* TPBUFFER14   */
+       { STB0899_OFF0_TP_BUFFER15      , STB0899_BASE_TP_BUFFER15      , 0x00000000 }, /* TPBUFFER15   */
+       { STB0899_OFF0_TP_BUFFER16      , STB0899_BASE_TP_BUFFER16      , 0x0000ff00 }, /* TPBUFFER16   */
+       { STB0899_OFF0_TP_BUFFER17      , STB0899_BASE_TP_BUFFER17      , 0x00000100 }, /* TPBUFFER17   */
+       { STB0899_OFF0_TP_BUFFER18      , STB0899_BASE_TP_BUFFER18      , 0x0000fe01 }, /* TPBUFFER18   */
+       { STB0899_OFF0_TP_BUFFER19      , STB0899_BASE_TP_BUFFER19      , 0x000004fe }, /* TPBUFFER19   */
+       { STB0899_OFF0_TP_BUFFER20      , STB0899_BASE_TP_BUFFER20      , 0x0000cfe7 }, /* TPBUFFER20   */
+       { STB0899_OFF0_TP_BUFFER21      , STB0899_BASE_TP_BUFFER21      , 0x0000bec6 }, /* TPBUFFER21   */
+       { STB0899_OFF0_TP_BUFFER22      , STB0899_BASE_TP_BUFFER22      , 0x0000c2bf }, /* TPBUFFER22   */
+       { STB0899_OFF0_TP_BUFFER23      , STB0899_BASE_TP_BUFFER23      , 0x0000c1c1 }, /* TPBUFFER23   */
+       { STB0899_OFF0_TP_BUFFER24      , STB0899_BASE_TP_BUFFER24      , 0x0000c1c1 }, /* TPBUFFER24   */
+       { STB0899_OFF0_TP_BUFFER25      , STB0899_BASE_TP_BUFFER25      , 0x0000c1c1 }, /* TPBUFFER25   */
+       { STB0899_OFF0_TP_BUFFER26      , STB0899_BASE_TP_BUFFER26      , 0x0000c1c1 }, /* TPBUFFER26   */
+       { STB0899_OFF0_TP_BUFFER27      , STB0899_BASE_TP_BUFFER27      , 0x0000c1c0 }, /* TPBUFFER27   */
+       { STB0899_OFF0_TP_BUFFER28      , STB0899_BASE_TP_BUFFER28      , 0x0000c0c0 }, /* TPBUFFER28   */
+       { STB0899_OFF0_TP_BUFFER29      , STB0899_BASE_TP_BUFFER29      , 0x0000c1c1 }, /* TPBUFFER29   */
+       { STB0899_OFF0_TP_BUFFER30      , STB0899_BASE_TP_BUFFER30      , 0x0000c1c1 }, /* TPBUFFER30   */
+       { STB0899_OFF0_TP_BUFFER31      , STB0899_BASE_TP_BUFFER31      , 0x0000c0c1 }, /* TPBUFFER31   */
+       { STB0899_OFF0_TP_BUFFER32      , STB0899_BASE_TP_BUFFER32      , 0x0000c0c1 }, /* TPBUFFER32   */
+       { STB0899_OFF0_TP_BUFFER33      , STB0899_BASE_TP_BUFFER33      , 0x0000c1c1 }, /* TPBUFFER33   */
+       { STB0899_OFF0_TP_BUFFER34      , STB0899_BASE_TP_BUFFER34      , 0x0000c1c1 }, /* TPBUFFER34   */
+       { STB0899_OFF0_TP_BUFFER35      , STB0899_BASE_TP_BUFFER35      , 0x0000c0c1 }, /* TPBUFFER35   */
+       { STB0899_OFF0_TP_BUFFER36      , STB0899_BASE_TP_BUFFER36      , 0x0000c1c1 }, /* TPBUFFER36   */
+       { STB0899_OFF0_TP_BUFFER37      , STB0899_BASE_TP_BUFFER37      , 0x0000c0c1 }, /* TPBUFFER37   */
+       { STB0899_OFF0_TP_BUFFER38      , STB0899_BASE_TP_BUFFER38      , 0x0000c1c1 }, /* TPBUFFER38   */
+       { STB0899_OFF0_TP_BUFFER39      , STB0899_BASE_TP_BUFFER39      , 0x0000c0c0 }, /* TPBUFFER39   */
+       { STB0899_OFF0_TP_BUFFER40      , STB0899_BASE_TP_BUFFER40      , 0x0000c1c0 }, /* TPBUFFER40   */
+       { STB0899_OFF0_TP_BUFFER41      , STB0899_BASE_TP_BUFFER41      , 0x0000c1c1 }, /* TPBUFFER41   */
+       { STB0899_OFF0_TP_BUFFER42      , STB0899_BASE_TP_BUFFER42      , 0x0000c0c0 }, /* TPBUFFER42   */
+       { STB0899_OFF0_TP_BUFFER43      , STB0899_BASE_TP_BUFFER43      , 0x0000c1c0 }, /* TPBUFFER43   */
+       { STB0899_OFF0_TP_BUFFER44      , STB0899_BASE_TP_BUFFER44      , 0x0000c0c1 }, /* TPBUFFER44   */
+       { STB0899_OFF0_TP_BUFFER45      , STB0899_BASE_TP_BUFFER45      , 0x0000c1be }, /* TPBUFFER45   */
+       { STB0899_OFF0_TP_BUFFER46      , STB0899_BASE_TP_BUFFER46      , 0x0000c1c9 }, /* TPBUFFER46   */
+       { STB0899_OFF0_TP_BUFFER47      , STB0899_BASE_TP_BUFFER47      , 0x0000c0da }, /* TPBUFFER47   */
+       { STB0899_OFF0_TP_BUFFER48      , STB0899_BASE_TP_BUFFER48      , 0x0000c0ba }, /* TPBUFFER48   */
+       { STB0899_OFF0_TP_BUFFER49      , STB0899_BASE_TP_BUFFER49      , 0x0000c1c4 }, /* TPBUFFER49   */
+       { STB0899_OFF0_TP_BUFFER50      , STB0899_BASE_TP_BUFFER50      , 0x0000c1bf }, /* TPBUFFER50   */
+       { STB0899_OFF0_TP_BUFFER51      , STB0899_BASE_TP_BUFFER51      , 0x0000c0c1 }, /* TPBUFFER51   */
+       { STB0899_OFF0_TP_BUFFER52      , STB0899_BASE_TP_BUFFER52      , 0x0000c1c0 }, /* TPBUFFER52   */
+       { STB0899_OFF0_TP_BUFFER53      , STB0899_BASE_TP_BUFFER53      , 0x0000c0c1 }, /* TPBUFFER53   */
+       { STB0899_OFF0_TP_BUFFER54      , STB0899_BASE_TP_BUFFER54      , 0x0000c1c1 }, /* TPBUFFER54   */
+       { STB0899_OFF0_TP_BUFFER55      , STB0899_BASE_TP_BUFFER55      , 0x0000c1c1 }, /* TPBUFFER55   */
+       { STB0899_OFF0_TP_BUFFER56      , STB0899_BASE_TP_BUFFER56      , 0x0000c1c1 }, /* TPBUFFER56   */
+       { STB0899_OFF0_TP_BUFFER57      , STB0899_BASE_TP_BUFFER57      , 0x0000c1c1 }, /* TPBUFFER57   */
+       { STB0899_OFF0_TP_BUFFER58      , STB0899_BASE_TP_BUFFER58      , 0x0000c1c1 }, /* TPBUFFER58   */
+       { STB0899_OFF0_TP_BUFFER59      , STB0899_BASE_TP_BUFFER59      , 0x0000c1c1 }, /* TPBUFFER59   */
+       { STB0899_OFF0_TP_BUFFER60      , STB0899_BASE_TP_BUFFER60      , 0x0000c1c1 }, /* TPBUFFER60   */
+       { STB0899_OFF0_TP_BUFFER61      , STB0899_BASE_TP_BUFFER61      , 0x0000c1c1 }, /* TPBUFFER61   */
+       { STB0899_OFF0_TP_BUFFER62      , STB0899_BASE_TP_BUFFER62      , 0x0000c1c1 }, /* TPBUFFER62   */
+       { STB0899_OFF0_TP_BUFFER63      , STB0899_BASE_TP_BUFFER63      , 0x0000c1c0 }, /* TPBUFFER63   */
+       { STB0899_OFF0_RESET_CNTRL      , STB0899_BASE_RESET_CNTRL      , 0x00000001 }, /* RESETCNTRL   */
+       { STB0899_OFF0_ACM_ENABLE       , STB0899_BASE_ACM_ENABLE       , 0x00005654 }, /* ACMENABLE    */
+       { STB0899_OFF0_DESCR_CNTRL      , STB0899_BASE_DESCR_CNTRL      , 0x00000000 }, /* DESCRCNTRL   */
+       { STB0899_OFF0_CSM_CNTRL1       , STB0899_BASE_CSM_CNTRL1       , 0x00020019 }, /* CSMCNTRL1    */
+       { STB0899_OFF0_CSM_CNTRL2       , STB0899_BASE_CSM_CNTRL2       , 0x004b3237 }, /* CSMCNTRL2    */
+       { STB0899_OFF0_CSM_CNTRL3       , STB0899_BASE_CSM_CNTRL3       , 0x0003dd17 }, /* CSMCNTRL3    */
+       { STB0899_OFF0_CSM_CNTRL4       , STB0899_BASE_CSM_CNTRL4       , 0x00008008 }, /* CSMCNTRL4    */
+       { STB0899_OFF0_UWP_CNTRL1       , STB0899_BASE_UWP_CNTRL1       , 0x002a3106 }, /* UWPCNTRL1    */
+       { STB0899_OFF0_UWP_CNTRL2       , STB0899_BASE_UWP_CNTRL2       , 0x0006140a }, /* UWPCNTRL2    */
+       { STB0899_OFF0_UWP_STAT1        , STB0899_BASE_UWP_STAT1        , 0x00008000 }, /* UWPSTAT1     */
+       { STB0899_OFF0_UWP_STAT2        , STB0899_BASE_UWP_STAT2        , 0x00000000 }, /* UWPSTAT2     */
+       { STB0899_OFF0_DMD_STAT2        , STB0899_BASE_DMD_STAT2        , 0x00000000 }, /* DMDSTAT2     */
+       { STB0899_OFF0_FREQ_ADJ_SCALE   , STB0899_BASE_FREQ_ADJ_SCALE   , 0x00000471 }, /* FREQADJSCALE */
+       { STB0899_OFF0_UWP_CNTRL3       , STB0899_BASE_UWP_CNTRL3       , 0x017b0465 }, /* UWPCNTRL3    */
+       { STB0899_OFF0_SYM_CLK_SEL      , STB0899_BASE_SYM_CLK_SEL      , 0x00000002 }, /* SYMCLKSEL    */
+       { STB0899_OFF0_SOF_SRCH_TO      , STB0899_BASE_SOF_SRCH_TO      , 0x00196464 }, /* SOFSRCHTO    */
+       { STB0899_OFF0_ACQ_CNTRL1       , STB0899_BASE_ACQ_CNTRL1       , 0x00000603 }, /* ACQCNTRL1    */
+       { STB0899_OFF0_ACQ_CNTRL2       , STB0899_BASE_ACQ_CNTRL2       , 0x02046666 }, /* ACQCNTRL2    */
+       { STB0899_OFF0_ACQ_CNTRL3       , STB0899_BASE_ACQ_CNTRL3       , 0x10046583 }, /* ACQCNTRL3    */
+       { STB0899_OFF0_FE_SETTLE        , STB0899_BASE_FE_SETTLE        , 0x00010404 }, /* FESETTLE     */
+       { STB0899_OFF0_AC_DWELL         , STB0899_BASE_AC_DWELL         , 0x0002aa8a }, /* ACDWELL      */
+       { STB0899_OFF0_ACQUIRE_TRIG     , STB0899_BASE_ACQUIRE_TRIG     , 0x00000000 }, /* ACQUIRETRIG  */
+       { STB0899_OFF0_LOCK_LOST        , STB0899_BASE_LOCK_LOST        , 0x00000001 }, /* LOCKLOST     */
+       { STB0899_OFF0_ACQ_STAT1        , STB0899_BASE_ACQ_STAT1        , 0x00000500 }, /* ACQSTAT1     */
+       { STB0899_OFF0_ACQ_TIMEOUT      , STB0899_BASE_ACQ_TIMEOUT      , 0x0028a0a0 }, /* ACQTIMEOUT   */
+       { STB0899_OFF0_ACQ_TIME         , STB0899_BASE_ACQ_TIME         , 0x00000000 }, /* ACQTIME      */
+       { STB0899_OFF0_FINAL_AGC_CNTRL  , STB0899_BASE_FINAL_AGC_CNTRL  , 0x00800c17 }, /* FINALAGCCNTRL*/
+       { STB0899_OFF0_FINAL_AGC_GAIN   , STB0899_BASE_FINAL_AGC_GAIN   , 0x00000000 }, /* FINALAGCCGAIN*/
+       { STB0899_OFF0_EQUALIZER_INIT   , STB0899_BASE_EQUALIZER_INIT   , 0x00000000 }, /* EQUILIZERINIT*/
+       { STB0899_OFF0_EQ_CNTRL         , STB0899_BASE_EQ_CNTRL         , 0x00054802 }, /* EQCNTL       */
+       { STB0899_OFF0_EQ_I_INIT_COEFF_0, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF0 */
+       { STB0899_OFF1_EQ_I_INIT_COEFF_1, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF1 */
+       { STB0899_OFF2_EQ_I_INIT_COEFF_2, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF2 */
+       { STB0899_OFF3_EQ_I_INIT_COEFF_3, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF3 */
+       { STB0899_OFF4_EQ_I_INIT_COEFF_4, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF4 */
+       { STB0899_OFF5_EQ_I_INIT_COEFF_5, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000400 }, /* EQIINITCOEFF5 */
+       { STB0899_OFF6_EQ_I_INIT_COEFF_6, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF6 */
+       { STB0899_OFF7_EQ_I_INIT_COEFF_7, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF7 */
+       { STB0899_OFF8_EQ_I_INIT_COEFF_8, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF8 */
+       { STB0899_OFF9_EQ_I_INIT_COEFF_9, STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF9 */
+       { STB0899_OFFa_EQ_I_INIT_COEFF_10,STB0899_BASE_EQ_I_INIT_COEFF_N, 0x00000000 }, /* EQIINITCOEFF10*/
+       { STB0899_OFF0_EQ_Q_INIT_COEFF_0, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF0 */
+       { STB0899_OFF1_EQ_Q_INIT_COEFF_1, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF1 */
+       { STB0899_OFF2_EQ_Q_INIT_COEFF_2, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF2 */
+       { STB0899_OFF3_EQ_Q_INIT_COEFF_3, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF3 */
+       { STB0899_OFF4_EQ_Q_INIT_COEFF_4, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF4 */
+       { STB0899_OFF5_EQ_Q_INIT_COEFF_5, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF5 */
+       { STB0899_OFF6_EQ_Q_INIT_COEFF_6, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF6 */
+       { STB0899_OFF7_EQ_Q_INIT_COEFF_7, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF7 */
+       { STB0899_OFF8_EQ_Q_INIT_COEFF_8, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF8 */
+       { STB0899_OFF9_EQ_Q_INIT_COEFF_9, STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF9 */
+       { STB0899_OFFa_EQ_Q_INIT_COEFF_10,STB0899_BASE_EQ_Q_INIT_COEFF_N, 0x00000000 }, /* EQQINITCOEFF10*/
+       { STB0899_OFF0_EQ_I_OUT_COEFF_0 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT0 */
+       { STB0899_OFF1_EQ_I_OUT_COEFF_1 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT1 */
+       { STB0899_OFF2_EQ_I_OUT_COEFF_2 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT2 */
+       { STB0899_OFF3_EQ_I_OUT_COEFF_3 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT3 */
+       { STB0899_OFF4_EQ_I_OUT_COEFF_4 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT4 */
+       { STB0899_OFF5_EQ_I_OUT_COEFF_5 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT5 */
+       { STB0899_OFF6_EQ_I_OUT_COEFF_6 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT6 */
+       { STB0899_OFF7_EQ_I_OUT_COEFF_7 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT7 */
+       { STB0899_OFF8_EQ_I_OUT_COEFF_8 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT8 */
+       { STB0899_OFF9_EQ_I_OUT_COEFF_9 , STB0899_BASE_EQ_I_OUT_COEFF_N , 0x00000000 }, /* EQICOEFFSOUT9 */
+       { STB0899_OFFa_EQ_I_OUT_COEFF_10,STB0899_BASE_EQ_I_OUT_COEFF_N  , 0x00000000 }, /* EQICOEFFSOUT10*/
+       { STB0899_OFF0_EQ_Q_OUT_COEFF_0 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT0 */
+       { STB0899_OFF1_EQ_Q_OUT_COEFF_1 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT1 */
+       { STB0899_OFF2_EQ_Q_OUT_COEFF_2 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT2 */
+       { STB0899_OFF3_EQ_Q_OUT_COEFF_3 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT3 */
+       { STB0899_OFF4_EQ_Q_OUT_COEFF_4 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT4 */
+       { STB0899_OFF5_EQ_Q_OUT_COEFF_5 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT5 */
+       { STB0899_OFF6_EQ_Q_OUT_COEFF_6 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT6 */
+       { STB0899_OFF7_EQ_Q_OUT_COEFF_7 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT7 */
+       { STB0899_OFF8_EQ_Q_OUT_COEFF_8 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT8 */
+       { STB0899_OFF9_EQ_Q_OUT_COEFF_9 , STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT9 */
+       { STB0899_OFFa_EQ_Q_OUT_COEFF_10, STB0899_BASE_EQ_Q_OUT_COEFF_N , 0x00000000 }, /* EQQCOEFFSOUT10*/
+       { 0xffff                        , 0xffffffff                    , 0xffffffff },
+};
+static const struct stb0899_s2_reg stb0899_s2_init_4[] = {
+       { STB0899_OFF0_BLOCK_LNGTH      , STB0899_BASE_BLOCK_LNGTH      , 0x00000008 }, /* BLOCKLNGTH   */
+       { STB0899_OFF0_ROW_STR          , STB0899_BASE_ROW_STR          , 0x000000b4 }, /* ROWSTR       */
+       { STB0899_OFF0_BN_END_ADDR      , STB0899_BASE_BN_END_ADDR      , 0x000004b5 }, /* BNANDADDR    */
+       { STB0899_OFF0_CN_END_ADDR      , STB0899_BASE_CN_END_ADDR      , 0x00000b4b }, /* CNANDADDR    */
+       { STB0899_OFF0_INFO_LENGTH      , STB0899_BASE_INFO_LENGTH      , 0x00000078 }, /* INFOLENGTH   */
+       { STB0899_OFF0_BOT_ADDR         , STB0899_BASE_BOT_ADDR         , 0x000001e0 }, /* BOT_ADDR     */
+       { STB0899_OFF0_BCH_BLK_LN       , STB0899_BASE_BCH_BLK_LN       , 0x0000a8c0 }, /* BCHBLKLN     */
+       { STB0899_OFF0_BCH_T            , STB0899_BASE_BCH_T            , 0x0000000c }, /* BCHT         */
+       { STB0899_OFF0_CNFG_MODE        , STB0899_BASE_CNFG_MODE        , 0x00000001 }, /* CNFGMODE     */
+       { STB0899_OFF0_LDPC_STAT        , STB0899_BASE_LDPC_STAT        , 0x0000000d }, /* LDPCSTAT     */
+       { STB0899_OFF0_ITER_SCALE       , STB0899_BASE_ITER_SCALE       , 0x00000040 }, /* ITERSCALE    */
+       { STB0899_OFF0_INPUT_MODE       , STB0899_BASE_INPUT_MODE       , 0x00000000 }, /* INPUTMODE    */
+       { STB0899_OFF0_LDPCDECRST       , STB0899_BASE_LDPCDECRST       , 0x00000000 }, /* LDPCDECRST   */
+       { STB0899_OFF0_CLK_PER_BYTE_RW  , STB0899_BASE_CLK_PER_BYTE_RW  , 0x00000008 }, /* CLKPERBYTE   */
+       { STB0899_OFF0_BCH_ERRORS       , STB0899_BASE_BCH_ERRORS       , 0x00000000 }, /* BCHERRORS    */
+       { STB0899_OFF0_LDPC_ERRORS      , STB0899_BASE_LDPC_ERRORS      , 0x00000000 }, /* LDPCERRORS   */
+       { STB0899_OFF0_BCH_MODE         , STB0899_BASE_BCH_MODE         , 0x00000000 }, /* BCHMODE      */
+       { STB0899_OFF0_ERR_ACC_PER      , STB0899_BASE_ERR_ACC_PER      , 0x00000008 }, /* ERRACCPER    */
+       { STB0899_OFF0_BCH_ERR_ACC      , STB0899_BASE_BCH_ERR_ACC      , 0x00000000 }, /* BCHERRACC    */
+       { STB0899_OFF0_FEC_TP_SEL       , STB0899_BASE_FEC_TP_SEL       , 0x00000000 }, /* FECTPSEL     */
+       { 0xffff                        , 0xffffffff                    , 0xffffffff },
+};
+
+static const struct stb0899_s1_reg stb0899_s1_init_5[] = {
+       { STB0899_TSTCK         , 0x00 },
+       { STB0899_TSTRES        , 0x00 },
+       { STB0899_TSTOUT        , 0x00 },
+       { STB0899_TSTIN         , 0x00 },
+       { STB0899_TSTSYS        , 0x00 },
+       { STB0899_TSTCHIP       , 0x00 },
+       { STB0899_TSTFREE       , 0x00 },
+       { STB0899_TSTI2C        , 0x00 },
+       { STB0899_BITSPEEDM     , 0x00 },
+       { STB0899_BITSPEEDL     , 0x00 },
+       { STB0899_TBUSBIT       , 0x00 },
+       { STB0899_TSTDIS        , 0x00 },
+       { STB0899_TSTDISRX      , 0x00 },
+       { STB0899_TSTJETON      , 0x00 },
+       { STB0899_TSTDCADJ      , 0x00 },
+       { STB0899_TSTAGC1       , 0x00 },
+       { STB0899_TSTAGC1N      , 0x00 },
+       { STB0899_TSTPOLYPH     , 0x00 },
+       { STB0899_TSTR          , 0x00 },
+       { STB0899_TSTAGC2       , 0x00 },
+       { STB0899_TSTCTL1       , 0x00 },
+       { STB0899_TSTCTL2       , 0x00 },
+       { STB0899_TSTCTL3       , 0x00 },
+       { STB0899_TSTDEMAP      , 0x00 },
+       { STB0899_TSTDEMAP2     , 0x00 },
+       { STB0899_TSTDEMMON     , 0x00 },
+       { STB0899_TSTRATE       , 0x00 },
+       { STB0899_TSTSELOUT     , 0x00 },
+       { STB0899_TSYNC         , 0x00 },
+       { STB0899_TSTERR        , 0x00 },
+       { STB0899_TSTRAM1       , 0x00 },
+       { STB0899_TSTVSELOUT    , 0x00 },
+       { STB0899_TSTFORCEIN    , 0x00 },
+       { STB0899_TSTRS1        , 0x00 },
+       { STB0899_TSTRS2        , 0x00 },
+       { STB0899_TSTRS3        , 0x00 },
+       { STB0899_GHOSTREG      , 0x81 },
+       { 0xffff                , 0xff },
+};
+
+#define STB0899_DVBS2_ESNO_AVE                 3
+#define STB0899_DVBS2_ESNO_QUANT               32
+#define STB0899_DVBS2_AVFRAMES_COARSE          10
+#define STB0899_DVBS2_AVFRAMES_FINE            20
+#define STB0899_DVBS2_MISS_THRESHOLD           6
+#define STB0899_DVBS2_UWP_THRESHOLD_ACQ                1125
+#define STB0899_DVBS2_UWP_THRESHOLD_TRACK      758
+#define STB0899_DVBS2_UWP_THRESHOLD_SOF                1350
+#define STB0899_DVBS2_SOF_SEARCH_TIMEOUT       1664100
+
+#define STB0899_DVBS2_BTR_NCO_BITS             28
+#define STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET    15
+#define STB0899_DVBS2_CRL_NCO_BITS             30
+#define STB0899_DVBS2_LDPC_MAX_ITER            70
+
+#endif //__STB0899_CFG_H
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
new file mode 100644 (file)
index 0000000..5288201
--- /dev/null
@@ -0,0 +1,1684 @@
+/*
+       STB0899 Multistandard Frontend driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#include "stb0899_drv.h"
+#include "stb0899_priv.h"
+#include "stb0899_reg.h"
+
+static unsigned int verbose = 0;//1;
+module_param(verbose, int, 0644);
+
+/* C/N in dB/10, NIRM/NIRL */
+static const struct stb0899_tab stb0899_cn_tab[] = {
+       { 200,  2600 },
+       { 190,  2700 },
+       { 180,  2860 },
+       { 170,  3020 },
+       { 160,  3210 },
+       { 150,  3440 },
+       { 140,  3710 },
+       { 130,  4010 },
+       { 120,  4360 },
+       { 110,  4740 },
+       { 100,  5190 },
+       { 90,   5670 },
+       { 80,   6200 },
+       { 70,   6770 },
+       { 60,   7360 },
+       { 50,   7970 },
+       { 40,   8250 },
+       { 30,   9000 },
+       { 20,   9450 },
+       { 15,   9600 },
+};
+
+/* DVB-S AGCIQ_VALUE vs. signal level in dBm/10.
+ * As measured, connected to a modulator.
+ * -8.0 to -50.0 dBm directly connected,
+ * -52.0 to -74.8 with extra attenuation.
+ * Cut-off to AGCIQ_VALUE = 0x80 below -74.8dBm.
+ * Crude linear extrapolation below -84.8dBm and above -8.0dBm.
+ */
+static const struct stb0899_tab stb0899_dvbsrf_tab[] = {
+       { -950, -128 },
+       { -748,  -94 },
+       { -745,  -92 },
+       { -735,  -90 },
+       { -720,  -87 },
+       { -670,  -77 },
+       { -640,  -70 },
+       { -610,  -62 },
+       { -600,  -60 },
+       { -590,  -56 },
+       { -560,  -41 },
+       { -540,  -25 },
+       { -530,  -17 },
+       { -520,  -11 },
+       { -500,    1 },
+       { -490,    6 },
+       { -480,   10 },
+       { -440,   22 },
+       { -420,   27 },
+       { -400,   31 },
+       { -380,   34 },
+       { -340,   40 },
+       { -320,   43 },
+       { -280,   48 },
+       { -250,   52 },
+       { -230,   55 },
+       { -180,   61 },
+       { -140,   66 },
+       {  -90,   73 },
+       {  -80,   74 },
+       {  500,  127 }
+};
+
+/* DVB-S2 IF_AGC_GAIN vs. signal level in dBm/10.
+ * As measured, connected to a modulator.
+ * -8.0 to -50.1 dBm directly connected,
+ * -53.0 to -76.6 with extra attenuation.
+ * Cut-off to IF_AGC_GAIN = 0x3fff below -76.6dBm.
+ * Crude linear extrapolation below -76.6dBm and above -8.0dBm.
+ */
+static const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
+       {  700,     0 },
+       {  -80,  3217 },
+       { -150,  3893 },
+       { -190,  4217 },
+       { -240,  4621 },
+       { -280,  4945 },
+       { -320,  5273 },
+       { -350,  5545 },
+       { -370,  5741 },
+       { -410,  6147 },
+       { -450,  6671 },
+       { -490,  7413 },
+       { -501,  7665 },
+       { -530,  8767 },
+       { -560, 10219 },
+       { -580, 10939 },
+       { -590, 11518 },
+       { -600, 11723 },
+       { -650, 12659 },
+       { -690, 13219 },
+       { -730, 13645 },
+       { -750, 13909 },
+       { -766, 14153 },
+       { -999, 16383 }
+};
+
+/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
+struct stb0899_tab stb0899_quant_tab[] = {
+       {    0,     0 },
+       {    0,   100 },
+       {  600,   200 },
+       {  950,   299 },
+       { 1200,   398 },
+       { 1400,   501 },
+       { 1560,   603 },
+       { 1690,   700 },
+       { 1810,   804 },
+       { 1910,   902 },
+       { 2000,  1000 },
+       { 2080,  1096 },
+       { 2160,  1202 },
+       { 2230,  1303 },
+       { 2350,  1496 },
+       { 2410,  1603 },
+       { 2460,  1698 },
+       { 2510,  1799 },
+       { 2600,  1995 },
+       { 2650,  2113 },
+       { 2690,  2213 },
+       { 2720,  2291 },
+       { 2760,  2399 },
+       { 2800,  2512 },
+       { 2860,  2692 },
+       { 2930,  2917 },
+       { 2960,  3020 },
+       { 3010,  3199 },
+       { 3040,  3311 },
+       { 3060,  3388 },
+       { 3120,  3631 },
+       { 3190,  3936 },
+       { 3400,  5012 },
+       { 3610,  6383 },
+       { 3800,  7943 },
+       { 4210, 12735 },
+       { 4500, 17783 },
+       { 4690, 22131 },
+       { 4810, 25410 }
+};
+
+/* DVB-S2 Es/N0 estimate in dB/100 vs read value */
+struct stb0899_tab stb0899_est_tab[] = {
+       {    0,      0 },
+       {    0,      1 },
+       {  301,      2 },
+       { 1204,     16 },
+       { 1806,     64 },
+       { 2408,    256 },
+       { 2709,    512 },
+       { 3010,   1023 },
+       { 3311,   2046 },
+       { 3612,   4093 },
+       { 3823,   6653 },
+       { 3913,   8185 },
+       { 4010,  10233 },
+       { 4107,  12794 },
+       { 4214,  16368 },
+       { 4266,  18450 },
+       { 4311,  20464 },
+       { 4353,  22542 },
+       { 4391,  24604 },
+       { 4425,  26607 },
+       { 4457,  28642 },
+       { 4487,  30690 },
+       { 4515,  32734 },
+       { 4612,  40926 },
+       { 4692,  49204 },
+       { 4816,  65464 },
+       { 4913,  81846 },
+       { 4993,  98401 },
+       { 5060, 114815 },
+       { 5118, 131220 },
+       { 5200, 158489 },
+       { 5300, 199526 },
+       { 5400, 251189 },
+       { 5500, 316228 },
+       { 5600, 398107 },
+       { 5720, 524807 },
+       { 5721, 526017 },
+};
+
+int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
+{
+       int ret;
+
+       u8 b0[] = { reg >> 8, reg & 0xff };
+       u8 buf;
+
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = state->config->demod_address,
+                       .flags  = 0,
+                       .buf    = b0,
+                       .len    = 2
+               },{
+                       .addr   = state->config->demod_address,
+                       .flags  = I2C_M_RD,
+                       .buf    = &buf,
+                       .len    = 1
+               }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2) {
+               if (ret != -ERESTARTSYS)
+                       dprintk(state->verbose, FE_ERROR, 1,
+                               "Read error, Reg=[0x%02x], Status=%d",
+                               reg, ret);
+
+               return ret < 0 ? ret : -EREMOTEIO;
+       }
+       if (unlikely(*state->verbose >= FE_DEBUGREG))
+               dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
+                       reg, buf);
+
+       return (unsigned int)buf;
+}
+
+int stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
+{
+       int result;
+
+       result = _stb0899_read_reg(state, reg);
+       /*
+        * Bug ID 9:
+        * access to 0xf2xx/0xf6xx
+        * must be followed by read from 0xf2ff/0xf6ff.
+        */
+       if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
+           (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
+               _stb0899_read_reg(state, (reg | 0x00ff));
+
+       return result;
+}
+
+u32 _stb0899_read_s2reg(struct stb0899_state *state,
+                       u32 stb0899_i2cdev,
+                       u32 stb0899_base_addr,
+                       u16 stb0899_reg_offset)
+{
+       int status;
+       u32 data;
+       u8 buf[7] = { 0 };
+       u16 tmpaddr;
+
+       u8 buf_0[] = {
+               GETBYTE(stb0899_i2cdev, BYTE1),         /* 0xf3 S2 Base Address (MSB)   */
+               GETBYTE(stb0899_i2cdev, BYTE0),         /* 0xfc S2 Base Address (LSB)   */
+               GETBYTE(stb0899_base_addr, BYTE0),      /* 0x00 Base Address (LSB)      */
+               GETBYTE(stb0899_base_addr, BYTE1),      /* 0x04 Base Address (LSB)      */
+               GETBYTE(stb0899_base_addr, BYTE2),      /* 0x00 Base Address (MSB)      */
+               GETBYTE(stb0899_base_addr, BYTE3),      /* 0x00 Base Address (MSB)      */
+       };
+       u8 buf_1[] = {
+               0x00,   /* 0xf3 Reg Offset      */
+               0x00,   /* 0x44 Reg Offset      */
+       };
+
+       struct i2c_msg msg_0 = {
+               .addr   = state->config->demod_address,
+               .flags  = 0,
+               .buf    = buf_0,
+               .len    = 6
+       };
+
+       struct i2c_msg msg_1 = {
+               .addr   = state->config->demod_address,
+               .flags  = 0,
+               .buf    = buf_1,
+               .len    = 2
+       };
+
+       struct i2c_msg msg_r = {
+               .addr   = state->config->demod_address,
+               .flags  = I2C_M_RD,
+               .buf    = buf,
+               .len    = 4
+       };
+
+       tmpaddr = stb0899_reg_offset & 0xff00;
+       if (!(stb0899_reg_offset & 0x8))
+               tmpaddr = stb0899_reg_offset | 0x20;
+
+       buf_1[0] = GETBYTE(tmpaddr, BYTE1);
+       buf_1[1] = GETBYTE(tmpaddr, BYTE0);
+
+       status = i2c_transfer(state->i2c, &msg_0, 1);
+       if (status < 1) {
+               if (status != -ERESTARTSYS)
+                       printk(KERN_ERR "%s ERR(1), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
+                              __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
+
+               goto err;
+       }
+
+       /* Dummy        */
+       status = i2c_transfer(state->i2c, &msg_1, 1);
+       if (status < 1)
+               goto err;
+
+       status = i2c_transfer(state->i2c, &msg_r, 1);
+       if (status < 1)
+               goto err;
+
+       buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
+       buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
+
+       /* Actual       */
+       status = i2c_transfer(state->i2c, &msg_1, 1);
+       if (status < 1) {
+               if (status != -ERESTARTSYS)
+                       printk(KERN_ERR "%s ERR(2), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
+                              __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
+               goto err;
+       }
+
+       status = i2c_transfer(state->i2c, &msg_r, 1);
+       if (status < 1) {
+               if (status != -ERESTARTSYS)
+                       printk(KERN_ERR "%s ERR(3), Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Status=%d\n",
+                              __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, status);
+               return status < 0 ? status : -EREMOTEIO;
+       }
+
+       data = MAKEWORD32(buf[3], buf[2], buf[1], buf[0]);
+       if (unlikely(*state->verbose >= FE_DEBUGREG))
+               printk(KERN_DEBUG "%s Device=[0x%04x], Base address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
+                      __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, data);
+
+       return data;
+
+err:
+       return status < 0 ? status : -EREMOTEIO;
+}
+
+int stb0899_write_s2reg(struct stb0899_state *state,
+                       u32 stb0899_i2cdev,
+                       u32 stb0899_base_addr,
+                       u16 stb0899_reg_offset,
+                       u32 stb0899_data)
+{
+       int status;
+
+       /* Base Address Setup   */
+       u8 buf_0[] = {
+               GETBYTE(stb0899_i2cdev, BYTE1),         /* 0xf3 S2 Base Address (MSB)   */
+               GETBYTE(stb0899_i2cdev, BYTE0),         /* 0xfc S2 Base Address (LSB)   */
+               GETBYTE(stb0899_base_addr, BYTE0),      /* 0x00 Base Address (LSB)      */
+               GETBYTE(stb0899_base_addr, BYTE1),      /* 0x04 Base Address (LSB)      */
+               GETBYTE(stb0899_base_addr, BYTE2),      /* 0x00 Base Address (MSB)      */
+               GETBYTE(stb0899_base_addr, BYTE3),      /* 0x00 Base Address (MSB)      */
+       };
+       u8 buf_1[] = {
+               0x00,   /* 0xf3 Reg Offset      */
+               0x00,   /* 0x44 Reg Offset      */
+               0x00,   /* data                 */
+               0x00,   /* data                 */
+               0x00,   /* data                 */
+               0x00,   /* data                 */
+       };
+
+       struct i2c_msg msg_0 = {
+               .addr   = state->config->demod_address,
+               .flags  = 0,
+               .buf    = buf_0,
+               .len    = 6
+       };
+
+       struct i2c_msg msg_1 = {
+               .addr   = state->config->demod_address,
+               .flags  = 0,
+               .buf    = buf_1,
+               .len    = 6
+       };
+
+       buf_1[0] = GETBYTE(stb0899_reg_offset, BYTE1);
+       buf_1[1] = GETBYTE(stb0899_reg_offset, BYTE0);
+       buf_1[2] = GETBYTE(stb0899_data, BYTE0);
+       buf_1[3] = GETBYTE(stb0899_data, BYTE1);
+       buf_1[4] = GETBYTE(stb0899_data, BYTE2);
+       buf_1[5] = GETBYTE(stb0899_data, BYTE3);
+
+       if (unlikely(*state->verbose >= FE_DEBUGREG))
+               printk(KERN_DEBUG "%s Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x]\n",
+                      __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data);
+
+       status = i2c_transfer(state->i2c, &msg_0, 1);
+       if (unlikely(status < 1)) {
+               if (status != -ERESTARTSYS)
+                       printk(KERN_ERR "%s ERR (1), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
+                              __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
+               goto err;
+       }
+       status = i2c_transfer(state->i2c, &msg_1, 1);
+       if (unlikely(status < 1)) {
+               if (status != -ERESTARTSYS)
+                       printk(KERN_ERR "%s ERR (2), Device=[0x%04x], Base Address=[0x%08x], Offset=[0x%04x], Data=[0x%08x], status=%d\n",
+                              __func__, stb0899_i2cdev, stb0899_base_addr, stb0899_reg_offset, stb0899_data, status);
+
+               return status < 0 ? status : -EREMOTEIO;
+       }
+
+       return 0;
+
+err:
+       return status < 0 ? status : -EREMOTEIO;
+}
+
+int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u32 count)
+{
+       int status;
+
+       u8 b0[] = { reg >> 8, reg & 0xff };
+
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = state->config->demod_address,
+                       .flags  = 0,
+                       .buf    = b0,
+                       .len    = 2
+               },{
+                       .addr   = state->config->demod_address,
+                       .flags  = I2C_M_RD,
+                       .buf    = buf,
+                       .len    = count
+               }
+       };
+
+       status = i2c_transfer(state->i2c, msg, 2);
+       if (status != 2) {
+               if (status != -ERESTARTSYS)
+                       printk(KERN_ERR "%s Read error, Reg=[0x%04x], Count=%u, Status=%d\n",
+                              __func__, reg, count, status);
+               goto err;
+       }
+       /*
+        * Bug ID 9:
+        * access to 0xf2xx/0xf6xx
+        * must be followed by read from 0xf2ff/0xf6ff.
+        */
+       if ((reg != 0xf2ff) && (reg != 0xf6ff) &&
+           (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
+               _stb0899_read_reg(state, (reg | 0x00ff));
+
+       if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+               int i;
+
+               printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+               for (i = 0; i < count; i++) {
+                       printk(" %02x", buf[i]);
+               }
+               printk("\n");
+       }
+
+       return 0;
+err:
+       return status < 0 ? status : -EREMOTEIO;
+}
+
+int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count)
+{
+       int ret;
+       u8 buf[2 + count];
+       struct i2c_msg i2c_msg = {
+               .addr   = state->config->demod_address,
+               .flags  = 0,
+               .buf    = buf,
+               .len    = 2 + count
+       };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+       memcpy(&buf[2], data, count);
+
+       if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+               int i;
+
+               printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+               for (i = 0; i < count; i++)
+                       printk(" %02x", data[i]);
+               printk("\n");
+       }
+       ret = i2c_transfer(state->i2c, &i2c_msg, 1);
+
+       /*
+        * Bug ID 9:
+        * access to 0xf2xx/0xf6xx
+        * must be followed by read from 0xf2ff/0xf6ff.
+        */
+       if ((((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600)))
+               stb0899_read_reg(state, (reg | 0x00ff));
+
+       if (ret != 1) {
+               if (ret != -ERESTARTSYS)
+                       dprintk(state->verbose, FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
+                               reg, data[0], count, ret);
+               return ret < 0 ? ret : -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+int stb0899_write_reg(struct stb0899_state *state, unsigned int reg, u8 data)
+{
+       return stb0899_write_regs(state, reg, &data, 1);
+}
+
+/*
+ * stb0899_get_mclk
+ * Get STB0899 master clock frequency
+ * ExtClk: external clock frequency (Hz)
+ */
+static u32 stb0899_get_mclk(struct stb0899_state *state)
+{
+       u32 mclk = 0, div = 0;
+
+       div = stb0899_read_reg(state, STB0899_NCOARSE);
+       mclk = (div + 1) * state->config->xtal_freq / 6;
+       dprintk(state->verbose, FE_DEBUG, 1, "div=%d, mclk=%d", div, mclk);
+
+       return mclk;
+}
+
+/*
+ * stb0899_set_mclk
+ * Set STB0899 master Clock frequency
+ * Mclk: demodulator master clock
+ * ExtClk: external clock frequency (Hz)
+ */
+static void stb0899_set_mclk(struct stb0899_state *state, u32 Mclk)
+{
+       struct stb0899_internal *internal = &state->internal;
+       u8 mdiv = 0;
+
+       dprintk(state->verbose, FE_DEBUG, 1, "state->config=%p", state->config);
+       mdiv = ((6 * Mclk) / state->config->xtal_freq) - 1;
+       dprintk(state->verbose, FE_DEBUG, 1, "mdiv=%d", mdiv);
+
+       stb0899_write_reg(state, STB0899_NCOARSE, mdiv);
+       internal->master_clk = stb0899_get_mclk(state);
+
+       dprintk(state->verbose, FE_DEBUG, 1, "MasterCLOCK=%d", internal->master_clk);
+}
+
+static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable)
+{
+       struct stb0899_config *config           = state->config;
+       const struct stb0899_postproc *postproc = config->postproc;
+
+       /* post process event */
+       if (postproc) {
+               if (enable) {
+                       if (postproc[ctl].level == STB0899_GPIOPULLUP)
+                               stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
+                       else
+                               stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
+               } else {
+                       if (postproc[ctl].level == STB0899_GPIOPULLUP)
+                               stb0899_write_reg(state, postproc[ctl].gpio, 0x82);
+                       else
+                               stb0899_write_reg(state, postproc[ctl].gpio, 0x02);
+               }
+       }
+       return 0;
+}
+
+static void stb0899_release(struct dvb_frontend *fe)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+
+       dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend");
+       /* post process event */
+       stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
+       kfree(state);
+}
+
+/*
+ * stb0899_get_alpha
+ * return: rolloff
+ */
+static int stb0899_get_alpha(struct stb0899_state *state)
+{
+       u8 mode_coeff;
+
+       mode_coeff = stb0899_read_reg(state, STB0899_DEMOD);
+
+       if (STB0899_GETFIELD(MODECOEFF, mode_coeff) == 1)
+               return 20;
+       else
+               return 35;
+}
+
+/*
+ * stb0899_init_calc
+ */
+static void stb0899_init_calc(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       int master_clk;
+       u8 agc[2];
+       u8 agc1cn;
+       u32 reg;
+
+       /* Read registers (in burst mode)       */
+       agc1cn = stb0899_read_reg(state, STB0899_AGC1CN);
+       stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O   */
+
+       /* Initial calculations */
+       master_clk                      = stb0899_get_mclk(state);
+       internal->t_agc1                = 0;
+       internal->t_agc2                = 0;
+       internal->master_clk            = master_clk;
+       internal->mclk                  = master_clk / 65536L;
+       internal->rolloff               = stb0899_get_alpha(state);
+
+       /* DVBS2 Initial calculations   */
+       /* Set AGC value to the middle  */
+       internal->agc_gain              = 8154;
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, IF_AGC_CNTRL);
+       STB0899_SETFIELD_VAL(IF_GAIN_INIT, reg, internal->agc_gain);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_IF_AGC_CNTRL, STB0899_OFF0_IF_AGC_CNTRL, reg);
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, RRC_ALPHA);
+       internal->rrc_alpha             = STB0899_GETFIELD(RRC_ALPHA, reg);
+
+       internal->center_freq           = 0;
+       internal->av_frame_coarse       = 10;
+       internal->av_frame_fine         = 20;
+       internal->step_size             = 2;
+/*
+       if ((pParams->SpectralInv == FE_IQ_NORMAL) || (pParams->SpectralInv == FE_IQ_AUTO))
+               pParams->IQLocked = 0;
+       else
+               pParams->IQLocked = 1;
+*/
+}
+
+static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeout)
+{
+       u8 reg = 0;
+       unsigned long start = jiffies;
+
+       while (1) {
+               reg = stb0899_read_reg(state, STB0899_DISSTATUS);
+               if (!STB0899_GETFIELD(FIFOFULL, reg))
+                       break;
+               if ((jiffies - start) > timeout) {
+                       dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+       u8 reg, i;
+
+       if (cmd->msg_len > 8)
+               return -EINVAL;
+
+       /* enable FIFO precharge        */
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+       STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 1);
+       stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+       for (i = 0; i < cmd->msg_len; i++) {
+               /* wait for FIFO empty  */
+               if (stb0899_wait_diseqc_fifo_empty(state, 10) < 0)
+                       return -ETIMEDOUT;
+
+               stb0899_write_reg(state, STB0899_DISFIFO, cmd->msg[i]);
+       }
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+       STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0);
+       stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+
+       return 0;
+}
+
+static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout)
+{
+       u8 reg = 0;
+       unsigned long start = jiffies;
+
+       while (!STB0899_GETFIELD(RXEND, reg)) {
+               reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
+               if (jiffies - start > timeout) {
+                       dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
+                       return -ETIMEDOUT;
+               }
+               msleep(10);
+       }
+
+       return 0;
+}
+
+static int stb0899_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+       u8 reg, length = 0, i;
+       int result;
+
+       if (stb0899_wait_diseqc_rxidle(state, 100) < 0)
+               return -ETIMEDOUT;
+
+       reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
+       if (STB0899_GETFIELD(RXEND, reg)) {
+
+               reg = stb0899_read_reg(state, STB0899_DISRX_ST1);
+               length = STB0899_GETFIELD(FIFOBYTENBR, reg);
+
+               if (length > sizeof (reply->msg)) {
+                       result = -EOVERFLOW;
+                       goto exit;
+               }
+               reply->msg_len = length;
+
+               /* extract data */
+               for (i = 0; i < length; i++)
+                       reply->msg[i] = stb0899_read_reg(state, STB0899_DISFIFO);
+       }
+
+       return 0;
+exit:
+
+       return result;
+}
+
+static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout)
+{
+       u8 reg = 0;
+       unsigned long start = jiffies;
+
+       while (!STB0899_GETFIELD(TXIDLE, reg)) {
+               reg = stb0899_read_reg(state, STB0899_DISSTATUS);
+               if (jiffies - start > timeout) {
+                       dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
+                       return -ETIMEDOUT;
+               }
+               msleep(10);
+       }
+       return 0;
+}
+
+static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+       u8 reg, old_state;
+
+       /* wait for diseqc idle */
+       if (stb0899_wait_diseqc_txidle(state, 100) < 0)
+               return -ETIMEDOUT;
+
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+       old_state = reg;
+       /* set to burst mode    */
+       STB0899_SETFIELD_VAL(DISEQCMODE, reg, 0x02);
+       STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x01);
+       stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+       switch (burst) {
+       case SEC_MINI_A:
+               /* unmodulated  */
+               stb0899_write_reg(state, STB0899_DISFIFO, 0x00);
+               break;
+       case SEC_MINI_B:
+               /* modulated    */
+               stb0899_write_reg(state, STB0899_DISFIFO, 0xff);
+               break;
+       }
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+       STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0x00);
+       stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+       /* wait for diseqc idle */
+       if (stb0899_wait_diseqc_txidle(state, 100) < 0)
+               return -ETIMEDOUT;
+
+       /* restore state        */
+       stb0899_write_reg(state, STB0899_DISCNTRL1, old_state);
+
+       return 0;
+}
+
+static int stb0899_diseqc_init(struct stb0899_state *state)
+{
+       struct dvb_diseqc_master_cmd tx_data;
+/*
+       struct dvb_diseqc_slave_reply rx_data;
+*/
+       u8 f22_tx, f22_rx, reg;
+
+       u32 mclk, tx_freq = 22000;/* count = 0, i; */
+       tx_data.msg[0] = 0xe2;
+       tx_data.msg_len = 3;
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL2);
+       STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0);
+       stb0899_write_reg(state, STB0899_DISCNTRL2, reg);
+
+       /* disable Tx spy       */
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+       STB0899_SETFIELD_VAL(DISEQCRESET, reg, 1);
+       stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+
+       reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
+       STB0899_SETFIELD_VAL(DISEQCRESET, reg, 0);
+       stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
+
+       mclk = stb0899_get_mclk(state);
+       f22_tx = mclk / (tx_freq * 32);
+       stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq     */
+       state->rx_freq = 20000;
+       f22_rx = mclk / (state->rx_freq * 32);
+
+       return 0;
+}
+
+static int stb0899_sleep(struct dvb_frontend *fe)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+/*
+       u8 reg;
+*/
+       dprintk(state->verbose, FE_DEBUG, 1, "Going to Sleep .. (Really tired .. :-))");
+       /* post process event */
+       stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0);
+
+       return 0;
+}
+
+static int stb0899_wakeup(struct dvb_frontend *fe)
+{
+       int rc;
+       struct stb0899_state *state = fe->demodulator_priv;
+
+       if ((rc = stb0899_write_reg(state, STB0899_SYNTCTRL, STB0899_SELOSCI)))
+               return rc;
+       /* Activate all clocks; DVB-S2 registers are inaccessible otherwise. */
+       if ((rc = stb0899_write_reg(state, STB0899_STOPCLK1, 0x00)))
+               return rc;
+       if ((rc = stb0899_write_reg(state, STB0899_STOPCLK2, 0x00)))
+               return rc;
+
+       /* post process event */
+       stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 1);
+
+       return 0;
+}
+
+static int stb0899_init(struct dvb_frontend *fe)
+{
+       int i;
+       struct stb0899_state *state = fe->demodulator_priv;
+       struct stb0899_config *config = state->config;
+
+       dprintk(state->verbose, FE_DEBUG, 1, "Initializing STB0899 ... ");
+
+       /* init device          */
+       dprintk(state->verbose, FE_DEBUG, 1, "init device");
+       for (i = 0; config->init_dev[i].address != 0xffff; i++)
+               stb0899_write_reg(state, config->init_dev[i].address, config->init_dev[i].data);
+
+       dprintk(state->verbose, FE_DEBUG, 1, "init S2 demod");
+       /* init S2 demod        */
+       for (i = 0; config->init_s2_demod[i].offset != 0xffff; i++)
+               stb0899_write_s2reg(state, STB0899_S2DEMOD,
+                                   config->init_s2_demod[i].base_address,
+                                   config->init_s2_demod[i].offset,
+                                   config->init_s2_demod[i].data);
+
+       dprintk(state->verbose, FE_DEBUG, 1, "init S1 demod");
+       /* init S1 demod        */
+       for (i = 0; config->init_s1_demod[i].address != 0xffff; i++)
+               stb0899_write_reg(state, config->init_s1_demod[i].address, config->init_s1_demod[i].data);
+
+       dprintk(state->verbose, FE_DEBUG, 1, "init S2 FEC");
+       /* init S2 fec          */
+       for (i = 0; config->init_s2_fec[i].offset != 0xffff; i++)
+               stb0899_write_s2reg(state, STB0899_S2FEC,
+                                   config->init_s2_fec[i].base_address,
+                                   config->init_s2_fec[i].offset,
+                                   config->init_s2_fec[i].data);
+
+       dprintk(state->verbose, FE_DEBUG, 1, "init TST");
+       /* init test            */
+       for (i = 0; config->init_tst[i].address != 0xffff; i++)
+               stb0899_write_reg(state, config->init_tst[i].address, config->init_tst[i].data);
+
+       stb0899_init_calc(state);
+       stb0899_diseqc_init(state);
+
+       return 0;
+}
+
+static int stb0899_table_lookup(const struct stb0899_tab *tab, int max, int val)
+{
+       int res = 0;
+       int min = 0, med;
+
+       if (val < tab[min].read)
+               res = tab[min].real;
+       else if (val >= tab[max].read)
+               res = tab[max].real;
+       else {
+               while ((max - min) > 1) {
+                       med = (max + min) / 2;
+                       if (val >= tab[min].read && val < tab[med].read)
+                               max = med;
+                       else
+                               min = med;
+               }
+               res = ((val - tab[min].read) *
+                      (tab[max].real - tab[min].real) /
+                      (tab[max].read - tab[min].read)) +
+                       tab[min].real;
+       }
+
+       return res;
+}
+
+static int stb0899_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct stb0899_state *state             = fe->demodulator_priv;
+       struct stb0899_internal *internal       = &state->internal;
+
+       int val;
+       u32 reg;
+       switch (state->delsys) {
+       case SYS_DVBS:
+       case SYS_DSS:
+               if (internal->lock) {
+                       reg  = stb0899_read_reg(state, STB0899_VSTATUS);
+                       if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
+
+                               reg = stb0899_read_reg(state, STB0899_AGCIQIN);
+                               val = (s32)(s8)STB0899_GETFIELD(AGCIQVALUE, reg);
+
+                               *strength = stb0899_table_lookup(stb0899_dvbsrf_tab, ARRAY_SIZE(stb0899_dvbsrf_tab) - 1, val);
+                               *strength += 750;
+                               dprintk(state->verbose, FE_DEBUG, 1, "AGCIQVALUE = 0x%02x, C = %d * 0.1 dBm",
+                                       val & 0xff, *strength);
+                       }
+               }
+               break;
+       case SYS_DVBS2:
+               if (internal->lock) {
+                       reg = STB0899_READ_S2REG(STB0899_DEMOD, IF_AGC_GAIN);
+                       val = STB0899_GETFIELD(IF_AGC_GAIN, reg);
+
+                       *strength = stb0899_table_lookup(stb0899_dvbs2rf_tab, ARRAY_SIZE(stb0899_dvbs2rf_tab) - 1, val);
+                       *strength += 750;
+                       dprintk(state->verbose, FE_DEBUG, 1, "IF_AGC_GAIN = 0x%04x, C = %d * 0.1 dBm",
+                               val & 0x3fff, *strength);
+               }
+               break;
+       default:
+               dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int stb0899_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct stb0899_state *state             = fe->demodulator_priv;
+       struct stb0899_internal *internal       = &state->internal;
+
+       unsigned int val, quant, quantn = -1, est, estn = -1;
+       u8 buf[2];
+       u32 reg;
+
+       reg  = stb0899_read_reg(state, STB0899_VSTATUS);
+       switch (state->delsys) {
+       case SYS_DVBS:
+       case SYS_DSS:
+               if (internal->lock) {
+                       if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
+
+                               stb0899_read_regs(state, STB0899_NIRM, buf, 2);
+                               val = MAKEWORD16(buf[0], buf[1]);
+
+                               *snr = stb0899_table_lookup(stb0899_cn_tab, ARRAY_SIZE(stb0899_cn_tab) - 1, val);
+                               dprintk(state->verbose, FE_DEBUG, 1, "NIR = 0x%02x%02x = %u, C/N = %d * 0.1 dBm\n",
+                                       buf[0], buf[1], val, *snr);
+                       }
+               }
+               break;
+       case SYS_DVBS2:
+               if (internal->lock) {
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_CNTRL1);
+                       quant = STB0899_GETFIELD(UWP_ESN0_QUANT, reg);
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, UWP_STAT2);
+                       est = STB0899_GETFIELD(ESN0_EST, reg);
+                       if (est == 1)
+                               val = 301; /* C/N = 30.1 dB */
+                       else if (est == 2)
+                               val = 270; /* C/N = 27.0 dB */
+                       else {
+                               /* quantn = 100 * log(quant^2) */
+                               quantn = stb0899_table_lookup(stb0899_quant_tab, ARRAY_SIZE(stb0899_quant_tab) - 1, quant * 100);
+                               /* estn = 100 * log(est) */
+                               estn = stb0899_table_lookup(stb0899_est_tab, ARRAY_SIZE(stb0899_est_tab) - 1, est);
+                               /* snr(dBm/10) = -10*(log(est)-log(quant^2)) => snr(dBm/10) = (100*log(quant^2)-100*log(est))/10 */
+                               val = (quantn - estn) / 10;
+                       }
+                       *snr = val;
+                       dprintk(state->verbose, FE_DEBUG, 1, "Es/N0 quant = %d (%d) estimate = %u (%d), C/N = %d * 0.1 dBm",
+                               quant, quantn, est, estn, val);
+               }
+               break;
+       default:
+               dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int stb0899_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+       struct stb0899_state *state             = fe->demodulator_priv;
+       struct stb0899_internal *internal       = &state->internal;
+       u8 reg;
+       *status = 0;
+
+       switch (state->delsys) {
+       case SYS_DVBS:
+       case SYS_DSS:
+               dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S/DSS");
+               if (internal->lock) {
+                       reg  = stb0899_read_reg(state, STB0899_VSTATUS);
+                       if (STB0899_GETFIELD(VSTATUS_LOCKEDVIT, reg)) {
+                               dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_CARRIER | FE_HAS_LOCK");
+                               *status |= FE_HAS_CARRIER | FE_HAS_LOCK;
+
+                               reg = stb0899_read_reg(state, STB0899_PLPARM);
+                               if (STB0899_GETFIELD(VITCURPUN, reg)) {
+                                       dprintk(state->verbose, FE_DEBUG, 1, "--------> FE_HAS_VITERBI | FE_HAS_SYNC");
+                                       *status |= FE_HAS_VITERBI | FE_HAS_SYNC;
+                                       /* post process event */
+                                       stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
+                               }
+                       }
+               }
+               break;
+       case SYS_DVBS2:
+               dprintk(state->verbose, FE_DEBUG, 1, "Delivery system DVB-S2");
+               if (internal->lock) {
+                       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_STAT2);
+                       if (STB0899_GETFIELD(UWP_LOCK, reg) && STB0899_GETFIELD(CSM_LOCK, reg)) {
+                               *status |= FE_HAS_CARRIER;
+                               dprintk(state->verbose, FE_DEBUG, 1,
+                                       "UWP & CSM Lock ! ---> DVB-S2 FE_HAS_CARRIER");
+
+                               reg = stb0899_read_reg(state, STB0899_CFGPDELSTATUS1);
+                               if (STB0899_GETFIELD(CFGPDELSTATUS_LOCK, reg)) {
+                                       *status |= FE_HAS_LOCK;
+                                       dprintk(state->verbose, FE_DEBUG, 1,
+                                               "Packet Delineator Locked ! -----> DVB-S2 FE_HAS_LOCK");
+
+                               }
+                               if (STB0899_GETFIELD(CONTINUOUS_STREAM, reg)) {
+                                       *status |= FE_HAS_VITERBI;
+                                       dprintk(state->verbose, FE_DEBUG, 1,
+                                               "Packet Delineator found VITERBI ! -----> DVB-S2 FE_HAS_VITERBI");
+                               }
+                               if (STB0899_GETFIELD(ACCEPTED_STREAM, reg)) {
+                                       *status |= FE_HAS_SYNC;
+                                       dprintk(state->verbose, FE_DEBUG, 1,
+                                               "Packet Delineator found SYNC ! -----> DVB-S2 FE_HAS_SYNC");
+                                       /* post process event */
+                                       stb0899_postproc(state, STB0899_POSTPROC_GPIO_LOCK, 1);
+                               }
+                       }
+               }
+               break;
+       default:
+               dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * stb0899_get_error
+ * viterbi error for DVB-S/DSS
+ * packet error for DVB-S2
+ * Bit Error Rate or Packet Error Rate * 10 ^ 7
+ */
+static int stb0899_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct stb0899_state *state             = fe->demodulator_priv;
+       struct stb0899_internal *internal       = &state->internal;
+
+       u8  lsb, msb;
+       u32 i;
+
+       *ber = 0;
+
+       switch (state->delsys) {
+       case SYS_DVBS:
+       case SYS_DSS:
+               if (internal->lock) {
+                       /* average 5 BER values */
+                       for (i = 0; i < 5; i++) {
+                               msleep(100);
+                               lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+                               msb = stb0899_read_reg(state, STB0899_ECNT1M);
+                               *ber += MAKEWORD16(msb, lsb);
+                       }
+                       *ber /= 5;
+                       /* Viterbi Check        */
+                       if (STB0899_GETFIELD(VSTATUS_PRFVIT, internal->v_status)) {
+                               /* Error Rate           */
+                               *ber *= 9766;
+                               /* ber = ber * 10 ^ 7   */
+                               *ber /= (-1 + (1 << (2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
+                               *ber /= 8;
+                       }
+               }
+               break;
+       case SYS_DVBS2:
+               if (internal->lock) {
+                       /* Average 5 PER values */
+                       for (i = 0; i < 5; i++) {
+                               msleep(100);
+                               lsb = stb0899_read_reg(state, STB0899_ECNT1L);
+                               msb = stb0899_read_reg(state, STB0899_ECNT1M);
+                               *ber += MAKEWORD16(msb, lsb);
+                       }
+                       /* ber = ber * 10 ^ 7   */
+                       *ber *= 10000000;
+                       *ber /= (-1 + (1 << (4 + 2 * STB0899_GETFIELD(NOE, internal->err_ctrl))));
+               }
+               break;
+       default:
+               dprintk(state->verbose, FE_DEBUG, 1, "Unsupported delivery system");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int stb0899_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_13:
+               stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
+               stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
+               stb0899_write_reg(state, STB0899_GPIO02CFG, 0x00);
+               break;
+       case SEC_VOLTAGE_18:
+               stb0899_write_reg(state, STB0899_GPIO00CFG, 0x02);
+               stb0899_write_reg(state, STB0899_GPIO01CFG, 0x02);
+               stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
+               break;
+       case SEC_VOLTAGE_OFF:
+               stb0899_write_reg(state, STB0899_GPIO00CFG, 0x82);
+               stb0899_write_reg(state, STB0899_GPIO01CFG, 0x82);
+               stb0899_write_reg(state, STB0899_GPIO02CFG, 0x82);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int stb0899_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+       struct stb0899_internal *internal = &state->internal;
+
+       u8 div, reg;
+
+       /* wait for diseqc idle */
+       if (stb0899_wait_diseqc_txidle(state, 100) < 0)
+               return -ETIMEDOUT;
+
+       switch (tone) {
+       case SEC_TONE_ON:
+               div = (internal->master_clk / 100) / 5632;
+               div = (div + 5) / 10;
+               stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x66);
+               reg = stb0899_read_reg(state, STB0899_ACRPRESC);
+               STB0899_SETFIELD_VAL(ACRPRESC, reg, 0x03);
+               stb0899_write_reg(state, STB0899_ACRPRESC, reg);
+               stb0899_write_reg(state, STB0899_ACRDIV1, div);
+               break;
+       case SEC_TONE_OFF:
+               stb0899_write_reg(state, STB0899_DISEQCOCFG, 0x20);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       int i2c_stat;
+       struct stb0899_state *state = fe->demodulator_priv;
+
+       i2c_stat = stb0899_read_reg(state, STB0899_I2CRPT);
+       if (i2c_stat < 0)
+               goto err;
+
+       if (enable) {
+               dprintk(state->verbose, FE_DEBUG, 1, "Enabling I2C Repeater ...");
+               i2c_stat |=  STB0899_I2CTON;
+               if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
+                       goto err;
+       } else {
+               dprintk(state->verbose, FE_DEBUG, 1, "Disabling I2C Repeater ...");
+               i2c_stat &= ~STB0899_I2CTON;
+               if (stb0899_write_reg(state, STB0899_I2CRPT, i2c_stat) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(state->verbose, FE_ERROR, 1, "I2C Repeater control failed");
+       return -EREMOTEIO;
+}
+
+
+static inline void CONVERT32(u32 x, char *str)
+{
+       *str++  = (x >> 24) & 0xff;
+       *str++  = (x >> 16) & 0xff;
+       *str++  = (x >>  8) & 0xff;
+       *str++  = (x >>  0) & 0xff;
+       *str    = '\0';
+}
+
+int stb0899_get_dev_id(struct stb0899_state *state)
+{
+       u8 chip_id, release;
+       u16 id;
+       u32 demod_ver = 0, fec_ver = 0;
+       char demod_str[5] = { 0 };
+       char fec_str[5] = { 0 };
+
+       id = stb0899_read_reg(state, STB0899_DEV_ID);
+       dprintk(state->verbose, FE_DEBUG, 1, "ID reg=[0x%02x]", id);
+       chip_id = STB0899_GETFIELD(CHIP_ID, id);
+       release = STB0899_GETFIELD(CHIP_REL, id);
+
+       dprintk(state->verbose, FE_ERROR, 1, "Device ID=[%d], Release=[%d]",
+               chip_id, release);
+
+       CONVERT32(STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_CORE_ID), (char *)&demod_str);
+
+       demod_ver = STB0899_READ_S2REG(STB0899_S2DEMOD, DMD_VERSION_ID);
+       dprintk(state->verbose, FE_ERROR, 1, "Demodulator Core ID=[%s], Version=[%d]", (char *) &demod_str, demod_ver);
+       CONVERT32(STB0899_READ_S2REG(STB0899_S2FEC, FEC_CORE_ID_REG), (char *)&fec_str);
+       fec_ver = STB0899_READ_S2REG(STB0899_S2FEC, FEC_VER_ID_REG);
+       if (! (chip_id > 0)) {
+               dprintk(state->verbose, FE_ERROR, 1, "couldn't find a STB 0899");
+
+               return -ENODEV;
+       }
+       dprintk(state->verbose, FE_ERROR, 1, "FEC Core ID=[%s], Version=[%d]", (char*) &fec_str, fec_ver);
+
+       return 0;
+}
+
+static void stb0899_set_delivery(struct stb0899_state *state)
+{
+       u8 reg;
+       u8 stop_clk[2];
+
+       stop_clk[0] = stb0899_read_reg(state, STB0899_STOPCLK1);
+       stop_clk[1] = stb0899_read_reg(state, STB0899_STOPCLK2);
+
+       switch (state->delsys) {
+       case SYS_DVBS:
+               dprintk(state->verbose, FE_DEBUG, 1, "Delivery System -- DVB-S");
+               /* FECM/Viterbi ON      */
+               reg = stb0899_read_reg(state, STB0899_FECM);
+               STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
+               STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
+               stb0899_write_reg(state, STB0899_FECM, reg);
+
+               stb0899_write_reg(state, STB0899_RSULC, 0xb1);
+               stb0899_write_reg(state, STB0899_TSULC, 0x40);
+               stb0899_write_reg(state, STB0899_RSLLC, 0x42);
+               stb0899_write_reg(state, STB0899_TSLPL, 0x12);
+
+               reg = stb0899_read_reg(state, STB0899_TSTRES);
+               STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
+               stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+               STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
+               STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
+               STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
+
+               STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
+               STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
+
+               STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 1);
+               STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
+
+               STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
+               break;
+       case SYS_DVBS2:
+               /* FECM/Viterbi OFF     */
+               reg = stb0899_read_reg(state, STB0899_FECM);
+               STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 0);
+               STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 0);
+               stb0899_write_reg(state, STB0899_FECM, reg);
+
+               stb0899_write_reg(state, STB0899_RSULC, 0xb1);
+               stb0899_write_reg(state, STB0899_TSULC, 0x42);
+               stb0899_write_reg(state, STB0899_RSLLC, 0x40);
+               stb0899_write_reg(state, STB0899_TSLPL, 0x02);
+
+               reg = stb0899_read_reg(state, STB0899_TSTRES);
+               STB0899_SETFIELD_VAL(FRESLDPC, reg, 0);
+               stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+               STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
+               STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 0);
+               STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 0);
+
+               STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 0);
+               STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 0);
+
+               STB0899_SETFIELD_VAL(STOP_CKINTBUF216, stop_clk[0], 0);
+               STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
+
+               STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 0);
+               break;
+       case SYS_DSS:
+               /* FECM/Viterbi ON      */
+               reg = stb0899_read_reg(state, STB0899_FECM);
+               STB0899_SETFIELD_VAL(FECM_RSVD0, reg, 1);
+               STB0899_SETFIELD_VAL(FECM_VITERBI_ON, reg, 1);
+               stb0899_write_reg(state, STB0899_FECM, reg);
+
+               stb0899_write_reg(state, STB0899_RSULC, 0xa1);
+               stb0899_write_reg(state, STB0899_TSULC, 0x61);
+               stb0899_write_reg(state, STB0899_RSLLC, 0x42);
+
+               reg = stb0899_read_reg(state, STB0899_TSTRES);
+               STB0899_SETFIELD_VAL(FRESLDPC, reg, 1);
+               stb0899_write_reg(state, STB0899_TSTRES, reg);
+
+               STB0899_SETFIELD_VAL(STOP_CHK8PSK, stop_clk[0], 1);
+               STB0899_SETFIELD_VAL(STOP_CKFEC108, stop_clk[0], 1);
+               STB0899_SETFIELD_VAL(STOP_CKFEC216, stop_clk[0], 1);
+
+               STB0899_SETFIELD_VAL(STOP_CKPKDLIN108, stop_clk[1], 1);
+               STB0899_SETFIELD_VAL(STOP_CKPKDLIN216, stop_clk[1], 1);
+
+               STB0899_SETFIELD_VAL(STOP_CKCORE216, stop_clk[0], 0);
+
+               STB0899_SETFIELD_VAL(STOP_CKS2DMD108, stop_clk[1], 1);
+               break;
+       default:
+               dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
+               break;
+       }
+       STB0899_SETFIELD_VAL(STOP_CKADCI108, stop_clk[0], 0);
+       stb0899_write_regs(state, STB0899_STOPCLK1, stop_clk, 2);
+}
+
+/*
+ * stb0899_set_iterations
+ * set the LDPC iteration scale function
+ */
+static void stb0899_set_iterations(struct stb0899_state *state)
+{
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_config *config = state->config;
+
+       s32 iter_scale;
+       u32 reg;
+
+       iter_scale = 17 * (internal->master_clk / 1000);
+       iter_scale += 410000;
+       iter_scale /= (internal->srate / 1000000);
+       iter_scale /= 1000;
+
+       if (iter_scale > config->ldpc_max_iter)
+               iter_scale = config->ldpc_max_iter;
+
+       reg = STB0899_READ_S2REG(STB0899_S2DEMOD, MAX_ITER);
+       STB0899_SETFIELD_VAL(MAX_ITERATIONS, reg, iter_scale);
+       stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_MAX_ITER, STB0899_OFF0_MAX_ITER, reg);
+}
+
+static enum dvbfe_search stb0899_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct stb0899_state *state = fe->demodulator_priv;
+       struct stb0899_params *i_params = &state->params;
+       struct stb0899_internal *internal = &state->internal;
+       struct stb0899_config *config = state->config;
+       struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+
+       u32 SearchRange, gain;
+
+       i_params->freq  = p->frequency;
+       i_params->srate = p->u.qpsk.symbol_rate;
+       state->delsys = props->delivery_system;
+       dprintk(state->verbose, FE_DEBUG, 1, "delivery system=%d", state->delsys);
+
+       SearchRange = 10000000;
+       dprintk(state->verbose, FE_DEBUG, 1, "Frequency=%d, Srate=%d", i_params->freq, i_params->srate);
+       /* checking Search Range is meaningless for a fixed 3 Mhz                       */
+       if (INRANGE(i_params->srate, 1000000, 45000000)) {
+               dprintk(state->verbose, FE_DEBUG, 1, "Parameters IN RANGE");
+               stb0899_set_delivery(state);
+
+               if (state->config->tuner_set_rfsiggain) {
+                       if (internal->srate > 15000000)
+                               gain =  8; /* 15Mb < srate < 45Mb, gain = 8dB   */
+                       else if (internal->srate > 5000000)
+                               gain = 12; /*  5Mb < srate < 15Mb, gain = 12dB  */
+                       else
+                               gain = 14; /*  1Mb < srate <  5Mb, gain = 14db  */
+                       state->config->tuner_set_rfsiggain(fe, gain);
+               }
+
+               if (i_params->srate <= 5000000)
+                       stb0899_set_mclk(state, config->lo_clk);
+               else
+                       stb0899_set_mclk(state, config->hi_clk);
+
+               switch (state->delsys) {
+               case SYS_DVBS:
+               case SYS_DSS:
+                       dprintk(state->verbose, FE_DEBUG, 1, "DVB-S delivery system");
+                       internal->freq  = i_params->freq;
+                       internal->srate = i_params->srate;
+                       /*
+                        * search = user search range +
+                        *          500Khz +
+                        *          2 * Tuner_step_size +
+                        *          10% of the symbol rate
+                        */
+                       internal->srch_range    = SearchRange + 1500000 + (i_params->srate / 5);
+                       internal->derot_percent = 30;
+
+                       /* What to do for tuners having no bandwidth setup ?    */
+                       /* enable tuner I/O */
+                       stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+                       if (state->config->tuner_set_bandwidth)
+                               state->config->tuner_set_bandwidth(fe, (13 * (stb0899_carr_width(state) + SearchRange)) / 10);
+                       if (state->config->tuner_get_bandwidth)
+                               state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
+
+                       /* disable tuner I/O */
+                       stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+                       /* Set DVB-S1 AGC               */
+                       stb0899_write_reg(state, STB0899_AGCRFCFG, 0x11);
+
+                       /* Run the search algorithm     */
+                       dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S search algo ..");
+                       if (stb0899_dvbs_algo(state)    == RANGEOK) {
+                               internal->lock          = 1;
+                               dprintk(state->verbose, FE_DEBUG, 1,
+                                       "-------------------------------------> DVB-S LOCK !");
+
+//                             stb0899_write_reg(state, STB0899_ERRCTRL1, 0x3d); /* Viterbi Errors     */
+//                             internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
+//                             internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
+//                             dprintk(state->verbose, FE_DEBUG, 1, "VSTATUS=0x%02x", internal->v_status);
+//                             dprintk(state->verbose, FE_DEBUG, 1, "ERR_CTRL=0x%02x", internal->err_ctrl);
+
+                               return DVBFE_ALGO_SEARCH_SUCCESS;
+                       } else {
+                               internal->lock          = 0;
+
+                               return DVBFE_ALGO_SEARCH_FAILED;
+                       }
+                       break;
+               case SYS_DVBS2:
+                       internal->freq                  = i_params->freq;
+                       internal->srate                 = i_params->srate;
+                       internal->srch_range            = SearchRange;
+
+                       /* enable tuner I/O */
+                       stb0899_i2c_gate_ctrl(&state->frontend, 1);
+
+                       if (state->config->tuner_set_bandwidth)
+                               state->config->tuner_set_bandwidth(fe, (stb0899_carr_width(state) + SearchRange));
+                       if (state->config->tuner_get_bandwidth)
+                               state->config->tuner_get_bandwidth(fe, &internal->tuner_bw);
+
+                       /* disable tuner I/O */
+                       stb0899_i2c_gate_ctrl(&state->frontend, 0);
+
+//                     pParams->SpectralInv            = pSearch->IQ_Inversion;
+
+                       /* Set DVB-S2 AGC               */
+                       stb0899_write_reg(state, STB0899_AGCRFCFG, 0x1c);
+
+                       /* Set IterScale =f(MCLK,SYMB)  */
+                       stb0899_set_iterations(state);
+
+                       /* Run the search algorithm     */
+                       dprintk(state->verbose, FE_DEBUG, 1, "running DVB-S2 search algo ..");
+                       if (stb0899_dvbs2_algo(state)   == DVBS2_FEC_LOCK) {
+                               internal->lock          = 1;
+                               dprintk(state->verbose, FE_DEBUG, 1,
+                                       "-------------------------------------> DVB-S2 LOCK !");
+
+//                             stb0899_write_reg(state, STB0899_ERRCTRL1, 0xb6); /* Packet Errors      */
+//                             internal->v_status = stb0899_read_reg(state, STB0899_VSTATUS);
+//                             internal->err_ctrl = stb0899_read_reg(state, STB0899_ERRCTRL1);
+
+                               return DVBFE_ALGO_SEARCH_SUCCESS;
+                       } else {
+                               internal->lock          = 0;
+
+                               return DVBFE_ALGO_SEARCH_FAILED;
+                       }
+                       break;
+               default:
+                       dprintk(state->verbose, FE_ERROR, 1, "Unsupported delivery system");
+                       return DVBFE_ALGO_SEARCH_INVALID;
+               }
+       }
+
+       return DVBFE_ALGO_SEARCH_ERROR;
+}
+/*
+ * stb0899_track
+ * periodically check the signal level against a specified
+ * threshold level and perform derotator centering.
+ * called once we have a lock from a succesful search
+ * event.
+ *
+ * Will be called periodically called to maintain the
+ * lock.
+ *
+ * Will be used to get parameters as well as info from
+ * the decoded baseband header
+ *
+ * Once a new lock has established, the internal state
+ * frequency (internal->freq) is updated
+ */
+static int stb0899_track(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       return 0;
+}
+
+static int stb0899_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct stb0899_state *state             = fe->demodulator_priv;
+       struct stb0899_internal *internal       = &state->internal;
+
+       dprintk(state->verbose, FE_DEBUG, 1, "Get params");
+       p->u.qpsk.symbol_rate = internal->srate;
+
+       return 0;
+}
+
+static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops stb0899_ops = {
+
+       .info = {
+               .name                   = "STB0899 Multistandard",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 0,
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        =  5000000,
+               .symbol_rate_max        = 45000000,
+
+               .caps                   = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_FEC_AUTO       |
+                                         FE_CAN_QPSK
+       },
+
+       .release                        = stb0899_release,
+       .init                           = stb0899_init,
+       .sleep                          = stb0899_sleep,
+//     .wakeup                         = stb0899_wakeup,
+
+       .i2c_gate_ctrl                  = stb0899_i2c_gate_ctrl,
+
+       .get_frontend_algo              = stb0899_frontend_algo,
+       .search                         = stb0899_search,
+       .track                          = stb0899_track,
+       .get_frontend                   = stb0899_get_frontend,
+
+
+       .read_status                    = stb0899_read_status,
+       .read_snr                       = stb0899_read_snr,
+       .read_signal_strength           = stb0899_read_signal_strength,
+       .read_ber                       = stb0899_read_ber,
+
+       .set_voltage                    = stb0899_set_voltage,
+       .set_tone                       = stb0899_set_tone,
+
+       .diseqc_send_master_cmd         = stb0899_send_diseqc_msg,
+       .diseqc_recv_slave_reply        = stb0899_recv_slave_reply,
+       .diseqc_send_burst              = stb0899_send_diseqc_burst,
+};
+
+struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c)
+{
+       struct stb0899_state *state = NULL;
+       enum stb0899_inversion inversion;
+
+       state = kzalloc(sizeof (struct stb0899_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       inversion                               = config->inversion;
+       state->verbose                          = &verbose;
+       state->config                           = config;
+       state->i2c                              = i2c;
+       state->frontend.ops                     = stb0899_ops;
+       state->frontend.demodulator_priv        = state;
+       state->internal.inversion               = inversion;
+
+       stb0899_wakeup(&state->frontend);
+       if (stb0899_get_dev_id(state) == -ENODEV) {
+               printk("%s: Exiting .. !\n", __func__);
+               goto error;
+       }
+
+       printk("%s: Attaching STB0899 \n", __func__);
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(stb0899_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STB0899 Multi-Std frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb0899_drv.h b/drivers/media/dvb/frontends/stb0899_drv.h
new file mode 100644 (file)
index 0000000..98b200c
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+       STB0899 Multistandard Frontend driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#ifndef __STB0899_DRV_H
+#define __STB0899_DRV_H
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+
+#define STB0899_TSMODE_SERIAL          1
+#define STB0899_CLKPOL_FALLING         2
+#define STB0899_CLKNULL_PARITY         3
+#define STB0899_SYNC_FORCED            4
+#define STB0899_FECMODE_DSS            5
+
+struct stb0899_s1_reg {
+       u16     address;
+       u8      data;
+};
+
+struct stb0899_s2_reg {
+       u16     offset;
+       u32     base_address;
+       u32     data;
+};
+
+enum stb0899_inversion {
+       IQ_SWAP_OFF     = 0,
+       IQ_SWAP_ON,
+       IQ_SWAP_AUTO
+};
+
+#define STB0899_GPIO00                         0xf140
+#define STB0899_GPIO01                         0xf141
+#define STB0899_GPIO02                         0xf142
+#define STB0899_GPIO03                         0xf143
+#define STB0899_GPIO04                         0xf144
+#define STB0899_GPIO05                         0xf145
+#define STB0899_GPIO06                         0xf146
+#define STB0899_GPIO07                         0xf147
+#define STB0899_GPIO08                         0xf148
+#define STB0899_GPIO09                         0xf149
+#define STB0899_GPIO10                         0xf14a
+#define STB0899_GPIO11                         0xf14b
+#define STB0899_GPIO12                         0xf14c
+#define STB0899_GPIO13                         0xf14d
+#define STB0899_GPIO14                         0xf14e
+#define STB0899_GPIO15                         0xf14f
+#define STB0899_GPIO16                         0xf150
+#define STB0899_GPIO17                         0xf151
+#define STB0899_GPIO18                         0xf152
+#define STB0899_GPIO19                         0xf153
+#define STB0899_GPIO20                         0xf154
+
+#define STB0899_GPIOPULLUP                     0x01 /* Output device is connected to Vdd */
+#define STB0899_GPIOPULLDN                     0x00 /* Output device is connected to Vss */
+
+#define STB0899_POSTPROC_GPIO_POWER            0x00
+#define STB0899_POSTPROC_GPIO_LOCK             0x01
+
+/*
+ * Post process output configuration control
+ * 1. POWER ON/OFF             (index 0)
+ * 2. FE_HAS_LOCK/LOCK_LOSS    (index 1)
+ *
+ * @gpio       = one of the above listed GPIO's
+ * @level      = output state: pulled up or low
+ */
+struct stb0899_postproc {
+       u16     gpio;
+       u8      level;
+};
+
+struct stb0899_config {
+       const struct stb0899_s1_reg     *init_dev;
+       const struct stb0899_s2_reg     *init_s2_demod;
+       const struct stb0899_s1_reg     *init_s1_demod;
+       const struct stb0899_s2_reg     *init_s2_fec;
+       const struct stb0899_s1_reg     *init_tst;
+
+       const struct stb0899_postproc   *postproc;
+
+       enum stb0899_inversion          inversion;
+
+       u32     xtal_freq;
+
+       u8      demod_address;
+       u8      ts_output_mode;
+       u8      block_sync_mode;
+       u8      ts_pfbit_toggle;
+
+       u8      clock_polarity;
+       u8      data_clk_parity;
+       u8      fec_mode;
+       u8      data_output_ctl;
+       u8      data_fifo_mode;
+       u8      out_rate_comp;
+       u8      i2c_repeater;
+//     int     inversion;
+       int     lo_clk;
+       int     hi_clk;
+
+       u32     esno_ave;
+       u32     esno_quant;
+       u32     avframes_coarse;
+       u32     avframes_fine;
+       u32     miss_threshold;
+       u32     uwp_threshold_acq;
+       u32     uwp_threshold_track;
+       u32     uwp_threshold_sof;
+       u32     sof_search_timeout;
+
+       u32     btr_nco_bits;
+       u32     btr_gain_shift_offset;
+       u32     crl_nco_bits;
+       u32     ldpc_max_iter;
+
+       int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency);
+       int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+       int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+       int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+       int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain);
+};
+
+#if defined(CONFIG_DVB_STB0899) || (defined(CONFIG_DVB_STB0899_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
+                                          struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *stb0899_attach(struct stb0899_config *config,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif //CONFIG_DVB_STB0899
+
+
+#endif
diff --git a/drivers/media/dvb/frontends/stb0899_priv.h b/drivers/media/dvb/frontends/stb0899_priv.h
new file mode 100644 (file)
index 0000000..24619e3
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+       STB0899 Multistandard Frontend driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#ifndef __STB0899_PRIV_H
+#define __STB0899_PRIV_H
+
+#include "dvb_frontend.h"
+#include "stb0899_drv.h"
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(x, y, z, format, arg...) do {                                          \
+       if (z) {                                                                        \
+               if      ((*x > FE_ERROR) && (*x > y))                                   \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((*x > FE_NOTICE) && (*x > y))                                  \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((*x > FE_INFO) && (*x > y))                                    \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((*x > FE_DEBUG) && (*x > y))                                   \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (*x > y)                                                             \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while(0)
+
+#define INRANGE(val, x, y)                     (((x <= val) && (val <= y)) ||          \
+                                                ((y <= val) && (val <= x)) ? 1 : 0)
+
+#define BYTE0                                  0
+#define BYTE1                                  8
+#define BYTE2                                  16
+#define BYTE3                                  24
+
+#define GETBYTE(x, y)                          (((x) >> (y)) & 0xff)
+#define MAKEWORD32(a, b, c, d)                 (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+#define MAKEWORD16(a, b)                       (((a) << 8) | (b))
+
+#define MIN(x, y)                              ((x) <= (y) ? (x) : (y))
+#define MAX(x, y)                              ((x) >= (y) ? (x) : (y))
+#define ABS(x)                                 ((x) >= 0 ? (x) : -(x))
+
+#define LSB(x)                                 ((x & 0xff))
+#define MSB(y)                                 ((y >> 8) & 0xff)
+
+
+#define STB0899_GETFIELD(bitf, val)            ((val >> STB0899_OFFST_##bitf) & ((1 << STB0899_WIDTH_##bitf) - 1))
+
+
+#define STB0899_SETFIELD(mask, val, width, offset)      (mask & (~(((1 << width) - 1) <<       \
+                                                        offset))) | ((val &                    \
+                                                        ((1 << width) - 1)) << offset)
+
+#define STB0899_SETFIELD_VAL(bitf, mask, val)  (mask = (mask & (~(((1 << STB0899_WIDTH_##bitf) - 1) <<\
+                                                        STB0899_OFFST_##bitf))) | \
+                                                        (val << STB0899_OFFST_##bitf))
+
+
+enum stb0899_status {
+       NOAGC1  = 0,
+       AGC1OK,
+       NOTIMING,
+       ANALOGCARRIER,
+       TIMINGOK,
+       NOAGC2,
+       AGC2OK,
+       NOCARRIER,
+       CARRIEROK,
+       NODATA,
+       FALSELOCK,
+       DATAOK,
+       OUTOFRANGE,
+       RANGEOK,
+       DVBS2_DEMOD_LOCK,
+       DVBS2_DEMOD_NOLOCK,
+       DVBS2_FEC_LOCK,
+       DVBS2_FEC_NOLOCK
+};
+
+enum stb0899_modcod {
+       STB0899_DUMMY_PLF,
+       STB0899_QPSK_14,
+       STB0899_QPSK_13,
+       STB0899_QPSK_25,
+       STB0899_QPSK_12,
+       STB0899_QPSK_35,
+       STB0899_QPSK_23,
+       STB0899_QPSK_34,
+       STB0899_QPSK_45,
+       STB0899_QPSK_56,
+       STB0899_QPSK_89,
+       STB0899_QPSK_910,
+       STB0899_8PSK_35,
+       STB0899_8PSK_23,
+       STB0899_8PSK_34,
+       STB0899_8PSK_56,
+       STB0899_8PSK_89,
+       STB0899_8PSK_910,
+       STB0899_16APSK_23,
+       STB0899_16APSK_34,
+       STB0899_16APSK_45,
+       STB0899_16APSK_56,
+       STB0899_16APSK_89,
+       STB0899_16APSK_910,
+       STB0899_32APSK_34,
+       STB0899_32APSK_45,
+       STB0899_32APSK_56,
+       STB0899_32APSK_89,
+       STB0899_32APSK_910
+};
+
+enum stb0899_frame {
+       STB0899_LONG_FRAME,
+       STB0899_SHORT_FRAME
+};
+
+enum stb0899_alpha {
+       RRC_20,
+       RRC_25,
+       RRC_35
+};
+
+struct stb0899_tab {
+       s32 real;
+       s32 read;
+};
+
+enum stb0899_fec {
+       STB0899_FEC_1_2                 = 13,
+       STB0899_FEC_2_3                 = 18,
+       STB0899_FEC_3_4                 = 21,
+       STB0899_FEC_5_6                 = 24,
+       STB0899_FEC_6_7                 = 25,
+       STB0899_FEC_7_8                 = 26
+};
+
+struct stb0899_params {
+       u32     freq;                                   /* Frequency    */
+       u32     srate;                                  /* Symbol rate  */
+       enum fe_code_rate fecrate;
+};
+
+struct stb0899_internal {
+       u32                     master_clk;
+       u32                     freq;                   /* Demod internal Frequency             */
+       u32                     srate;                  /* Demod internal Symbol rate           */
+       enum stb0899_fec        fecrate;                /* Demod internal FEC rate              */
+       u32                     srch_range;             /* Demod internal Search Range          */
+       u32                     sub_range;              /* Demod current sub range (Hz)         */
+       u32                     tuner_step;             /* Tuner step (Hz)                      */
+       u32                     tuner_offst;            /* Relative offset to carrier (Hz)      */
+       u32                     tuner_bw;               /* Current bandwidth of the tuner (Hz)  */
+
+       s32                     mclk;                   /* Masterclock Divider factor (binary)  */
+       s32                     rolloff;                /* Current RollOff of the filter (x100) */
+
+       s16                     derot_freq;             /* Current derotator frequency (Hz)     */
+       s16                     derot_percent;
+
+       s16                     direction;              /* Current derotator search direction   */
+       s16                     derot_step;             /* Derotator step (binary value)        */
+       s16                     t_derot;                /* Derotator time constant (ms)         */
+       s16                     t_data;                 /* Data recovery time constant (ms)     */
+       s16                     sub_dir;                /* Direction of the next sub range      */
+
+       s16                     t_agc1;                 /* Agc1 time constant (ms)              */
+       s16                     t_agc2;                 /* Agc2 time constant (ms)              */
+
+       u32                     lock;                   /* Demod internal lock state            */
+       enum stb0899_status     status;                 /* Demod internal status                */
+
+       /* DVB-S2 */
+       s32                     agc_gain;               /* RF AGC Gain                          */
+       s32                     center_freq;            /* Nominal carrier frequency            */
+       s32                     av_frame_coarse;        /* Coarse carrier freq search frames    */
+       s32                     av_frame_fine;          /* Fine carrier freq search frames      */
+
+       s16                     step_size;              /* Carrier frequency search step size   */
+
+       enum stb0899_alpha      rrc_alpha;
+       enum stb0899_inversion  inversion;
+       enum stb0899_modcod     modcod;
+       u8                      pilots;                 /* Pilots found                         */
+
+       enum stb0899_frame      frame_length;
+       u8                      v_status;               /* VSTATUS                              */
+       u8                      err_ctrl;               /* ERRCTRLn                             */
+};
+
+struct stb0899_state {
+       struct i2c_adapter              *i2c;
+       struct stb0899_config           *config;
+       struct dvb_frontend             frontend;
+
+       u32                             *verbose;       /* Cached module verbosity level        */
+
+       struct stb0899_internal         internal;       /* Device internal parameters           */
+
+       /*      cached params from API  */
+       enum fe_delivery_system         delsys;
+       struct stb0899_params           params;
+
+       u32                             rx_freq;        /* DiSEqC 2.0 receiver freq             */
+       struct mutex                    search_lock;
+};
+/* stb0899.c           */
+extern int stb0899_read_reg(struct stb0899_state *state,
+                           unsigned int reg);
+
+extern u32 _stb0899_read_s2reg(struct stb0899_state *state,
+                              u32 stb0899_i2cdev,
+                              u32 stb0899_base_addr,
+                              u16 stb0899_reg_offset);
+
+extern int stb0899_read_regs(struct stb0899_state *state,
+                            unsigned int reg, u8 *buf,
+                            u32 count);
+
+extern int stb0899_write_regs(struct stb0899_state *state,
+                             unsigned int reg, u8 *data,
+                             u32 count);
+
+extern int stb0899_write_reg(struct stb0899_state *state,
+                            unsigned int reg,
+                            u8 data);
+
+extern int stb0899_write_s2reg(struct stb0899_state *state,
+                              u32 stb0899_i2cdev,
+                              u32 stb0899_base_addr,
+                              u16 stb0899_reg_offset,
+                              u32 stb0899_data);
+
+extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+
+
+#define STB0899_READ_S2REG(DEVICE, REG)        (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG))
+//#define STB0899_WRITE_S2REG(DEVICE, REG, DATA)       (_stb0899_write_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG, DATA))
+
+/* stb0899_algo.c      */
+extern enum stb0899_status stb0899_dvbs_algo(struct stb0899_state *state);
+extern enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state);
+extern long stb0899_carr_width(struct stb0899_state *state);
+
+#endif //__STB0899_PRIV_H
diff --git a/drivers/media/dvb/frontends/stb0899_reg.h b/drivers/media/dvb/frontends/stb0899_reg.h
new file mode 100644 (file)
index 0000000..ba1ed56
--- /dev/null
@@ -0,0 +1,2027 @@
+/*
+       STB0899 Multistandard Frontend driver
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#ifndef __STB0899_REG_H
+#define __STB0899_REG_H
+
+/*     S1      */
+#define STB0899_DEV_ID                         0xf000
+#define STB0899_CHIP_ID                                (0x0f << 4)
+#define STB0899_OFFST_CHIP_ID                  4
+#define STB0899_WIDTH_CHIP_ID                  4
+#define STB0899_CHIP_REL                       (0x0f << 0)
+#define STB0899_OFFST_CHIP_REL                 0
+#define STB0899_WIDTH_CHIP_REL                 4
+
+#define STB0899_DEMOD                          0xf40e
+#define STB0899_MODECOEFF                      (0x01 << 0)
+#define STB0899_OFFST_MODECOEFF                        0
+#define STB0899_WIDTH_MODECOEFF                        1
+
+#define STB0899_RCOMPC                         0xf410
+#define STB0899_AGC1CN                         0xf412
+#define STB0899_AGC1REF                                0xf413
+#define STB0899_RTC                            0xf417
+#define STB0899_TMGCFG                         0xf418
+#define STB0899_AGC2REF                                0xf419
+#define STB0899_TLSR                           0xf41a
+
+#define STB0899_CFD                            0xf41b
+#define STB0899_CFD_ON                         (0x01 << 7)
+#define STB0899_OFFST_CFD_ON                   7
+#define STB0899_WIDTH_CFD_ON                   1
+
+#define STB0899_ACLC                           0xf41c
+
+#define STB0899_BCLC                           0xf41d
+#define STB0899_OFFST_ALGO                     6
+#define STB0899_WIDTH_ALGO_QPSK2               2
+#define STB0899_ALGO_QPSK2                     (2 << 6)
+#define STB0899_ALGO_QPSK1                     (1 << 6)
+#define STB0899_ALGO_BPSK                      (0 << 6)
+#define STB0899_OFFST_BETA                     0
+#define STB0899_WIDTH_BETA                     6
+
+#define STB0899_EQON                           0xf41e
+#define STB0899_LDT                            0xf41f
+#define STB0899_LDT2                           0xf420
+#define STB0899_EQUALREF                       0xf425
+#define STB0899_TMGRAMP                                0xf426
+#define STB0899_TMGTHD                         0xf427
+#define STB0899_IDCCOMP                                0xf428
+#define STB0899_QDCCOMP                                0xf429
+#define STB0899_POWERI                         0xf42a
+#define STB0899_POWERQ                         0xf42b
+#define STB0899_RCOMP                          0xf42c
+
+#define STB0899_AGCIQIN                                0xf42e
+#define STB0899_AGCIQVALUE                     (0xff << 0)
+#define STB0899_OFFST_AGCIQVALUE               0
+#define STB0899_WIDTH_AGCIQVALUE               8
+
+#define STB0899_AGC2I1                         0xf436
+#define STB0899_AGC2I2                         0xf437
+
+#define STB0899_TLIR                           0xf438
+#define STB0899_TLIR_TMG_LOCK_IND              (0xff << 0)
+#define STB0899_OFFST_TLIR_TMG_LOCK_IND                0
+#define STB0899_WIDTH_TLIR_TMG_LOCK_IND                8
+
+#define STB0899_RTF                            0xf439
+#define STB0899_RTF_TIMING_LOOP_FREQ           (0xff << 0)
+#define STB0899_OFFST_RTF_TIMING_LOOP_FREQ     0
+#define STB0899_WIDTH_RTF_TIMING_LOOP_FREQ     8
+
+#define STB0899_DSTATUS                                0xf43a
+#define STB0899_CARRIER_FOUND                  (0x01 << 7)
+#define STB0899_OFFST_CARRIER_FOUND            7
+#define STB0899_WIDTH_CARRIER_FOUND            1
+#define STB0899_TMG_LOCK                       (0x01 << 6)
+#define STB0899_OFFST_TMG_LOCK                 6
+#define STB0899_WIDTH_TMG_LOCK                 1
+#define STB0899_DEMOD_LOCK                     (0x01 << 5)
+#define STB0899_OFFST_DEMOD_LOCK               5
+#define STB0899_WIDTH_DEMOD_LOCK               1
+#define STB0899_TMG_AUTO                       (0x01 << 4)
+#define STB0899_OFFST_TMG_AUTO                 4
+#define STB0899_WIDTH_TMG_AUTO                 1
+#define STB0899_END_MAIN                       (0x01 << 3)
+#define STB0899_OFFST_END_MAIN                 3
+#define STB0899_WIDTH_END_MAIN                 1
+
+#define STB0899_LDI                            0xf43b
+#define STB0899_OFFST_LDI                      0
+#define STB0899_WIDTH_LDI                      8
+
+#define STB0899_CFRM                           0xf43e
+#define STB0899_OFFST_CFRM                     0
+#define STB0899_WIDTH_CFRM                     8
+
+#define STB0899_CFRL                           0xf43f
+#define STB0899_OFFST_CFRL                     0
+#define STB0899_WIDTH_CFRL                     8
+
+#define STB0899_NIRM                           0xf440
+#define STB0899_OFFST_NIRM                     0
+#define STB0899_WIDTH_NIRM                     8
+
+#define STB0899_NIRL                           0xf441
+#define STB0899_OFFST_NIRL                     0
+#define STB0899_WIDTH_NIRL                     8
+
+#define STB0899_ISYMB                          0xf444
+#define STB0899_QSYMB                          0xf445
+
+#define STB0899_SFRH                           0xf446
+#define STB0899_OFFST_SFRH                     0
+#define STB0899_WIDTH_SFRH                     8
+
+#define STB0899_SFRM                           0xf447
+#define STB0899_OFFST_SFRM                     0
+#define STB0899_WIDTH_SFRM                     8
+
+#define STB0899_SFRL                           0xf448
+#define STB0899_OFFST_SFRL                     4
+#define STB0899_WIDTH_SFRL                     4
+
+#define STB0899_SFRUPH                         0xf44c
+#define STB0899_SFRUPM                         0xf44d
+#define STB0899_SFRUPL                         0xf44e
+
+#define STB0899_EQUAI1                         0xf4e0
+#define STB0899_EQUAQ1                         0xf4e1
+#define STB0899_EQUAI2                         0xf4e2
+#define STB0899_EQUAQ2                         0xf4e3
+#define STB0899_EQUAI3                         0xf4e4
+#define STB0899_EQUAQ3                         0xf4e5
+#define STB0899_EQUAI4                         0xf4e6
+#define STB0899_EQUAQ4                         0xf4e7
+#define STB0899_EQUAI5                         0xf4e8
+#define STB0899_EQUAQ5                         0xf4e9
+
+#define STB0899_DSTATUS2                       0xf50c
+#define STB0899_DS2_TMG_AUTOSRCH               (0x01 << 7)
+#define STB8999_OFFST_DS2_TMG_AUTOSRCH         7
+#define STB0899_WIDTH_DS2_TMG_AUTOSRCH         1
+#define STB0899_DS2_END_MAINLOOP               (0x01 << 6)
+#define STB0899_OFFST_DS2_END_MAINLOOP         6
+#define STB0899_WIDTH_DS2_END_MAINLOOP         1
+#define STB0899_DS2_CFSYNC                     (0x01 << 5)
+#define STB0899_OFFST_DS2_CFSYNC               5
+#define STB0899_WIDTH_DS2_CFSYNC               1
+#define STB0899_DS2_TMGLOCK                    (0x01 << 4)
+#define STB0899_OFFST_DS2_TMGLOCK              4
+#define STB0899_WIDTH_DS2_TMGLOCK              1
+#define STB0899_DS2_DEMODWAIT                  (0x01 << 3)
+#define STB0899_OFFST_DS2_DEMODWAIT            3
+#define STB0899_WIDTH_DS2_DEMODWAIT            1
+#define STB0899_DS2_FECON                      (0x01 << 1)
+#define STB0899_OFFST_DS2_FECON                        1
+#define STB0899_WIDTH_DS2_FECON                        1
+
+/*     S1 FEC  */
+#define STB0899_VSTATUS                                0xf50d
+#define STB0899_VSTATUS_VITERBI_ON             (0x01 << 7)
+#define STB0899_OFFST_VSTATUS_VITERBI_ON       7
+#define STB0899_WIDTH_VSTATUS_VITERBI_ON       1
+#define STB0899_VSTATUS_END_LOOPVIT            (0x01 << 6)
+#define STB0899_OFFST_VSTATUS_END_LOOPVIT      6
+#define STB0899_WIDTH_VSTATUS_END_LOOPVIT      1
+#define STB0899_VSTATUS_PRFVIT                 (0x01 << 4)
+#define STB0899_OFFST_VSTATUS_PRFVIT           4
+#define STB0899_WIDTH_VSTATUS_PRFVIT           1
+#define STB0899_VSTATUS_LOCKEDVIT              (0x01 << 3)
+#define STB0899_OFFST_VSTATUS_LOCKEDVIT                3
+#define STB0899_WIDTH_VSTATUS_LOCKEDVIT                1
+
+#define STB0899_VERROR                         0xf50f
+
+#define STB0899_IQSWAP                         0xf523
+#define STB0899_SYM                            (0x01 << 3)
+#define STB0899_OFFST_SYM                      3
+#define STB0899_WIDTH_SYM                      1
+
+#define STB0899_FECAUTO1                       0xf530
+#define STB0899_DSSSRCH                                (0x01 << 3)
+#define STB0899_OFFST_DSSSRCH                  3
+#define STB0899_WIDTH_DSSSRCH                  1
+#define STB0899_SYMSRCH                                (0x01 << 2)
+#define STB0899_OFFST_SYMSRCH                  2
+#define STB0899_WIDTH_SYMSRCH                  1
+#define STB0899_QPSKSRCH                       (0x01 << 1)
+#define STB0899_OFFST_QPSKSRCH                 1
+#define STB0899_WIDTH_QPSKSRCH                 1
+#define STB0899_BPSKSRCH                       (0x01 << 0)
+#define STB0899_OFFST_BPSKSRCH                 0
+#define STB0899_WIDTH_BPSKSRCH                 1
+
+#define STB0899_FECM                           0xf533
+#define STB0899_FECM_NOT_DVB                   (0x01 << 7)
+#define STB0899_OFFST_FECM_NOT_DVB             7
+#define STB0899_WIDTH_FECM_NOT_DVB             1
+#define STB0899_FECM_RSVD1                     (0x07 << 4)
+#define STB0899_OFFST_FECM_RSVD1               4
+#define STB0899_WIDTH_FECM_RSVD1               3
+#define STB0899_FECM_VITERBI_ON                        (0x01 << 3)
+#define STB0899_OFFST_FECM_VITERBI_ON          3
+#define STB0899_WIDTH_FECM_VITERBI_ON          1
+#define STB0899_FECM_RSVD0                     (0x01 << 2)
+#define STB0899_OFFST_FECM_RSVD0               2
+#define STB0899_WIDTH_FECM_RSVD0               1
+#define STB0899_FECM_SYNCDIS                   (0x01 << 1)
+#define STB0899_OFFST_FECM_SYNCDIS             1
+#define STB0899_WIDTH_FECM_SYNCDIS             1
+#define STB0899_FECM_SYMI                      (0x01 << 0)
+#define STB0899_OFFST_FECM_SYMI                        0
+#define STB0899_WIDTH_FECM_SYMI                        1
+
+#define STB0899_VTH12                          0xf534
+#define STB0899_VTH23                          0xf535
+#define STB0899_VTH34                          0xf536
+#define STB0899_VTH56                          0xf537
+#define STB0899_VTH67                          0xf538
+#define STB0899_VTH78                          0xf539
+
+#define STB0899_PRVIT                          0xf53c
+#define STB0899_PR_7_8                         (0x01 << 5)
+#define STB0899_OFFST_PR_7_8                   5
+#define STB0899_WIDTH_PR_7_8                   1
+#define STB0899_PR_6_7                         (0x01 << 4)
+#define STB0899_OFFST_PR_6_7                   4
+#define STB0899_WIDTH_PR_6_7                   1
+#define STB0899_PR_5_6                         (0x01 << 3)
+#define STB0899_OFFST_PR_5_6                   3
+#define STB0899_WIDTH_PR_5_6                   1
+#define STB0899_PR_3_4                         (0x01 << 2)
+#define STB0899_OFFST_PR_3_4                   2
+#define STB0899_WIDTH_PR_3_4                   1
+#define STB0899_PR_2_3                         (0x01 << 1)
+#define STB0899_OFFST_PR_2_3                   1
+#define STB0899_WIDTH_PR_2_3                   1
+#define STB0899_PR_1_2                         (0x01 << 0)
+#define STB0899_OFFST_PR_1_2                   0
+#define STB0899_WIDTH_PR_1_2                   1
+
+#define STB0899_VITSYNC                                0xf53d
+#define STB0899_AM                             (0x01 << 7)
+#define STB0899_OFFST_AM                       7
+#define STB0899_WIDTH_AM                       1
+#define STB0899_FREEZE                         (0x01 << 6)
+#define STB0899_OFFST_FREEZE                   6
+#define STB0899_WIDTH_FREEZE                   1
+#define STB0899_SN_65536                       (0x03 << 4)
+#define STB0899_OFFST_SN_65536                 4
+#define STB0899_WIDTH_SN_65536                 2
+#define STB0899_SN_16384                       (0x01 << 5)
+#define STB0899_OFFST_SN_16384                 5
+#define STB0899_WIDTH_SN_16384                 1
+#define STB0899_SN_4096                                (0x01 << 4)
+#define STB0899_OFFST_SN_4096                  4
+#define STB0899_WIDTH_SN_4096                  1
+#define STB0899_SN_1024                                (0x00 << 4)
+#define STB0899_OFFST_SN_1024                  4
+#define STB0899_WIDTH_SN_1024                  0
+#define STB0899_TO_128                         (0x03 << 2)
+#define STB0899_OFFST_TO_128                   2
+#define STB0899_WIDTH_TO_128                   2
+#define STB0899_TO_64                          (0x01 << 3)
+#define STB0899_OFFST_TO_64                    3
+#define STB0899_WIDTH_TO_64                    1
+#define STB0899_TO_32                          (0x01 << 2)
+#define STB0899_OFFST_TO_32                    2
+#define STB0899_WIDTH_TO_32                    1
+#define STB0899_TO_16                          (0x00 << 2)
+#define STB0899_OFFST_TO_16                    2
+#define STB0899_WIDTH_TO_16                    0
+#define STB0899_HYST_128                       (0x03 << 1)
+#define STB0899_OFFST_HYST_128                 1
+#define STB0899_WIDTH_HYST_128                 2
+#define STB0899_HYST_64                                (0x01 << 1)
+#define STB0899_OFFST_HYST_64                  1
+#define STB0899_WIDTH_HYST_64                  1
+#define STB0899_HYST_32                                (0x01 << 0)
+#define STB0899_OFFST_HYST_32                  0
+#define STB0899_WIDTH_HYST_32                  1
+#define STB0899_HYST_16                                (0x00 << 0)
+#define STB0899_OFFST_HYST_16                  0
+#define STB0899_WIDTH_HYST_16                  0
+
+#define STB0899_RSULC                          0xf548
+#define STB0899_ULDIL_ON                       (0x01 << 7)
+#define STB0899_OFFST_ULDIL_ON                 7
+#define STB0899_WIDTH_ULDIL_ON                 1
+#define STB0899_ULAUTO_ON                      (0x01 << 6)
+#define STB0899_OFFST_ULAUTO_ON                        6
+#define STB0899_WIDTH_ULAUTO_ON                        1
+#define STB0899_ULRS_ON                                (0x01 << 5)
+#define STB0899_OFFST_ULRS_ON                  5
+#define STB0899_WIDTH_ULRS_ON                  1
+#define STB0899_ULDESCRAM_ON                   (0x01 << 4)
+#define STB0899_OFFST_ULDESCRAM_ON             4
+#define STB0899_WIDTH_ULDESCRAM_ON             1
+#define STB0899_UL_DISABLE                     (0x01 << 2)
+#define STB0899_OFFST_UL_DISABLE               2
+#define STB0899_WIDTH_UL_DISABLE               1
+#define STB0899_NOFTHRESHOLD                   (0x01 << 0)
+#define STB0899_OFFST_NOFTHRESHOLD             0
+#define STB0899_WIDTH_NOFTHRESHOLD             1
+
+#define STB0899_RSLLC                          0xf54a
+#define STB0899_DEMAPVIT                       0xf583
+#define STB0899_DEMAPVIT_RSVD                  (0x01 << 7)
+#define STB0899_OFFST_DEMAPVIT_RSVD            7
+#define STB0899_WIDTH_DEMAPVIT_RSVD            1
+#define STB0899_DEMAPVIT_KDIVIDER              (0x7f << 0)
+#define STB0899_OFFST_DEMAPVIT_KDIVIDER                0
+#define STB0899_WIDTH_DEMAPVIT_KDIVIDER                7
+
+#define STB0899_PLPARM                         0xf58c
+#define STB0899_VITMAPPING                     (0x07 << 5)
+#define STB0899_OFFST_VITMAPPING               5
+#define STB0899_WIDTH_VITMAPPING               3
+#define STB0899_VITMAPPING_BPSK                        (0x01 << 5)
+#define STB0899_OFFST_VITMAPPING_BPSK          5
+#define STB0899_WIDTH_VITMAPPING_BPSK          1
+#define STB0899_VITMAPPING_QPSK                        (0x00 << 5)
+#define STB0899_OFFST_VITMAPPING_QPSK          5
+#define STB0899_WIDTH_VITMAPPING_QPSK          0
+#define STB0899_VITCURPUN                      (0x1f << 0)
+#define STB0899_OFFST_VITCURPUN                        0
+#define STB0899_WIDTH_VITCURPUN                        5
+#define STB0899_VITCURPUN_1_2                  (0x0d << 0)
+#define STB0899_VITCURPUN_2_3                  (0x12 << 0)
+#define STB0899_VITCURPUN_3_4                  (0x15 << 0)
+#define STB0899_VITCURPUN_5_6                  (0x18 << 0)
+#define STB0899_VITCURPUN_6_7                  (0x19 << 0)
+#define STB0899_VITCURPUN_7_8                  (0x1a << 0)
+
+/*     S2 DEMOD        */
+#define STB0899_OFF0_DMD_STATUS                        0xf300
+#define STB0899_BASE_DMD_STATUS                        0x00000000
+#define STB0899_IF_AGC_LOCK                    (0x01 << 8)
+#define STB0899_OFFST_IF_AGC_LOCK              0
+#define STB0899_WIDTH_IF_AGC_LOCK              1
+
+#define STB0899_OFF0_CRL_FREQ                  0xf304
+#define STB0899_BASE_CRL_FREQ                  0x00000000
+#define STB0899_CARR_FREQ                      (0x3fffffff << 0)
+#define STB0899_OFFST_CARR_FREQ                        0
+#define STB0899_WIDTH_CARR_FREQ                        30
+
+#define STB0899_OFF0_BTR_FREQ                  0xf308
+#define STB0899_BASE_BTR_FREQ                  0x00000000
+#define STB0899_BTR_FREQ                       (0xfffffff << 0)
+#define STB0899_OFFST_BTR_FREQ                 0
+#define STB0899_WIDTH_BTR_FREQ                 28
+
+#define STB0899_OFF0_IF_AGC_GAIN               0xf30c
+#define STB0899_BASE_IF_AGC_GAIN               0x00000000
+#define STB0899_IF_AGC_GAIN                    (0x3fff < 0)
+#define STB0899_OFFST_IF_AGC_GAIN              0
+#define STB0899_WIDTH_IF_AGC_GAIN              14
+
+#define STB0899_OFF0_BB_AGC_GAIN               0xf310
+#define STB0899_BASE_BB_AGC_GAIN               0x00000000
+#define STB0899_BB_AGC_GAIN                    (0x3fff < 0)
+#define STB0899_OFFST_BB_AGC_GAIN              0
+#define STB0899_WIDTH_BB_AGC_GAIN              14
+
+#define STB0899_OFF0_DC_OFFSET                 0xf314
+#define STB0899_BASE_DC_OFFSET                 0x00000000
+#define STB0899_I                              (0xff < 8)
+#define STB0899_OFFST_I                                8
+#define STB0899_WIDTH_I                                8
+#define STB0899_Q                              (0xff < 0)
+#define STB0899_OFFST_Q                                8
+#define STB0899_WIDTH_Q                                8
+
+#define STB0899_OFF0_DMD_CNTRL                 0xf31c
+#define STB0899_BASE_DMD_CNTRL                 0x00000000
+#define STB0899_ADC0_PINS1IN                   (0x01 << 6)
+#define STB0899_OFFST_ADC0_PINS1IN              6
+#define STB0899_WIDTH_ADC0_PINS1IN              1
+#define STB0899_IN2COMP1_OFFBIN0               (0x01 << 3)
+#define STB0899_OFFST_IN2COMP1_OFFBIN0          3
+#define STB0899_WIDTH_IN2COMP1_OFFBIN0          1
+#define STB0899_DC_COMP                                (0x01 << 2)
+#define STB0899_OFFST_DC_COMP                  2
+#define STB0899_WIDTH_DC_COMP                  1
+#define STB0899_MODMODE                                (0x03 << 0)
+#define STB0899_OFFST_MODMODE                  0
+#define STB0899_WIDTH_MODMODE                  2
+
+#define STB0899_OFF0_IF_AGC_CNTRL              0xf320
+#define STB0899_BASE_IF_AGC_CNTRL              0x00000000
+#define STB0899_IF_GAIN_INIT                   (0x3fff << 13)
+#define STB0899_OFFST_IF_GAIN_INIT             13
+#define STB0899_WIDTH_IF_GAIN_INIT             14
+#define STB0899_IF_GAIN_SENSE                  (0x01 << 12)
+#define STB0899_OFFST_IF_GAIN_SENSE            12
+#define STB0899_WIDTH_IF_GAIN_SENSE            1
+#define STB0899_IF_LOOP_GAIN                   (0x0f << 8)
+#define STB0899_OFFST_IF_LOOP_GAIN             8
+#define STB0899_WIDTH_IF_LOOP_GAIN             4
+#define STB0899_IF_LD_GAIN_INIT                        (0x01 << 7)
+#define STB0899_OFFST_IF_LD_GAIN_INIT          7
+#define STB0899_WIDTH_IF_LD_GAIN_INIT          1
+#define STB0899_IF_AGC_REF                     (0x7f << 0)
+#define STB0899_OFFST_IF_AGC_REF               0
+#define STB0899_WIDTH_IF_AGC_REF               7
+
+#define STB0899_OFF0_BB_AGC_CNTRL              0xf324
+#define STB0899_BASE_BB_AGC_CNTRL              0x00000000
+#define STB0899_BB_GAIN_INIT                   (0x3fff << 12)
+#define STB0899_OFFST_BB_GAIN_INIT             12
+#define STB0899_WIDTH_BB_GAIN_INIT             14
+#define STB0899_BB_LOOP_GAIN                   (0x0f << 8)
+#define STB0899_OFFST_BB_LOOP_GAIN             8
+#define STB0899_WIDTH_BB_LOOP_GAIN             4
+#define STB0899_BB_LD_GAIN_INIT                        (0x01 << 7)
+#define STB0899_OFFST_BB_LD_GAIN_INIT          7
+#define STB0899_WIDTH_BB_LD_GAIN_INIT          1
+#define STB0899_BB_AGC_REF                     (0x7f << 0)
+#define STB0899_OFFST_BB_AGC_REF               0
+#define STB0899_WIDTH_BB_AGC_REF               7
+
+#define STB0899_OFF0_CRL_CNTRL                 0xf328
+#define STB0899_BASE_CRL_CNTRL                 0x00000000
+#define STB0899_CRL_LOCK_CLEAR                 (0x01 << 5)
+#define STB0899_OFFST_CRL_LOCK_CLEAR           5
+#define STB0899_WIDTH_CRL_LOCK_CLEAR           1
+#define STB0899_CRL_SWPR_CLEAR                 (0x01 << 4)
+#define STB0899_OFFST_CRL_SWPR_CLEAR           4
+#define STB0899_WIDTH_CRL_SWPR_CLEAR           1
+#define STB0899_CRL_SWP_ENA                    (0x01 << 3)
+#define STB0899_OFFST_CRL_SWP_ENA              3
+#define STB0899_WIDTH_CRL_SWP_ENA              1
+#define STB0899_CRL_DET_SEL                    (0x01 << 2)
+#define STB0899_OFFST_CRL_DET_SEL              2
+#define STB0899_WIDTH_CRL_DET_SEL              1
+#define STB0899_CRL_SENSE                      (0x01 << 1)
+#define STB0899_OFFST_CRL_SENSE                        1
+#define STB0899_WIDTH_CRL_SENSE                        1
+#define STB0899_CRL_PHSERR_CLEAR               (0x01 << 0)
+#define STB0899_OFFST_CRL_PHSERR_CLEAR         0
+#define STB0899_WIDTH_CRL_PHSERR_CLEAR         1
+
+#define STB0899_OFF0_CRL_PHS_INIT              0xf32c
+#define STB0899_BASE_CRL_PHS_INIT              0x00000000
+#define STB0899_CRL_PHS_INIT_31                        (0x1 << 30)
+#define STB0899_OFFST_CRL_PHS_INIT_31          30
+#define STB0899_WIDTH_CRL_PHS_INIT_31          1
+#define STB0899_CRL_LD_INIT_PHASE              (0x1 << 24)
+#define STB0899_OFFST_CRL_LD_INIT_PHASE                24
+#define STB0899_WIDTH_CRL_LD_INIT_PHASE                1
+#define STB0899_CRL_INIT_PHASE                 (0xffffff << 0)
+#define STB0899_OFFST_CRL_INIT_PHASE           0
+#define STB0899_WIDTH_CRL_INIT_PHASE           24
+
+#define STB0899_OFF0_CRL_FREQ_INIT             0xf330
+#define STB0899_BASE_CRL_FREQ_INIT             0x00000000
+#define STB0899_CRL_FREQ_INIT_31               (0x1 << 30)
+#define STB0899_OFFST_CRL_FREQ_INIT_31         30
+#define STB0899_WIDTH_CRL_FREQ_INIT_31         1
+#define STB0899_CRL_LD_FREQ_INIT               (0x1 << 24)
+#define STB0899_OFFST_CRL_LD_FREQ_INIT         24
+#define STB0899_WIDTH_CRL_LD_FREQ_INIT         1
+#define STB0899_CRL_FREQ_INIT                  (0xffffff << 0)
+#define STB0899_OFFST_CRL_FREQ_INIT            0
+#define STB0899_WIDTH_CRL_FREQ_INIT            24
+
+#define STB0899_OFF0_CRL_LOOP_GAIN             0xf334
+#define STB0899_BASE_CRL_LOOP_GAIN             0x00000000
+#define STB0899_KCRL2_RSHFT                    (0xf << 16)
+#define STB0899_OFFST_KCRL2_RSHFT              16
+#define STB0899_WIDTH_KCRL2_RSHFT              4
+#define STB0899_KCRL1                          (0xf << 12)
+#define STB0899_OFFST_KCRL1                    12
+#define STB0899_WIDTH_KCRL1                    4
+#define STB0899_KCRL1_RSHFT                    (0xf << 8)
+#define STB0899_OFFST_KCRL1_RSHFT              8
+#define STB0899_WIDTH_KCRL1_RSHFT              4
+#define STB0899_KCRL0                          (0xf << 4)
+#define STB0899_OFFST_KCRL0                    4
+#define STB0899_WIDTH_KCRL0                    4
+#define STB0899_KCRL0_RSHFT                    (0xf << 0)
+#define STB0899_OFFST_KCRL0_RSHFT              0
+#define STB0899_WIDTH_KCRL0_RSHFT              4
+
+#define STB0899_OFF0_CRL_NOM_FREQ              0xf338
+#define STB0899_BASE_CRL_NOM_FREQ              0x00000000
+#define STB0899_CRL_NOM_FREQ                   (0x3fffffff << 0)
+#define STB0899_OFFST_CRL_NOM_FREQ             0
+#define STB0899_WIDTH_CRL_NOM_FREQ             30
+
+#define STB0899_OFF0_CRL_SWP_RATE              0xf33c
+#define STB0899_BASE_CRL_SWP_RATE              0x00000000
+#define STB0899_CRL_SWP_RATE                   (0x3fffffff << 0)
+#define STB0899_OFFST_CRL_SWP_RATE             0
+#define STB0899_WIDTH_CRL_SWP_RATE             30
+
+#define STB0899_OFF0_CRL_MAX_SWP               0xf340
+#define STB0899_BASE_CRL_MAX_SWP               0x00000000
+#define STB0899_CRL_MAX_SWP                    (0x3fffffff << 0)
+#define STB0899_OFFST_CRL_MAX_SWP              0
+#define STB0899_WIDTH_CRL_MAX_SWP              30
+
+#define STB0899_OFF0_CRL_LK_CNTRL              0xf344
+#define STB0899_BASE_CRL_LK_CNTRL              0x00000000
+
+#define STB0899_OFF0_DECIM_CNTRL               0xf348
+#define STB0899_BASE_DECIM_CNTRL               0x00000000
+#define STB0899_BAND_LIMIT_B                   (0x01 << 5)
+#define STB0899_OFFST_BAND_LIMIT_B             5
+#define STB0899_WIDTH_BAND_LIMIT_B             1
+#define STB0899_WIN_SEL                                (0x03 << 3)
+#define STB0899_OFFST_WIN_SEL                  3
+#define STB0899_WIDTH_WIN_SEL                  2
+#define STB0899_DECIM_RATE                     (0x07 << 0)
+#define STB0899_OFFST_DECIM_RATE               0
+#define STB0899_WIDTH_DECIM_RATE               3
+
+#define STB0899_OFF0_BTR_CNTRL                 0xf34c
+#define STB0899_BASE_BTR_CNTRL                 0x00000000
+#define STB0899_BTR_FREQ_CORR                  (0x7ff << 4)
+#define STB0899_OFFST_BTR_FREQ_CORR            4
+#define STB0899_WIDTH_BTR_FREQ_CORR            11
+#define STB0899_BTR_CLR_LOCK                   (0x01 << 3)
+#define STB0899_OFFST_BTR_CLR_LOCK             3
+#define STB0899_WIDTH_BTR_CLR_LOCK             1
+#define STB0899_BTR_SENSE                      (0x01 << 2)
+#define STB0899_OFFST_BTR_SENSE                        2
+#define STB0899_WIDTH_BTR_SENSE                        1
+#define STB0899_BTR_ERR_ENA                    (0x01 << 1)
+#define STB0899_OFFST_BTR_ERR_ENA              1
+#define STB0899_WIDTH_BTR_ERR_ENA              1
+#define STB0899_INTRP_PHS_SENSE                        (0x01 << 0)
+#define STB0899_OFFST_INTRP_PHS_SENSE          0
+#define STB0899_WIDTH_INTRP_PHS_SENSE          1
+
+#define STB0899_OFF0_BTR_LOOP_GAIN             0xf350
+#define STB0899_BASE_BTR_LOOP_GAIN             0x00000000
+#define STB0899_KBTR2_RSHFT                    (0x0f << 16)
+#define STB0899_OFFST_KBTR2_RSHFT              16
+#define STB0899_WIDTH_KBTR2_RSHFT              4
+#define STB0899_KBTR1                          (0x0f << 12)
+#define STB0899_OFFST_KBTR1                    12
+#define STB0899_WIDTH_KBTR1                    4
+#define STB0899_KBTR1_RSHFT                    (0x0f << 8)
+#define STB0899_OFFST_KBTR1_RSHFT              8
+#define STB0899_WIDTH_KBTR1_RSHFT              4
+#define STB0899_KBTR0                          (0x0f << 4)
+#define STB0899_OFFST_KBTR0                    4
+#define STB0899_WIDTH_KBTR0                    4
+#define STB0899_KBTR0_RSHFT                    (0x0f << 0)
+#define STB0899_OFFST_KBTR0_RSHFT              0
+#define STB0899_WIDTH_KBTR0_RSHFT              4
+
+#define STB0899_OFF0_BTR_PHS_INIT              0xf354
+#define STB0899_BASE_BTR_PHS_INIT              0x00000000
+#define STB0899_BTR_LD_PHASE_INIT              (0x01 << 28)
+#define STB0899_OFFST_BTR_LD_PHASE_INIT                28
+#define STB0899_WIDTH_BTR_LD_PHASE_INIT                1
+#define STB0899_BTR_INIT_PHASE                 (0xfffffff << 0)
+#define STB0899_OFFST_BTR_INIT_PHASE           0
+#define STB0899_WIDTH_BTR_INIT_PHASE           28
+
+#define STB0899_OFF0_BTR_FREQ_INIT             0xf358
+#define STB0899_BASE_BTR_FREQ_INIT             0x00000000
+#define STB0899_BTR_LD_FREQ_INIT               (1 << 28)
+#define STB0899_OFFST_BTR_LD_FREQ_INIT         28
+#define STB0899_WIDTH_BTR_LD_FREQ_INIT         1
+#define STB0899_BTR_FREQ_INIT                  (0xfffffff << 0)
+#define STB0899_OFFST_BTR_FREQ_INIT            0
+#define STB0899_WIDTH_BTR_FREQ_INIT            28
+
+#define STB0899_OFF0_BTR_NOM_FREQ              0xf35c
+#define STB0899_BASE_BTR_NOM_FREQ              0x00000000
+#define STB0899_BTR_NOM_FREQ                   (0xfffffff << 0)
+#define STB0899_OFFST_BTR_NOM_FREQ             0
+#define STB0899_WIDTH_BTR_NOM_FREQ             28
+
+#define STB0899_OFF0_BTR_LK_CNTRL              0xf360
+#define STB0899_BASE_BTR_LK_CNTRL              0x00000000
+#define STB0899_BTR_MIN_ENERGY                 (0x0f << 24)
+#define STB0899_OFFST_BTR_MIN_ENERGY           24
+#define STB0899_WIDTH_BTR_MIN_ENERGY           4
+#define STB0899_BTR_LOCK_TH_LO                 (0xff << 16)
+#define STB0899_OFFST_BTR_LOCK_TH_LO           16
+#define STB0899_WIDTH_BTR_LOCK_TH_LO           8
+#define STB0899_BTR_LOCK_TH_HI                 (0xff << 8)
+#define STB0899_OFFST_BTR_LOCK_TH_HI           8
+#define STB0899_WIDTH_BTR_LOCK_TH_HI           8
+#define STB0899_BTR_LOCK_GAIN                  (0x03 << 6)
+#define STB0899_OFFST_BTR_LOCK_GAIN            6
+#define STB0899_WIDTH_BTR_LOCK_GAIN            2
+#define STB0899_BTR_LOCK_LEAK                  (0x3f << 0)
+#define STB0899_OFFST_BTR_LOCK_LEAK            0
+#define STB0899_WIDTH_BTR_LOCK_LEAK            6
+
+#define STB0899_OFF0_DECN_CNTRL                        0xf364
+#define STB0899_BASE_DECN_CNTRL                        0x00000000
+
+#define STB0899_OFF0_TP_CNTRL                  0xf368
+#define STB0899_BASE_TP_CNTRL                  0x00000000
+
+#define STB0899_OFF0_TP_BUF_STATUS             0xf36c
+#define STB0899_BASE_TP_BUF_STATUS             0x00000000
+#define STB0899_TP_BUFFER_FULL                  (1 << 0)
+
+#define STB0899_OFF0_DC_ESTIM                  0xf37c
+#define STB0899_BASE_DC_ESTIM                  0x0000
+#define STB0899_I_DC_ESTIMATE                  (0xff << 8)
+#define STB0899_OFFST_I_DC_ESTIMATE            8
+#define STB0899_WIDTH_I_DC_ESTIMATE            8
+#define STB0899_Q_DC_ESTIMATE                  (0xff << 0)
+#define STB0899_OFFST_Q_DC_ESTIMATE            0
+#define STB0899_WIDTH_Q_DC_ESTIMATE            8
+
+#define STB0899_OFF0_FLL_CNTRL                 0xf310
+#define STB0899_BASE_FLL_CNTRL                 0x00000020
+#define STB0899_CRL_FLL_ACC                    (0x01 << 4)
+#define STB0899_OFFST_CRL_FLL_ACC              4
+#define STB0899_WIDTH_CRL_FLL_ACC              1
+#define STB0899_FLL_AVG_PERIOD                 (0x0f << 0)
+#define STB0899_OFFST_FLL_AVG_PERIOD           0
+#define STB0899_WIDTH_FLL_AVG_PERIOD           4
+
+#define STB0899_OFF0_FLL_FREQ_WD               0xf314
+#define STB0899_BASE_FLL_FREQ_WD               0x00000020
+#define STB0899_FLL_FREQ_WD                    (0xffffffff << 0)
+#define STB0899_OFFST_FLL_FREQ_WD              0
+#define STB0899_WIDTH_FLL_FREQ_WD              32
+
+#define STB0899_OFF0_ANTI_ALIAS_SEL            0xf358
+#define STB0899_BASE_ANTI_ALIAS_SEL            0x00000020
+#define STB0899_ANTI_ALIAS_SELB                        (0x03 << 0)
+#define STB0899_OFFST_ANTI_ALIAS_SELB          0
+#define STB0899_WIDTH_ANTI_ALIAS_SELB          2
+
+#define STB0899_OFF0_RRC_ALPHA                 0xf35c
+#define STB0899_BASE_RRC_ALPHA                 0x00000020
+#define STB0899_RRC_ALPHA                      (0x03 << 0)
+#define STB0899_OFFST_RRC_ALPHA                        0
+#define STB0899_WIDTH_RRC_ALPHA                        2
+
+#define STB0899_OFF0_DC_ADAPT_LSHFT            0xf360
+#define STB0899_BASE_DC_ADAPT_LSHFT            0x00000020
+#define STB0899_DC_ADAPT_LSHFT                 (0x077 << 0)
+#define STB0899_OFFST_DC_ADAPT_LSHFT           0
+#define STB0899_WIDTH_DC_ADAPT_LSHFT           3
+
+#define STB0899_OFF0_IMB_OFFSET                        0xf364
+#define STB0899_BASE_IMB_OFFSET                        0x00000020
+#define STB0899_PHS_IMB_COMP                   (0xff << 8)
+#define STB0899_OFFST_PHS_IMB_COMP             8
+#define STB0899_WIDTH_PHS_IMB_COMP             8
+#define STB0899_AMPL_IMB_COMP                  (0xff << 0)
+#define STB0899_OFFST_AMPL_IMB_COMP            0
+#define STB0899_WIDTH_AMPL_IMB_COMP            8
+
+#define STB0899_OFF0_IMB_ESTIMATE              0xf368
+#define STB0899_BASE_IMB_ESTIMATE              0x00000020
+#define STB0899_PHS_IMB_ESTIMATE               (0xff << 8)
+#define STB0899_OFFST_PHS_IMB_ESTIMATE         8
+#define STB0899_WIDTH_PHS_IMB_ESTIMATE         8
+#define STB0899_AMPL_IMB_ESTIMATE              (0xff << 0)
+#define STB0899_OFFST_AMPL_IMB_ESTIMATE                0
+#define STB0899_WIDTH_AMPL_IMB_ESTIMATE                8
+
+#define STB0899_OFF0_IMB_CNTRL                 0xf36c
+#define STB0899_BASE_IMB_CNTRL                 0x00000020
+#define STB0899_PHS_ADAPT_LSHFT                        (0x07 << 4)
+#define STB0899_OFFST_PHS_ADAPT_LSHFT          4
+#define STB0899_WIDTH_PHS_ADAPT_LSHFT          3
+#define STB0899_AMPL_ADAPT_LSHFT               (0x07 << 1)
+#define STB0899_OFFST_AMPL_ADAPT_LSHFT         1
+#define STB0899_WIDTH_AMPL_ADAPT_LSHFT         3
+#define STB0899_IMB_COMP                       (0x01 << 0)
+#define STB0899_OFFST_IMB_COMP                 0
+#define STB0899_WIDTH_IMB_COMP                 1
+
+#define STB0899_OFF0_IF_AGC_CNTRL2             0xf374
+#define STB0899_BASE_IF_AGC_CNTRL2             0x00000020
+#define STB0899_IF_AGC_LOCK_TH                 (0xff << 11)
+#define STB0899_OFFST_IF_AGC_LOCK_TH           11
+#define STB0899_WIDTH_IF_AGC_LOCK_TH           8
+#define STB0899_IF_AGC_SD_DIV                  (0xff << 3)
+#define STB0899_OFFST_IF_AGC_SD_DIV            3
+#define STB0899_WIDTH_IF_AGC_SD_DIV            8
+#define STB0899_IF_AGC_DUMP_PER                        (0x07 << 0)
+#define STB0899_OFFST_IF_AGC_DUMP_PER          0
+#define STB0899_WIDTH_IF_AGC_DUMP_PER          3
+
+#define STB0899_OFF0_DMD_CNTRL2                        0xf378
+#define STB0899_BASE_DMD_CNTRL2                        0x00000020
+#define STB0899_SPECTRUM_INVERT                        (0x01 << 2)
+#define STB0899_OFFST_SPECTRUM_INVERT          2
+#define STB0899_WIDTH_SPECTRUM_INVERT          1
+#define STB0899_AGC_MODE                       (0x01 << 1)
+#define STB0899_OFFST_AGC_MODE                 1
+#define STB0899_WIDTH_AGC_MODE                 1
+#define STB0899_CRL_FREQ_ADJ                   (0x01 << 0)
+#define STB0899_OFFST_CRL_FREQ_ADJ             0
+#define STB0899_WIDTH_CRL_FREQ_ADJ             1
+
+#define STB0899_OFF0_TP_BUFFER                 0xf300
+#define STB0899_BASE_TP_BUFFER                 0x00000040
+#define STB0899_TP_BUFFER_IN                   (0xffff << 0)
+#define STB0899_OFFST_TP_BUFFER_IN             0
+#define STB0899_WIDTH_TP_BUFFER_IN             16
+
+#define STB0899_OFF0_TP_BUFFER1                        0xf304
+#define STB0899_BASE_TP_BUFFER1                        0x00000040
+#define STB0899_OFF0_TP_BUFFER2                        0xf308
+#define STB0899_BASE_TP_BUFFER2                        0x00000040
+#define STB0899_OFF0_TP_BUFFER3                        0xf30c
+#define STB0899_BASE_TP_BUFFER3                        0x00000040
+#define STB0899_OFF0_TP_BUFFER4                        0xf310
+#define STB0899_BASE_TP_BUFFER4                        0x00000040
+#define STB0899_OFF0_TP_BUFFER5                        0xf314
+#define STB0899_BASE_TP_BUFFER5                        0x00000040
+#define STB0899_OFF0_TP_BUFFER6                        0xf318
+#define STB0899_BASE_TP_BUFFER6                        0x00000040
+#define STB0899_OFF0_TP_BUFFER7                        0xf31c
+#define STB0899_BASE_TP_BUFFER7                        0x00000040
+#define STB0899_OFF0_TP_BUFFER8                        0xf320
+#define STB0899_BASE_TP_BUFFER8                        0x00000040
+#define STB0899_OFF0_TP_BUFFER9                        0xf324
+#define STB0899_BASE_TP_BUFFER9                        0x00000040
+#define STB0899_OFF0_TP_BUFFER10               0xf328
+#define STB0899_BASE_TP_BUFFER10               0x00000040
+#define STB0899_OFF0_TP_BUFFER11               0xf32c
+#define STB0899_BASE_TP_BUFFER11               0x00000040
+#define STB0899_OFF0_TP_BUFFER12               0xf330
+#define STB0899_BASE_TP_BUFFER12               0x00000040
+#define STB0899_OFF0_TP_BUFFER13               0xf334
+#define STB0899_BASE_TP_BUFFER13               0x00000040
+#define STB0899_OFF0_TP_BUFFER14               0xf338
+#define STB0899_BASE_TP_BUFFER14               0x00000040
+#define STB0899_OFF0_TP_BUFFER15               0xf33c
+#define STB0899_BASE_TP_BUFFER15               0x00000040
+#define STB0899_OFF0_TP_BUFFER16               0xf340
+#define STB0899_BASE_TP_BUFFER16               0x00000040
+#define STB0899_OFF0_TP_BUFFER17               0xf344
+#define STB0899_BASE_TP_BUFFER17               0x00000040
+#define STB0899_OFF0_TP_BUFFER18               0xf348
+#define STB0899_BASE_TP_BUFFER18               0x00000040
+#define STB0899_OFF0_TP_BUFFER19               0xf34c
+#define STB0899_BASE_TP_BUFFER19               0x00000040
+#define STB0899_OFF0_TP_BUFFER20               0xf350
+#define STB0899_BASE_TP_BUFFER20               0x00000040
+#define STB0899_OFF0_TP_BUFFER21               0xf354
+#define STB0899_BASE_TP_BUFFER21               0x00000040
+#define STB0899_OFF0_TP_BUFFER22               0xf358
+#define STB0899_BASE_TP_BUFFER22               0x00000040
+#define STB0899_OFF0_TP_BUFFER23               0xf35c
+#define STB0899_BASE_TP_BUFFER23               0x00000040
+#define STB0899_OFF0_TP_BUFFER24               0xf360
+#define STB0899_BASE_TP_BUFFER24               0x00000040
+#define STB0899_OFF0_TP_BUFFER25               0xf364
+#define STB0899_BASE_TP_BUFFER25               0x00000040
+#define STB0899_OFF0_TP_BUFFER26               0xf368
+#define STB0899_BASE_TP_BUFFER26               0x00000040
+#define STB0899_OFF0_TP_BUFFER27               0xf36c
+#define STB0899_BASE_TP_BUFFER27               0x00000040
+#define STB0899_OFF0_TP_BUFFER28               0xf370
+#define STB0899_BASE_TP_BUFFER28               0x00000040
+#define STB0899_OFF0_TP_BUFFER29               0xf374
+#define STB0899_BASE_TP_BUFFER29               0x00000040
+#define STB0899_OFF0_TP_BUFFER30               0xf378
+#define STB0899_BASE_TP_BUFFER30               0x00000040
+#define STB0899_OFF0_TP_BUFFER31               0xf37c
+#define STB0899_BASE_TP_BUFFER31               0x00000040
+#define STB0899_OFF0_TP_BUFFER32               0xf300
+#define STB0899_BASE_TP_BUFFER32               0x00000060
+#define STB0899_OFF0_TP_BUFFER33               0xf304
+#define STB0899_BASE_TP_BUFFER33               0x00000060
+#define STB0899_OFF0_TP_BUFFER34               0xf308
+#define STB0899_BASE_TP_BUFFER34               0x00000060
+#define STB0899_OFF0_TP_BUFFER35               0xf30c
+#define STB0899_BASE_TP_BUFFER35               0x00000060
+#define STB0899_OFF0_TP_BUFFER36               0xf310
+#define STB0899_BASE_TP_BUFFER36               0x00000060
+#define STB0899_OFF0_TP_BUFFER37               0xf314
+#define STB0899_BASE_TP_BUFFER37               0x00000060
+#define STB0899_OFF0_TP_BUFFER38               0xf318
+#define STB0899_BASE_TP_BUFFER38               0x00000060
+#define STB0899_OFF0_TP_BUFFER39               0xf31c
+#define STB0899_BASE_TP_BUFFER39               0x00000060
+#define STB0899_OFF0_TP_BUFFER40               0xf320
+#define STB0899_BASE_TP_BUFFER40               0x00000060
+#define STB0899_OFF0_TP_BUFFER41               0xf324
+#define STB0899_BASE_TP_BUFFER41               0x00000060
+#define STB0899_OFF0_TP_BUFFER42               0xf328
+#define STB0899_BASE_TP_BUFFER42               0x00000060
+#define STB0899_OFF0_TP_BUFFER43               0xf32c
+#define STB0899_BASE_TP_BUFFER43               0x00000060
+#define STB0899_OFF0_TP_BUFFER44               0xf330
+#define STB0899_BASE_TP_BUFFER44               0x00000060
+#define STB0899_OFF0_TP_BUFFER45               0xf334
+#define STB0899_BASE_TP_BUFFER45               0x00000060
+#define STB0899_OFF0_TP_BUFFER46               0xf338
+#define STB0899_BASE_TP_BUFFER46               0x00000060
+#define STB0899_OFF0_TP_BUFFER47               0xf33c
+#define STB0899_BASE_TP_BUFFER47               0x00000060
+#define STB0899_OFF0_TP_BUFFER48               0xf340
+#define STB0899_BASE_TP_BUFFER48               0x00000060
+#define STB0899_OFF0_TP_BUFFER49               0xf344
+#define STB0899_BASE_TP_BUFFER49               0x00000060
+#define STB0899_OFF0_TP_BUFFER50               0xf348
+#define STB0899_BASE_TP_BUFFER50               0x00000060
+#define STB0899_OFF0_TP_BUFFER51               0xf34c
+#define STB0899_BASE_TP_BUFFER51               0x00000060
+#define STB0899_OFF0_TP_BUFFER52               0xf350
+#define STB0899_BASE_TP_BUFFER52               0x00000060
+#define STB0899_OFF0_TP_BUFFER53               0xf354
+#define STB0899_BASE_TP_BUFFER53               0x00000060
+#define STB0899_OFF0_TP_BUFFER54               0xf358
+#define STB0899_BASE_TP_BUFFER54               0x00000060
+#define STB0899_OFF0_TP_BUFFER55               0xf35c
+#define STB0899_BASE_TP_BUFFER55               0x00000060
+#define STB0899_OFF0_TP_BUFFER56               0xf360
+#define STB0899_BASE_TP_BUFFER56               0x00000060
+#define STB0899_OFF0_TP_BUFFER57               0xf364
+#define STB0899_BASE_TP_BUFFER57               0x00000060
+#define STB0899_OFF0_TP_BUFFER58               0xf368
+#define STB0899_BASE_TP_BUFFER58               0x00000060
+#define STB0899_OFF0_TP_BUFFER59               0xf36c
+#define STB0899_BASE_TP_BUFFER59               0x00000060
+#define STB0899_OFF0_TP_BUFFER60               0xf370
+#define STB0899_BASE_TP_BUFFER60               0x00000060
+#define STB0899_OFF0_TP_BUFFER61               0xf374
+#define STB0899_BASE_TP_BUFFER61               0x00000060
+#define STB0899_OFF0_TP_BUFFER62               0xf378
+#define STB0899_BASE_TP_BUFFER62               0x00000060
+#define STB0899_OFF0_TP_BUFFER63               0xf37c
+#define STB0899_BASE_TP_BUFFER63               0x00000060
+
+#define STB0899_OFF0_RESET_CNTRL               0xf300
+#define STB0899_BASE_RESET_CNTRL               0x00000400
+#define STB0899_DVBS2_RESET                    (0x01 << 0)
+#define STB0899_OFFST_DVBS2_RESET              0
+#define STB0899_WIDTH_DVBS2_RESET              1
+
+#define STB0899_OFF0_ACM_ENABLE                        0xf304
+#define STB0899_BASE_ACM_ENABLE                        0x00000400
+#define STB0899_ACM_ENABLE                     1
+
+#define STB0899_OFF0_DESCR_CNTRL               0xf30c
+#define STB0899_BASE_DESCR_CNTRL               0x00000400
+#define STB0899_OFFST_DESCR_CNTRL               0
+#define STB0899_WIDTH_DESCR_CNTRL               16
+
+#define STB0899_OFF0_UWP_CNTRL1                        0xf320
+#define STB0899_BASE_UWP_CNTRL1                        0x00000400
+#define STB0899_UWP_TH_SOF                     (0x7fff << 11)
+#define STB0899_OFFST_UWP_TH_SOF               11
+#define STB0899_WIDTH_UWP_TH_SOF               15
+#define STB0899_UWP_ESN0_QUANT                 (0xff << 3)
+#define STB0899_OFFST_UWP_ESN0_QUANT           3
+#define STB0899_WIDTH_UWP_ESN0_QUANT           8
+#define STB0899_UWP_ESN0_AVE                   (0x03 << 1)
+#define STB0899_OFFST_UWP_ESN0_AVE             1
+#define STB0899_WIDTH_UWP_ESN0_AVE             2
+#define STB0899_UWP_START                      (0x01 << 0)
+#define STB0899_OFFST_UWP_START                        0
+#define STB0899_WIDTH_UWP_START                        1
+
+#define STB0899_OFF0_UWP_CNTRL2                        0xf324
+#define STB0899_BASE_UWP_CNTRL2                        0x00000400
+#define STB0899_UWP_MISS_TH                    (0xff << 16)
+#define STB0899_OFFST_UWP_MISS_TH              16
+#define STB0899_WIDTH_UWP_MISS_TH              8
+#define STB0899_FE_FINE_TRK                    (0xff << 8)
+#define STB0899_OFFST_FE_FINE_TRK              8
+#define STB0899_WIDTH_FE_FINE_TRK              8
+#define STB0899_FE_COARSE_TRK                  (0xff << 0)
+#define STB0899_OFFST_FE_COARSE_TRK            0
+#define STB0899_WIDTH_FE_COARSE_TRK            8
+
+#define STB0899_OFF0_UWP_STAT1                 0xf328
+#define STB0899_BASE_UWP_STAT1                 0x00000400
+#define STB0899_UWP_STATE                      (0x03ff << 15)
+#define STB0899_OFFST_UWP_STATE                        15
+#define STB0899_WIDTH_UWP_STATE                        10
+#define STB0899_UW_MAX_PEAK                    (0x7fff << 0)
+#define STB0899_OFFST_UW_MAX_PEAK              0
+#define STB0899_WIDTH_UW_MAX_PEAK              15
+
+#define STB0899_OFF0_UWP_STAT2                 0xf32c
+#define STB0899_BASE_UWP_STAT2                 0x00000400
+#define STB0899_ESNO_EST                       (0x07ffff << 7)
+#define STB0899_OFFST_ESN0_EST                 7
+#define STB0899_WIDTH_ESN0_EST                 19
+#define STB0899_UWP_DECODE_MOD                 (0x7f << 0)
+#define STB0899_OFFST_UWP_DECODE_MOD           0
+#define STB0899_WIDTH_UWP_DECODE_MOD           7
+
+#define STB0899_OFF0_DMD_CORE_ID               0xf334
+#define STB0899_BASE_DMD_CORE_ID               0x00000400
+#define STB0899_CORE_ID                                (0xffffffff << 0)
+#define STB0899_OFFST_CORE_ID                  0
+#define STB0899_WIDTH_CORE_ID                  32
+
+#define STB0899_OFF0_DMD_VERSION_ID            0xf33c
+#define STB0899_BASE_DMD_VERSION_ID            0x00000400
+#define STB0899_VERSION_ID                     (0xff << 0)
+#define STB0899_OFFST_VERSION_ID               0
+#define STB0899_WIDTH_VERSION_ID               8
+
+#define STB0899_OFF0_DMD_STAT2                 0xf340
+#define STB0899_BASE_DMD_STAT2                 0x00000400
+#define STB0899_CSM_LOCK                       (0x01 << 1)
+#define STB0899_OFFST_CSM_LOCK                 1
+#define STB0899_WIDTH_CSM_LOCK                 1
+#define STB0899_UWP_LOCK                       (0x01 << 0)
+#define STB0899_OFFST_UWP_LOCK                 0
+#define STB0899_WIDTH_UWP_LOCK                 1
+
+#define STB0899_OFF0_FREQ_ADJ_SCALE            0xf344
+#define STB0899_BASE_FREQ_ADJ_SCALE            0x00000400
+#define STB0899_FREQ_ADJ_SCALE                 (0x0fff << 0)
+#define STB0899_OFFST_FREQ_ADJ_SCALE           0
+#define STB0899_WIDTH_FREQ_ADJ_SCALE           12
+
+#define STB0899_OFF0_UWP_CNTRL3                        0xf34c
+#define STB0899_BASE_UWP_CNTRL3                        0x00000400
+#define STB0899_UWP_TH_TRACK                   (0x7fff << 15)
+#define STB0899_OFFST_UWP_TH_TRACK             15
+#define STB0899_WIDTH_UWP_TH_TRACK             15
+#define STB0899_UWP_TH_ACQ                     (0x7fff << 0)
+#define STB0899_OFFST_UWP_TH_ACQ               0
+#define STB0899_WIDTH_UWP_TH_ACQ               15
+
+#define STB0899_OFF0_SYM_CLK_SEL               0xf350
+#define STB0899_BASE_SYM_CLK_SEL               0x00000400
+#define STB0899_SYM_CLK_SEL                    (0x03 << 0)
+#define STB0899_OFFST_SYM_CLK_SEL              0
+#define STB0899_WIDTH_SYM_CLK_SEL              2
+
+#define STB0899_OFF0_SOF_SRCH_TO               0xf354
+#define STB0899_BASE_SOF_SRCH_TO               0x00000400
+#define STB0899_SOF_SEARCH_TIMEOUT             (0x3fffff << 0)
+#define STB0899_OFFST_SOF_SEARCH_TIMEOUT       0
+#define STB0899_WIDTH_SOF_SEARCH_TIMEOUT       22
+
+#define STB0899_OFF0_ACQ_CNTRL1                        0xf358
+#define STB0899_BASE_ACQ_CNTRL1                        0x00000400
+#define STB0899_FE_FINE_ACQ                    (0xff << 8)
+#define STB0899_OFFST_FE_FINE_ACQ              8
+#define STB0899_WIDTH_FE_FINE_ACQ              8
+#define STB0899_FE_COARSE_ACQ                  (0xff << 0)
+#define STB0899_OFFST_FE_COARSE_ACQ            0
+#define STB0899_WIDTH_FE_COARSE_ACQ            8
+
+#define STB0899_OFF0_ACQ_CNTRL2                        0xf35c
+#define STB0899_BASE_ACQ_CNTRL2                        0x00000400
+#define STB0899_ZIGZAG                         (0x01 << 25)
+#define STB0899_OFFST_ZIGZAG                   25
+#define STB0899_WIDTH_ZIGZAG                   1
+#define STB0899_NUM_STEPS                      (0xff << 17)
+#define STB0899_OFFST_NUM_STEPS                        17
+#define STB0899_WIDTH_NUM_STEPS                        8
+#define STB0899_FREQ_STEPSIZE                  (0x1ffff << 0)
+#define STB0899_OFFST_FREQ_STEPSIZE            0
+#define STB0899_WIDTH_FREQ_STEPSIZE            17
+
+#define STB0899_OFF0_ACQ_CNTRL3                        0xf360
+#define STB0899_BASE_ACQ_CNTRL3                        0x00000400
+#define STB0899_THRESHOLD_SCL                  (0x3f << 23)
+#define STB0899_OFFST_THRESHOLD_SCL            23
+#define STB0899_WIDTH_THRESHOLD_SCL            6
+#define STB0899_UWP_TH_SRCH                    (0x7fff << 8)
+#define STB0899_OFFST_UWP_TH_SRCH              8
+#define STB0899_WIDTH_UWP_TH_SRCH              15
+#define STB0899_AUTO_REACQUIRE                 (0x01 << 7)
+#define STB0899_OFFST_AUTO_REACQUIRE           7
+#define STB0899_WIDTH_AUTO_REACQUIRE           1
+#define STB0899_TRACK_LOCK_SEL                 (0x01 << 6)
+#define STB0899_OFFST_TRACK_LOCK_SEL           6
+#define STB0899_WIDTH_TRACK_LOCK_SEL           1
+#define STB0899_ACQ_SEARCH_MODE                        (0x03 << 4)
+#define STB0899_OFFST_ACQ_SEARCH_MODE          4
+#define STB0899_WIDTH_ACQ_SEARCH_MODE          2
+#define STB0899_CONFIRM_FRAMES                 (0x0f << 0)
+#define STB0899_OFFST_CONFIRM_FRAMES           0
+#define STB0899_WIDTH_CONFIRM_FRAMES           4
+
+#define STB0899_OFF0_FE_SETTLE                 0xf364
+#define STB0899_BASE_FE_SETTLE                 0x00000400
+#define STB0899_SETTLING_TIME                  (0x3fffff << 0)
+#define STB0899_OFFST_SETTLING_TIME            0
+#define STB0899_WIDTH_SETTLING_TIME            22
+
+#define STB0899_OFF0_AC_DWELL                  0xf368
+#define STB0899_BASE_AC_DWELL                  0x00000400
+#define STB0899_DWELL_TIME                     (0x3fffff << 0)
+#define STB0899_OFFST_DWELL_TIME               0
+#define STB0899_WIDTH_DWELL_TIME               22
+
+#define STB0899_OFF0_ACQUIRE_TRIG              0xf36c
+#define STB0899_BASE_ACQUIRE_TRIG              0x00000400
+#define STB0899_ACQUIRE                                (0x01 << 0)
+#define STB0899_OFFST_ACQUIRE                  0
+#define STB0899_WIDTH_ACQUIRE                  1
+
+#define STB0899_OFF0_LOCK_LOST                 0xf370
+#define STB0899_BASE_LOCK_LOST                 0x00000400
+#define STB0899_LOCK_LOST                      (0x01 << 0)
+#define STB0899_OFFST_LOCK_LOST                        0
+#define STB0899_WIDTH_LOCK_LOST                        1
+
+#define STB0899_OFF0_ACQ_STAT1                 0xf374
+#define STB0899_BASE_ACQ_STAT1                 0x00000400
+#define STB0899_STEP_FREQ                      (0x1fffff << 11)
+#define STB0899_OFFST_STEP_FREQ                        11
+#define STB0899_WIDTH_STEP_FREQ                        21
+#define STB0899_ACQ_STATE                      (0x07 << 8)
+#define STB0899_OFFST_ACQ_STATE                        8
+#define STB0899_WIDTH_ACQ_STATE                        3
+#define STB0899_UW_DETECT_COUNT                        (0xff << 0)
+#define STB0899_OFFST_UW_DETECT_COUNT          0
+#define STB0899_WIDTH_UW_DETECT_COUNT          8
+
+#define STB0899_OFF0_ACQ_TIMEOUT               0xf378
+#define STB0899_BASE_ACQ_TIMEOUT               0x00000400
+#define STB0899_ACQ_TIMEOUT                    (0x3fffff << 0)
+#define STB0899_OFFST_ACQ_TIMEOUT              0
+#define STB0899_WIDTH_ACQ_TIMEOUT              22
+
+#define STB0899_OFF0_ACQ_TIME                  0xf37c
+#define STB0899_BASE_ACQ_TIME                  0x00000400
+#define STB0899_ACQ_TIME_SYM                   (0xffffff << 0)
+#define STB0899_OFFST_ACQ_TIME_SYM             0
+#define STB0899_WIDTH_ACQ_TIME_SYM             24
+
+#define STB0899_OFF0_FINAL_AGC_CNTRL           0xf308
+#define STB0899_BASE_FINAL_AGC_CNTRL           0x00000440
+#define STB0899_FINAL_GAIN_INIT                        (0x3fff << 12)
+#define STB0899_OFFST_FINAL_GAIN_INIT          12
+#define STB0899_WIDTH_FINAL_GAIN_INIT          14
+#define STB0899_FINAL_LOOP_GAIN                        (0x0f << 8)
+#define STB0899_OFFST_FINAL_LOOP_GAIN          8
+#define STB0899_WIDTH_FINAL_LOOP_GAIN          4
+#define STB0899_FINAL_LD_GAIN_INIT             (0x01 << 7)
+#define STB0899_OFFST_FINAL_LD_GAIN_INIT       7
+#define STB0899_WIDTH_FINAL_LD_GAIN_INIT       1
+#define STB0899_FINAL_AGC_REF                  (0x7f << 0)
+#define STB0899_OFFST_FINAL_AGC_REF            0
+#define STB0899_WIDTH_FINAL_AGC_REF            7
+
+#define STB0899_OFF0_FINAL_AGC_GAIN            0xf30c
+#define STB0899_BASE_FINAL_AGC_GAIN            0x00000440
+#define STB0899_FINAL_AGC_GAIN                 (0x3fff << 0)
+#define STB0899_OFFST_FINAL_AGC_GAIN           0
+#define STB0899_WIDTH_FINAL_AGC_GAIN           14
+
+#define STB0899_OFF0_EQUALIZER_INIT            0xf310
+#define STB0899_BASE_EQUALIZER_INIT            0x00000440
+#define STB0899_EQ_SRST                                (0x01 << 1)
+#define STB0899_OFFST_EQ_SRST                  1
+#define STB0899_WIDTH_EQ_SRST                  1
+#define STB0899_EQ_INIT                                (0x01 << 0)
+#define STB0899_OFFST_EQ_INIT                  0
+#define STB0899_WIDTH_EQ_INIT                  1
+
+#define STB0899_OFF0_EQ_CNTRL                  0xf314
+#define STB0899_BASE_EQ_CNTRL                  0x00000440
+#define STB0899_EQ_ADAPT_MODE                  (0x01 << 18)
+#define STB0899_OFFST_EQ_ADAPT_MODE            18
+#define STB0899_WIDTH_EQ_ADAPT_MODE            1
+#define STB0899_EQ_DELAY                       (0x0f << 14)
+#define STB0899_OFFST_EQ_DELAY                 14
+#define STB0899_WIDTH_EQ_DELAY                 4
+#define STB0899_EQ_QUANT_LEVEL                 (0xff << 6)
+#define STB0899_OFFST_EQ_QUANT_LEVEL           6
+#define STB0899_WIDTH_EQ_QUANT_LEVEL           8
+#define STB0899_EQ_DISABLE_UPDATE              (0x01 << 5)
+#define STB0899_OFFST_EQ_DISABLE_UPDATE                5
+#define STB0899_WIDTH_EQ_DISABLE_UPDATE                1
+#define STB0899_EQ_BYPASS                      (0x01 << 4)
+#define STB0899_OFFST_EQ_BYPASS                        4
+#define STB0899_WIDTH_EQ_BYPASS                        1
+#define STB0899_EQ_SHIFT                       (0x0f << 0)
+#define STB0899_OFFST_EQ_SHIFT                 0
+#define STB0899_WIDTH_EQ_SHIFT                 4
+
+#define STB0899_OFF0_EQ_I_INIT_COEFF_0         0xf320
+#define STB0899_OFF1_EQ_I_INIT_COEFF_1         0xf324
+#define STB0899_OFF2_EQ_I_INIT_COEFF_2         0xf328
+#define STB0899_OFF3_EQ_I_INIT_COEFF_3         0xf32c
+#define STB0899_OFF4_EQ_I_INIT_COEFF_4         0xf330
+#define STB0899_OFF5_EQ_I_INIT_COEFF_5         0xf334
+#define STB0899_OFF6_EQ_I_INIT_COEFF_6         0xf338
+#define STB0899_OFF7_EQ_I_INIT_COEFF_7         0xf33c
+#define STB0899_OFF8_EQ_I_INIT_COEFF_8         0xf340
+#define STB0899_OFF9_EQ_I_INIT_COEFF_9         0xf344
+#define STB0899_OFFa_EQ_I_INIT_COEFF_10                0xf348
+#define STB0899_BASE_EQ_I_INIT_COEFF_N         0x00000440
+#define STB0899_EQ_I_INIT_COEFF_N              (0x0fff << 0)
+#define STB0899_OFFST_EQ_I_INIT_COEFF_N                0
+#define STB0899_WIDTH_EQ_I_INIT_COEFF_N                12
+
+#define STB0899_OFF0_EQ_Q_INIT_COEFF_0         0xf350
+#define STB0899_OFF1_EQ_Q_INIT_COEFF_1         0xf354
+#define STB0899_OFF2_EQ_Q_INIT_COEFF_2         0xf358
+#define STB0899_OFF3_EQ_Q_INIT_COEFF_3         0xf35c
+#define STB0899_OFF4_EQ_Q_INIT_COEFF_4         0xf360
+#define STB0899_OFF5_EQ_Q_INIT_COEFF_5         0xf364
+#define STB0899_OFF6_EQ_Q_INIT_COEFF_6         0xf368
+#define STB0899_OFF7_EQ_Q_INIT_COEFF_7         0xf36c
+#define STB0899_OFF8_EQ_Q_INIT_COEFF_8         0xf370
+#define STB0899_OFF9_EQ_Q_INIT_COEFF_9         0xf374
+#define STB0899_OFFa_EQ_Q_INIT_COEFF_10                0xf378
+#define STB0899_BASE_EQ_Q_INIT_COEFF_N         0x00000440
+#define STB0899_EQ_Q_INIT_COEFF_N              (0x0fff << 0)
+#define STB0899_OFFST_EQ_Q_INIT_COEFF_N                0
+#define STB0899_WIDTH_EQ_Q_INIT_COEFF_N                12
+
+#define STB0899_OFF0_EQ_I_OUT_COEFF_0          0xf300
+#define STB0899_OFF1_EQ_I_OUT_COEFF_1          0xf304
+#define STB0899_OFF2_EQ_I_OUT_COEFF_2          0xf308
+#define STB0899_OFF3_EQ_I_OUT_COEFF_3          0xf30c
+#define STB0899_OFF4_EQ_I_OUT_COEFF_4          0xf310
+#define STB0899_OFF5_EQ_I_OUT_COEFF_5          0xf314
+#define STB0899_OFF6_EQ_I_OUT_COEFF_6          0xf318
+#define STB0899_OFF7_EQ_I_OUT_COEFF_7          0xf31c
+#define STB0899_OFF8_EQ_I_OUT_COEFF_8          0xf320
+#define STB0899_OFF9_EQ_I_OUT_COEFF_9          0xf324
+#define STB0899_OFFa_EQ_I_OUT_COEFF_10         0xf328
+#define STB0899_BASE_EQ_I_OUT_COEFF_N          0x00000460
+#define STB0899_EQ_I_OUT_COEFF_N               (0x0fff << 0)
+#define STB0899_OFFST_EQ_I_OUT_COEFF_N         0
+#define STB0899_WIDTH_EQ_I_OUT_COEFF_N         12
+
+#define STB0899_OFF0_EQ_Q_OUT_COEFF_0          0xf330
+#define STB0899_OFF1_EQ_Q_OUT_COEFF_1          0xf334
+#define STB0899_OFF2_EQ_Q_OUT_COEFF_2          0xf338
+#define STB0899_OFF3_EQ_Q_OUT_COEFF_3          0xf33c
+#define STB0899_OFF4_EQ_Q_OUT_COEFF_4          0xf340
+#define STB0899_OFF5_EQ_Q_OUT_COEFF_5          0xf344
+#define STB0899_OFF6_EQ_Q_OUT_COEFF_6          0xf348
+#define STB0899_OFF7_EQ_Q_OUT_COEFF_7          0xf34c
+#define STB0899_OFF8_EQ_Q_OUT_COEFF_8          0xf350
+#define STB0899_OFF9_EQ_Q_OUT_COEFF_9          0xf354
+#define STB0899_OFFa_EQ_Q_OUT_COEFF_10         0xf358
+#define STB0899_BASE_EQ_Q_OUT_COEFF_N          0x00000460
+#define STB0899_EQ_Q_OUT_COEFF_N               (0x0fff << 0)
+#define STB0899_OFFST_EQ_Q_OUT_COEFF_N         0
+#define STB0899_WIDTH_EQ_Q_OUT_COEFF_N         12
+
+/*     S2 FEC  */
+#define STB0899_OFF0_BLOCK_LNGTH               0xfa04
+#define STB0899_BASE_BLOCK_LNGTH               0x00000000
+#define STB0899_BLOCK_LENGTH                   (0xff << 0)
+#define STB0899_OFFST_BLOCK_LENGTH             0
+#define STB0899_WIDTH_BLOCK_LENGTH             8
+
+#define STB0899_OFF0_ROW_STR                   0xfa08
+#define STB0899_BASE_ROW_STR                   0x00000000
+#define STB0899_ROW_STRIDE                     (0xff << 0)
+#define STB0899_OFFST_ROW_STRIDE               0
+#define STB0899_WIDTH_ROW_STRIDE               8
+
+#define STB0899_OFF0_MAX_ITER                  0xfa0c
+#define STB0899_BASE_MAX_ITER                  0x00000000
+#define STB0899_MAX_ITERATIONS                 (0xff << 0)
+#define STB0899_OFFST_MAX_ITERATIONS           0
+#define STB0899_WIDTH_MAX_ITERATIONS           8
+
+#define STB0899_OFF0_BN_END_ADDR               0xfa10
+#define STB0899_BASE_BN_END_ADDR               0x00000000
+#define STB0899_BN_END_ADDR                    (0x0fff << 0)
+#define STB0899_OFFST_BN_END_ADDR              0
+#define STB0899_WIDTH_BN_END_ADDR              12
+
+#define STB0899_OFF0_CN_END_ADDR               0xfa14
+#define STB0899_BASE_CN_END_ADDR               0x00000000
+#define STB0899_CN_END_ADDR                    (0x0fff << 0)
+#define STB0899_OFFST_CN_END_ADDR              0
+#define STB0899_WIDTH_CN_END_ADDR              12
+
+#define STB0899_OFF0_INFO_LENGTH               0xfa1c
+#define STB0899_BASE_INFO_LENGTH               0x00000000
+#define STB0899_INFO_LENGTH                    (0xff << 0)
+#define STB0899_OFFST_INFO_LENGTH              0
+#define STB0899_WIDTH_INFO_LENGTH              8
+
+#define STB0899_OFF0_BOT_ADDR                  0xfa20
+#define STB0899_BASE_BOT_ADDR                  0x00000000
+#define STB0899_BOTTOM_BASE_ADDR               (0x03ff << 0)
+#define STB0899_OFFST_BOTTOM_BASE_ADDR         0
+#define STB0899_WIDTH_BOTTOM_BASE_ADDR         10
+
+#define STB0899_OFF0_BCH_BLK_LN                        0xfa24
+#define STB0899_BASE_BCH_BLK_LN                        0x00000000
+#define STB0899_BCH_BLOCK_LENGTH               (0xffff << 0)
+#define STB0899_OFFST_BCH_BLOCK_LENGTH         0
+#define STB0899_WIDTH_BCH_BLOCK_LENGTH         16
+
+#define STB0899_OFF0_BCH_T                     0xfa28
+#define STB0899_BASE_BCH_T                     0x00000000
+#define STB0899_BCH_T                          (0x0f << 0)
+#define STB0899_OFFST_BCH_T                    0
+#define STB0899_WIDTH_BCH_T                    4
+
+#define STB0899_OFF0_CNFG_MODE                 0xfa00
+#define STB0899_BASE_CNFG_MODE                 0x00000800
+#define STB0899_MODCOD                         (0x1f << 2)
+#define STB0899_OFFST_MODCOD                   2
+#define STB0899_WIDTH_MODCOD                   5
+#define STB0899_MODCOD_SEL                     (0x01 << 1)
+#define STB0899_OFFST_MODCOD_SEL               1
+#define STB0899_WIDTH_MODCOD_SEL               1
+#define STB0899_CONFIG_MODE                    (0x01 << 0)
+#define STB0899_OFFST_CONFIG_MODE              0
+#define STB0899_WIDTH_CONFIG_MODE              1
+
+#define STB0899_OFF0_LDPC_STAT                 0xfa04
+#define STB0899_BASE_LDPC_STAT                 0x00000800
+#define STB0899_ITERATION                      (0xff << 3)
+#define STB0899_OFFST_ITERATION                        3
+#define STB0899_WIDTH_ITERATION                        8
+#define STB0899_LDPC_DEC_STATE                 (0x07 << 0)
+#define STB0899_OFFST_LDPC_DEC_STATE           0
+#define STB0899_WIDTH_LDPC_DEC_STATE           3
+
+#define STB0899_OFF0_ITER_SCALE                        0xfa08
+#define STB0899_BASE_ITER_SCALE                        0x00000800
+#define STB0899_ITERATION_SCALE                        (0xff << 0)
+#define STB0899_OFFST_ITERATION_SCALE          0
+#define STB0899_WIDTH_ITERATION_SCALE          8
+
+#define STB0899_OFF0_INPUT_MODE                        0xfa0c
+#define STB0899_BASE_INPUT_MODE                        0x00000800
+#define STB0899_SD_BLOCK1_STREAM0              (0x01 << 0)
+#define STB0899_OFFST_SD_BLOCK1_STREAM0                0
+#define STB0899_WIDTH_SD_BLOCK1_STREAM0                1
+
+#define STB0899_OFF0_LDPCDECRST                        0xfa10
+#define STB0899_BASE_LDPCDECRST                        0x00000800
+#define STB0899_LDPC_DEC_RST                   (0x01 << 0)
+#define STB0899_OFFST_LDPC_DEC_RST             0
+#define STB0899_WIDTH_LDPC_DEC_RST             1
+
+#define STB0899_OFF0_CLK_PER_BYTE_RW           0xfa14
+#define STB0899_BASE_CLK_PER_BYTE_RW           0x00000800
+#define STB0899_CLKS_PER_BYTE                  (0x0f << 0)
+#define STB0899_OFFST_CLKS_PER_BYTE            0
+#define STB0899_WIDTH_CLKS_PER_BYTE            5
+
+#define STB0899_OFF0_BCH_ERRORS                        0xfa18
+#define STB0899_BASE_BCH_ERRORS                        0x00000800
+#define STB0899_BCH_ERRORS                     (0x0f << 0)
+#define STB0899_OFFST_BCH_ERRORS               0
+#define STB0899_WIDTH_BCH_ERRORS               4
+
+#define STB0899_OFF0_LDPC_ERRORS               0xfa1c
+#define STB0899_BASE_LDPC_ERRORS               0x00000800
+#define STB0899_LDPC_ERRORS                    (0xffff << 0)
+#define STB0899_OFFST_LDPC_ERRORS              0
+#define STB0899_WIDTH_LDPC_ERRORS              16
+
+#define STB0899_OFF0_BCH_MODE                  0xfa20
+#define STB0899_BASE_BCH_MODE                  0x00000800
+#define STB0899_BCH_CORRECT_N                  (0x01 << 1)
+#define STB0899_OFFST_BCH_CORRECT_N            1
+#define STB0899_WIDTH_BCH_CORRECT_N            1
+#define STB0899_FULL_BYPASS                    (0x01 << 0)
+#define STB0899_OFFST_FULL_BYPASS              0
+#define STB0899_WIDTH_FULL_BYPASS              1
+
+#define STB0899_OFF0_ERR_ACC_PER               0xfa24
+#define STB0899_BASE_ERR_ACC_PER               0x00000800
+#define STB0899_BCH_ERR_ACC_PERIOD             (0x0f << 0)
+#define STB0899_OFFST_BCH_ERR_ACC_PERIOD       0
+#define STB0899_WIDTH_BCH_ERR_ACC_PERIOD       4
+
+#define STB0899_OFF0_BCH_ERR_ACC               0xfa28
+#define STB0899_BASE_BCH_ERR_ACC               0x00000800
+#define STB0899_BCH_ERR_ACCUM                  (0xff << 0)
+#define STB0899_OFFST_BCH_ERR_ACCUM            0
+#define STB0899_WIDTH_BCH_ERR_ACCUM            8
+
+#define STB0899_OFF0_FEC_CORE_ID_REG           0xfa2c
+#define STB0899_BASE_FEC_CORE_ID_REG           0x00000800
+#define STB0899_FEC_CORE_ID                    (0xffffffff << 0)
+#define STB0899_OFFST_FEC_CORE_ID              0
+#define STB0899_WIDTH_FEC_CORE_ID              32
+
+#define STB0899_OFF0_FEC_VER_ID_REG            0xfa34
+#define STB0899_BASE_FEC_VER_ID_REG            0x00000800
+#define STB0899_FEC_VER_ID                     (0xff << 0)
+#define STB0899_OFFST_FEC_VER_ID               0
+#define STB0899_WIDTH_FEC_VER_ID               8
+
+#define STB0899_OFF0_FEC_TP_SEL                        0xfa38
+#define STB0899_BASE_FEC_TP_SEL                        0x00000800
+
+#define STB0899_OFF0_CSM_CNTRL1                        0xf310
+#define STB0899_BASE_CSM_CNTRL1                        0x00000400
+#define STB0899_CSM_FORCE_FREQLOCK             (0x01 << 19)
+#define STB0899_OFFST_CSM_FORCE_FREQLOCK       19
+#define STB0899_WIDTH_CSM_FORCE_FREQLOCK       1
+#define STB0899_CSM_FREQ_LOCKSTATE             (0x01 << 18)
+#define STB0899_OFFST_CSM_FREQ_LOCKSTATE       18
+#define STB0899_WIDTH_CSM_FREQ_LOCKSTATE       1
+#define STB0899_CSM_AUTO_PARAM                 (0x01 << 17)
+#define STB0899_OFFST_CSM_AUTO_PARAM           17
+#define STB0899_WIDTH_CSM_AUTO_PARAM           1
+#define STB0899_FE_LOOP_SHIFT                  (0x07 << 14)
+#define STB0899_OFFST_FE_LOOP_SHIFT            14
+#define STB0899_WIDTH_FE_LOOP_SHIFT            3
+#define STB0899_CSM_AGC_SHIFT                  (0x07 << 11)
+#define STB0899_OFFST_CSM_AGC_SHIFT            11
+#define STB0899_WIDTH_CSM_AGC_SHIFT            3
+#define STB0899_CSM_AGC_GAIN                   (0x1ff << 2)
+#define STB0899_OFFST_CSM_AGC_GAIN             2
+#define STB0899_WIDTH_CSM_AGC_GAIN             9
+#define STB0899_CSM_TWO_PASS                   (0x01 << 1)
+#define STB0899_OFFST_CSM_TWO_PASS             1
+#define STB0899_WIDTH_CSM_TWO_PASS             1
+#define STB0899_CSM_DVT_TABLE                  (0x01 << 0)
+#define STB0899_OFFST_CSM_DVT_TABLE            0
+#define STB0899_WIDTH_CSM_DVT_TABLE            1
+
+#define STB0899_OFF0_CSM_CNTRL2                        0xf314
+#define STB0899_BASE_CSM_CNTRL2                        0x00000400
+#define STB0899_CSM_GAMMA_RHO_ACQ              (0x1ff << 9)
+#define STB0899_OFFST_CSM_GAMMA_RHOACQ         9
+#define STB0899_WIDTH_CSM_GAMMA_RHOACQ         9
+#define STB0899_CSM_GAMMA_ACQ                  (0x1ff << 0)
+#define STB0899_OFFST_CSM_GAMMA_ACQ            0
+#define STB0899_WIDTH_CSM_GAMMA_ACQ            9
+
+#define STB0899_OFF0_CSM_CNTRL3                        0xf318
+#define STB0899_BASE_CSM_CNTRL3                        0x00000400
+#define STB0899_CSM_GAMMA_RHO_TRACK            (0x1ff << 9)
+#define STB0899_OFFST_CSM_GAMMA_RHOTRACK       9
+#define STB0899_WIDTH_CSM_GAMMA_RHOTRACK       9
+#define STB0899_CSM_GAMMA_TRACK                        (0x1ff << 0)
+#define STB0899_OFFST_CSM_GAMMA_TRACK          0
+#define STB0899_WIDTH_CSM_GAMMA_TRACK          9
+
+#define STB0899_OFF0_CSM_CNTRL4                        0xf31c
+#define STB0899_BASE_CSM_CNTRL4                        0x00000400
+#define STB0899_CSM_PHASEDIFF_THRESH           (0x0f << 8)
+#define STB0899_OFFST_CSM_PHASEDIFF_THRESH     8
+#define STB0899_WIDTH_CSM_PHASEDIFF_THRESH     4
+#define STB0899_CSM_LOCKCOUNT_THRESH           (0xff << 0)
+#define STB0899_OFFST_CSM_LOCKCOUNT_THRESH     0
+#define STB0899_WIDTH_CSM_LOCKCOUNT_THRESH     8
+
+/*     Check on chapter 8 page 42      */
+#define STB0899_ERRCTRL1                       0xf574
+#define STB0899_ERRCTRL2                       0xf575
+#define STB0899_ERRCTRL3                       0xf576
+#define STB0899_ERR_SRC_S1                     (0x1f << 3)
+#define STB0899_OFFST_ERR_SRC_S1               3
+#define STB0899_WIDTH_ERR_SRC_S1               5
+#define STB0899_ERR_SRC_S2                     (0x0f << 0)
+#define STB0899_OFFST_ERR_SRC_S2               0
+#define STB0899_WIDTH_ERR_SRC_S2               4
+#define STB0899_NOE                            (0x07 << 0)
+#define STB0899_OFFST_NOE                      0
+#define STB0899_WIDTH_NOE                      3
+
+#define STB0899_ECNT1M                         0xf524
+#define STB0899_ECNT1L                         0xf525
+#define STB0899_ECNT2M                         0xf526
+#define STB0899_ECNT2L                         0xf527
+#define STB0899_ECNT3M                         0xf528
+#define STB0899_ECNT3L                         0xf529
+
+#define STB0899_DMONMSK1                       0xf57b
+#define STB0899_DMONMSK1_WAIT_1STEP            (1 << 7)
+#define STB0899_DMONMSK1_FREE_14               (1 << 6)
+#define STB0899_DMONMSK1_AVRGVIT_CALC          (1 << 5)
+#define STB0899_DMONMSK1_FREE_12               (1 << 4)
+#define STB0899_DMONMSK1_FREE_11               (1 << 3)
+#define STB0899_DMONMSK1_B0DIV_CALC            (1 << 2)
+#define STB0899_DMONMSK1_KDIVB1_CALC           (1 << 1)
+#define STB0899_DMONMSK1_KDIVB2_CALC           (1 << 0)
+
+#define STB0899_DMONMSK0                       0xf57c
+#define STB0899_DMONMSK0_SMOTTH_CALC           (1 << 7)
+#define STB0899_DMONMSK0_FREE_6                        (1 << 6)
+#define STB0899_DMONMSK0_SIGPOWER_CALC         (1 << 5)
+#define STB0899_DMONMSK0_QSEUIL_CALC           (1 << 4)
+#define STB0899_DMONMSK0_FREE_3                        (1 << 3)
+#define STB0899_DMONMSK0_FREE_2                        (1 << 2)
+#define STB0899_DMONMSK0_KVDIVB1_CALC          (1 << 1)
+#define STB0899_DMONMSK0_KVDIVB2_CALC          (1 << 0)
+
+#define STB0899_TSULC                          0xf549
+#define STB0899_ULNOSYNCBYTES                  (0x01 << 7)
+#define STB0899_OFFST_ULNOSYNCBYTES            7
+#define STB0899_WIDTH_ULNOSYNCBYTES            1
+#define STB0899_ULPARITY_ON                    (0x01 << 6)
+#define STB0899_OFFST_ULPARITY_ON              6
+#define STB0899_WIDTH_ULPARITY_ON              1
+#define STB0899_ULSYNCOUTRS                    (0x01 << 5)
+#define STB0899_OFFST_ULSYNCOUTRS              5
+#define STB0899_WIDTH_ULSYNCOUTRS              1
+#define STB0899_ULDSS_PACKETS                  (0x01 << 0)
+#define STB0899_OFFST_ULDSS_PACKETS            0
+#define STB0899_WIDTH_ULDSS_PACKETS            1
+
+#define STB0899_TSLPL                          0xf54b
+#define STB0899_LLDVBS2_MODE                   (0x01 << 4)
+#define STB0899_OFFST_LLDVBS2_MODE             4
+#define STB0899_WIDTH_LLDVBS2_MODE             1
+#define STB0899_LLISSYI_ON                     (0x01 << 3)
+#define STB0899_OFFST_LLISSYI_ON               3
+#define STB0899_WIDTH_LLISSYI_ON               1
+#define STB0899_LLNPD_ON                       (0x01 << 2)
+#define STB0899_OFFST_LLNPD_ON                 2
+#define STB0899_WIDTH_LLNPD_ON                 1
+#define STB0899_LLCRC8_ON                      (0x01 << 1)
+#define STB0899_OFFST_LLCRC8_ON                        1
+#define STB0899_WIDTH_LLCRC8_ON                        1
+
+#define STB0899_TSCFGH                         0xf54c
+#define STB0899_OUTRS_PS                       (0x01 << 6)
+#define STB0899_OFFST_OUTRS_PS                 6
+#define STB0899_WIDTH_OUTRS_PS                 1
+#define STB0899_SYNCBYTE                       (0x01 << 5)
+#define STB0899_OFFST_SYNCBYTE                 5
+#define STB0899_WIDTH_SYNCBYTE                 1
+#define STB0899_PFBIT                          (0x01 << 4)
+#define STB0899_OFFST_PFBIT                    4
+#define STB0899_WIDTH_PFBIT                    1
+#define STB0899_ERR_BIT                                (0x01 << 3)
+#define STB0899_OFFST_ERR_BIT                  3
+#define STB0899_WIDTH_ERR_BIT                  1
+#define STB0899_MPEG                           (0x01 << 2)
+#define STB0899_OFFST_MPEG                     2
+#define STB0899_WIDTH_MPEG                     1
+#define STB0899_CLK_POL                                (0x01 << 1)
+#define STB0899_OFFST_CLK_POL                  1
+#define STB0899_WIDTH_CLK_POL                  1
+#define STB0899_FORCE0                         (0x01 << 0)
+#define STB0899_OFFST_FORCE0                   0
+#define STB0899_WIDTH_FORCE0                   1
+
+#define STB0899_TSCFGM                         0xf54d
+#define STB0899_LLPRIORITY                     (0x01 << 3)
+#define STB0899_OFFST_LLPRIORIY                        3
+#define STB0899_WIDTH_LLPRIORITY               1
+#define STB0899_EN188                          (0x01 << 2)
+#define STB0899_OFFST_EN188                    2
+#define STB0899_WIDTH_EN188                    1
+
+#define STB0899_TSCFGL                         0xf54e
+#define STB0899_DEL_ERRPCK                     (0x01 << 7)
+#define STB0899_OFFST_DEL_ERRPCK               7
+#define STB0899_WIDTH_DEL_ERRPCK               1
+#define STB0899_ERRFLAGSTD                     (0x01 << 5)
+#define STB0899_OFFST_ERRFLAGSTD               5
+#define STB0899_WIDTH_ERRFLAGSTD               1
+#define STB0899_MPEGERR                                (0x01 << 4)
+#define STB0899_OFFST_MPEGERR                  4
+#define STB0899_WIDTH_MPEGERR                  1
+#define STB0899_BCH_CHK                                (0x01 << 3)
+#define STB0899_OFFST_BCH_CHK                  5
+#define STB0899_WIDTH_BCH_CHK                  1
+#define STB0899_CRC8CHK                                (0x01 << 2)
+#define STB0899_OFFST_CRC8CHK                  2
+#define STB0899_WIDTH_CRC8CHK                  1
+#define STB0899_SPEC_INFO                      (0x01 << 1)
+#define STB0899_OFFST_SPEC_INFO                        1
+#define STB0899_WIDTH_SPEC_INFO                        1
+#define STB0899_LOW_PRIO_CLK                   (0x01 << 0)
+#define STB0899_OFFST_LOW_PRIO_CLK             0
+#define STB0899_WIDTH_LOW_PRIO_CLK             1
+#define STB0899_ERROR_NORM                     (0x00 << 0)
+#define STB0899_OFFST_ERROR_NORM               0
+#define STB0899_WIDTH_ERROR_NORM               0
+
+#define STB0899_TSOUT                          0xf54f
+#define STB0899_RSSYNCDEL                      0xf550
+#define STB0899_TSINHDELH                      0xf551
+#define STB0899_TSINHDELM                      0xf552
+#define STB0899_TSINHDELL                      0xf553
+#define STB0899_TSLLSTKM                       0xf55a
+#define STB0899_TSLLSTKL                       0xf55b
+#define STB0899_TSULSTKM                       0xf55c
+#define STB0899_TSULSTKL                       0xf55d
+#define STB0899_TSSTATUS                       0xf561
+
+#define STB0899_PDELCTRL                       0xf600
+#define STB0899_INVERT_RES                     (0x01 << 7)
+#define STB0899_OFFST_INVERT_RES               7
+#define STB0899_WIDTH_INVERT_RES               1
+#define STB0899_FORCE_ACCEPTED                 (0x01 << 6)
+#define STB0899_OFFST_FORCE_ACCEPTED           6
+#define STB0899_WIDTH_FORCE_ACCEPTED           1
+#define STB0899_FILTER_EN                      (0x01 << 5)
+#define STB0899_OFFST_FILTER_EN                        5
+#define STB0899_WIDTH_FILTER_EN                        1
+#define STB0899_LOCKFALL_THRESH                        (0x01 << 4)
+#define STB0899_OFFST_LOCKFALL_THRESH          4
+#define STB0899_WIDTH_LOCKFALL_THRESH          1
+#define STB0899_HYST_EN                                (0x01 << 3)
+#define STB0899_OFFST_HYST_EN                  3
+#define STB0899_WIDTH_HYST_EN                  1
+#define STB0899_HYST_SWRST                     (0x01 << 2)
+#define STB0899_OFFST_HYST_SWRST               2
+#define STB0899_WIDTH_HYST_SWRST               1
+#define STB0899_ALGO_EN                                (0x01 << 1)
+#define STB0899_OFFST_ALGO_EN                  1
+#define STB0899_WIDTH_ALGO_EN                  1
+#define STB0899_ALGO_SWRST                     (0x01 << 0)
+#define STB0899_OFFST_ALGO_SWRST               0
+#define STB0899_WIDTH_ALGO_SWRST               1
+
+#define STB0899_PDELCTRL2                      0xf601
+#define STB0899_BBHCTRL1                       0xf602
+#define STB0899_BBHCTRL2                       0xf603
+#define STB0899_HYSTTHRESH                     0xf604
+
+#define STB0899_MATCSTM                                0xf605
+#define STB0899_MATCSTL                                0xf606
+#define STB0899_UPLCSTM                                0xf607
+#define STB0899_UPLCSTL                                0xf608
+#define STB0899_DFLCSTM                                0xf609
+#define STB0899_DFLCSTL                                0xf60a
+#define STB0899_SYNCCST                                0xf60b
+#define STB0899_SYNCDCSTM                      0xf60c
+#define STB0899_SYNCDCSTL                      0xf60d
+#define STB0899_ISI_ENTRY                      0xf60e
+#define STB0899_ISI_BIT_EN                     0xf60f
+#define STB0899_MATSTRM                                0xf610
+#define STB0899_MATSTRL                                0xf611
+#define STB0899_UPLSTRM                                0xf612
+#define STB0899_UPLSTRL                                0xf613
+#define STB0899_DFLSTRM                                0xf614
+#define STB0899_DFLSTRL                                0xf615
+#define STB0899_SYNCSTR                                0xf616
+#define STB0899_SYNCDSTRM                      0xf617
+#define STB0899_SYNCDSTRL                      0xf618
+
+#define STB0899_CFGPDELSTATUS1                 0xf619
+#define STB0899_BADDFL                         (0x01 << 6)
+#define STB0899_OFFST_BADDFL                   6
+#define STB0899_WIDTH_BADDFL                   1
+#define STB0899_CONTINUOUS_STREAM              (0x01 << 5)
+#define STB0899_OFFST_CONTINUOUS_STREAM                5
+#define STB0899_WIDTH_CONTINUOUS_STREAM                1
+#define STB0899_ACCEPTED_STREAM                        (0x01 << 4)
+#define STB0899_OFFST_ACCEPTED_STREAM          4
+#define STB0899_WIDTH_ACCEPTED_STREAM          1
+#define STB0899_BCH_ERRFLAG                    (0x01 << 3)
+#define STB0899_OFFST_BCH_ERRFLAG              3
+#define STB0899_WIDTH_BCH_ERRFLAG              1
+#define STB0899_CRCRES                         (0x01 << 2)
+#define STB0899_OFFST_CRCRES                   2
+#define STB0899_WIDTH_CRCRES                   1
+#define STB0899_CFGPDELSTATUS_LOCK             (0x01 << 1)
+#define STB0899_OFFST_CFGPDELSTATUS_LOCK       1
+#define STB0899_WIDTH_CFGPDELSTATUS_LOCK       1
+#define STB0899_1STLOCK                                (0x01 << 0)
+#define STB0899_OFFST_1STLOCK                  0
+#define STB0899_WIDTH_1STLOCK                  1
+
+#define STB0899_CFGPDELSTATUS2                 0xf61a
+#define STB0899_BBFERRORM                      0xf61b
+#define STB0899_BBFERRORL                      0xf61c
+#define STB0899_UPKTERRORM                     0xf61d
+#define STB0899_UPKTERRORL                     0xf61e
+
+#define STB0899_TSTCK                          0xff10
+
+#define STB0899_TSTRES                         0xff11
+#define STB0899_FRESLDPC                       (0x01 << 7)
+#define STB0899_OFFST_FRESLDPC                 7
+#define STB0899_WIDTH_FRESLDPC                 1
+#define STB0899_FRESRS                         (0x01 << 6)
+#define STB0899_OFFST_FRESRS                   6
+#define STB0899_WIDTH_FRESRS                   1
+#define STB0899_FRESVIT                                (0x01 << 5)
+#define STB0899_OFFST_FRESVIT                  5
+#define STB0899_WIDTH_FRESVIT                  1
+#define STB0899_FRESMAS1_2                     (0x01 << 4)
+#define STB0899_OFFST_FRESMAS1_2               4
+#define STB0899_WIDTH_FRESMAS1_2               1
+#define STB0899_FRESACS                                (0x01 << 3)
+#define STB0899_OFFST_FRESACS                  3
+#define STB0899_WIDTH_FRESACS                  1
+#define STB0899_FRESSYM                                (0x01 << 2)
+#define STB0899_OFFST_FRESSYM                  2
+#define STB0899_WIDTH_FRESSYM                  1
+#define STB0899_FRESMAS                                (0x01 << 1)
+#define STB0899_OFFST_FRESMAS                  1
+#define STB0899_WIDTH_FRESMAS                  1
+#define STB0899_FRESINT                                (0x01 << 0)
+#define STB0899_OFFST_FRESINIT                 0
+#define STB0899_WIDTH_FRESINIT                 1
+
+#define STB0899_TSTOUT                         0xff12
+#define STB0899_EN_SIGNATURE                   (0x01 << 7)
+#define STB0899_OFFST_EN_SIGNATURE             7
+#define STB0899_WIDTH_EN_SIGNATURE             1
+#define STB0899_BCLK_CLK                       (0x01 << 6)
+#define STB0899_OFFST_BCLK_CLK                 6
+#define STB0899_WIDTH_BCLK_CLK                 1
+#define STB0899_SGNL_OUT                       (0x01 << 5)
+#define STB0899_OFFST_SGNL_OUT                 5
+#define STB0899_WIDTH_SGNL_OUT                 1
+#define STB0899_TS                             (0x01 << 4)
+#define STB0899_OFFST_TS                       4
+#define STB0899_WIDTH_TS                       1
+#define STB0899_CTEST                          (0x01 << 0)
+#define STB0899_OFFST_CTEST                    0
+#define STB0899_WIDTH_CTEST                    1
+
+#define STB0899_TSTIN                          0xff13
+#define STB0899_TEST_IN                                (0x01 << 7)
+#define STB0899_OFFST_TEST_IN                  7
+#define STB0899_WIDTH_TEST_IN                  1
+#define STB0899_EN_ADC                         (0x01 << 6)
+#define STB0899_OFFST_EN_ADC                   6
+#define STB0899_WIDTH_ENADC                    1
+#define STB0899_SGN_ADC                                (0x01 << 5)
+#define STB0899_OFFST_SGN_ADC                  5
+#define STB0899_WIDTH_SGN_ADC                  1
+#define STB0899_BCLK_IN                                (0x01 << 4)
+#define STB0899_OFFST_BCLK_IN                  4
+#define STB0899_WIDTH_BCLK_IN                  1
+#define STB0899_JETONIN_MODE                   (0x01 << 3)
+#define STB0899_OFFST_JETONIN_MODE             3
+#define STB0899_WIDTH_JETONIN_MODE             1
+#define STB0899_BCLK_VALUE                     (0x01 << 2)
+#define STB0899_OFFST_BCLK_VALUE               2
+#define STB0899_WIDTH_BCLK_VALUE               1
+#define STB0899_SGNRST_T12                     (0x01 << 1)
+#define STB0899_OFFST_SGNRST_T12               1
+#define STB0899_WIDTH_SGNRST_T12               1
+#define STB0899_LOWSP_ENAX                     (0x01 << 0)
+#define STB0899_OFFST_LOWSP_ENAX               0
+#define STB0899_WIDTH_LOWSP_ENAX               1
+
+#define STB0899_TSTSYS                         0xff14
+#define STB0899_TSTCHIP                                0xff15
+#define STB0899_TSTFREE                                0xff16
+#define STB0899_TSTI2C                         0xff17
+#define STB0899_BITSPEEDM                      0xff1c
+#define STB0899_BITSPEEDL                      0xff1d
+#define STB0899_TBUSBIT                                0xff1e
+#define STB0899_TSTDIS                         0xff24
+#define STB0899_TSTDISRX                       0xff25
+#define STB0899_TSTJETON                       0xff28
+#define STB0899_TSTDCADJ                       0xff40
+#define STB0899_TSTAGC1                                0xff41
+#define STB0899_TSTAGC1N                       0xff42
+#define STB0899_TSTPOLYPH                      0xff48
+#define STB0899_TSTR                           0xff49
+#define STB0899_TSTAGC2                                0xff4a
+#define STB0899_TSTCTL1                                0xff4b
+#define STB0899_TSTCTL2                                0xff4c
+#define STB0899_TSTCTL3                                0xff4d
+#define STB0899_TSTDEMAP                       0xff50
+#define STB0899_TSTDEMAP2                      0xff51
+#define STB0899_TSTDEMMON                      0xff52
+#define STB0899_TSTRATE                                0xff53
+#define STB0899_TSTSELOUT                      0xff54
+#define STB0899_TSYNC                          0xff55
+#define STB0899_TSTERR                         0xff56
+#define STB0899_TSTRAM1                                0xff58
+#define STB0899_TSTVSELOUT                     0xff59
+#define STB0899_TSTFORCEIN                     0xff5a
+#define STB0899_TSTRS1                         0xff5c
+#define STB0899_TSTRS2                         0xff5d
+#define STB0899_TSTRS3                         0xff53
+
+#define STB0899_INTBUFSTATUS                   0xf200
+#define STB0899_INTBUFCTRL                     0xf201
+#define STB0899_PCKLENUL                       0xf55e
+#define STB0899_PCKLENLL                       0xf55f
+#define STB0899_RSPCKLEN                       0xf560
+
+/*     2 registers     */
+#define STB0899_SYNCDCST                       0xf60c
+
+/*     DiSEqC  */
+#define STB0899_DISCNTRL1                      0xf0a0
+#define STB0899_TIMOFF                         (0x01 << 7)
+#define STB0899_OFFST_TIMOFF                   7
+#define STB0899_WIDTH_TIMOFF                   1
+#define STB0899_DISEQCRESET                    (0x01 << 6)
+#define STB0899_OFFST_DISEQCRESET              6
+#define STB0899_WIDTH_DISEQCRESET              1
+#define STB0899_TIMCMD                         (0x03 << 4)
+#define STB0899_OFFST_TIMCMD                   4
+#define STB0899_WIDTH_TIMCMD                   2
+#define STB0899_DISPRECHARGE                   (0x01 << 2)
+#define STB0899_OFFST_DISPRECHARGE             2
+#define STB0899_WIDTH_DISPRECHARGE             1
+#define STB0899_DISEQCMODE                     (0x03 << 0)
+#define STB0899_OFFST_DISEQCMODE               0
+#define STB0899_WIDTH_DISEQCMODE               2
+
+#define STB0899_DISCNTRL2                      0xf0a1
+#define STB0899_RECEIVER_ON                    (0x01 << 7)
+#define STB0899_OFFST_RECEIVER_ON              7
+#define STB0899_WIDTH_RECEIVER_ON              1
+#define STB0899_IGNO_SHORT_22K                 (0x01 << 6)
+#define STB0899_OFFST_IGNO_SHORT_22K           6
+#define STB0899_WIDTH_IGNO_SHORT_22K           1
+#define STB0899_ONECHIP_TRX                    (0x01 << 5)
+#define STB0899_OFFST_ONECHIP_TRX              5
+#define STB0899_WIDTH_ONECHIP_TRX              1
+#define STB0899_EXT_ENVELOP                    (0x01 << 4)
+#define STB0899_OFFST_EXT_ENVELOP              4
+#define STB0899_WIDTH_EXT_ENVELOP              1
+#define STB0899_PIN_SELECT                     (0x03 << 2)
+#define STB0899_OFFST_PIN_SELCT                        2
+#define STB0899_WIDTH_PIN_SELCT                        2
+#define STB0899_IRQ_RXEND                      (0x01 << 1)
+#define STB0899_OFFST_IRQ_RXEND                        1
+#define STB0899_WIDTH_IRQ_RXEND                        1
+#define STB0899_IRQ_4NBYTES                    (0x01 << 0)
+#define STB0899_OFFST_IRQ_4NBYTES              0
+#define STB0899_WIDTH_IRQ_4NBYTES              1
+
+#define STB0899_DISRX_ST0                      0xf0a4
+#define STB0899_RXEND                          (0x01 << 7)
+#define STB0899_OFFST_RXEND                    7
+#define STB0899_WIDTH_RXEND                    1
+#define STB0899_RXACTIVE                       (0x01 << 6)
+#define STB0899_OFFST_RXACTIVE                 6
+#define STB0899_WIDTH_RXACTIVE                 1
+#define STB0899_SHORT22K                       (0x01 << 5)
+#define STB0899_OFFST_SHORT22K                 5
+#define STB0899_WIDTH_SHORT22K                 1
+#define STB0899_CONTTONE                       (0x01 << 4)
+#define STB0899_OFFST_CONTTONE                 4
+#define STB0899_WIDTH_CONTONE                  1
+#define STB0899_4BFIFOREDY                     (0x01 << 3)
+#define STB0899_OFFST_4BFIFOREDY               3
+#define STB0899_WIDTH_4BFIFOREDY               1
+#define STB0899_FIFOEMPTY                      (0x01 << 2)
+#define STB0899_OFFST_FIFOEMPTY                        2
+#define STB0899_WIDTH_FIFOEMPTY                        1
+#define STB0899_ABORTTRX                       (0x01 << 0)
+#define STB0899_OFFST_ABORTTRX                 0
+#define STB0899_WIDTH_ABORTTRX                 1
+
+#define STB0899_DISRX_ST1                      0xf0a5
+#define STB0899_RXFAIL                         (0x01 << 7)
+#define STB0899_OFFST_RXFAIL                   7
+#define STB0899_WIDTH_RXFAIL                   1
+#define STB0899_FIFOPFAIL                      (0x01 << 6)
+#define STB0899_OFFST_FIFOPFAIL                        6
+#define STB0899_WIDTH_FIFOPFAIL                        1
+#define STB0899_RXNONBYTES                     (0x01 << 5)
+#define STB0899_OFFST_RXNONBYTES               5
+#define STB0899_WIDTH_RXNONBYTES               1
+#define STB0899_FIFOOVF                                (0x01 << 4)
+#define STB0899_OFFST_FIFOOVF                  4
+#define STB0899_WIDTH_FIFOOVF                  1
+#define STB0899_FIFOBYTENBR                    (0x0f << 0)
+#define STB0899_OFFST_FIFOBYTENBR              0
+#define STB0899_WIDTH_FIFOBYTENBR              4
+
+#define STB0899_DISPARITY                      0xf0a6
+
+#define STB0899_DISFIFO                                0xf0a7
+
+#define STB0899_DISSTATUS                      0xf0a8
+#define STB0899_FIFOFULL                       (0x01 << 6)
+#define STB0899_OFFST_FIFOFULL                 6
+#define STB0899_WIDTH_FIFOFULL                 1
+#define STB0899_TXIDLE                         (0x01 << 5)
+#define STB0899_OFFST_TXIDLE                   5
+#define STB0899_WIDTH_TXIDLE                   1
+#define STB0899_GAPBURST                       (0x01 << 4)
+#define STB0899_OFFST_GAPBURST                 4
+#define STB0899_WIDTH_GAPBURST                 1
+#define STB0899_TXFIFOBYTES                    (0x0f << 0)
+#define STB0899_OFFST_TXFIFOBYTES              0
+#define STB0899_WIDTH_TXFIFOBYTES              4
+#define STB0899_DISF22                         0xf0a9
+
+#define STB0899_DISF22RX                       0xf0aa
+
+/*     General Purpose */
+#define STB0899_SYSREG                         0xf101
+#define STB0899_ACRPRESC                       0xf110
+#define STB0899_OFFST_RSVD2                    7
+#define STB0899_WIDTH_RSVD2                    1
+#define STB0899_OFFST_ACRPRESC                 4
+#define STB0899_WIDTH_ACRPRESC                 3
+#define STB0899_OFFST_RSVD1                    3
+#define STB0899_WIDTH_RSVD1                    1
+#define STB0899_OFFST_ACRPRESC2                        0
+#define STB0899_WIDTH_ACRPRESC2                        3
+
+#define STB0899_ACRDIV1                                0xf111
+#define STB0899_ACRDIV2                                0xf112
+#define STB0899_DACR1                          0xf113
+#define STB0899_DACR2                          0xf114
+#define STB0899_OUTCFG                         0xf11c
+#define STB0899_MODECFG                                0xf11d
+#define STB0899_NCOARSE                                0xf1b3
+
+#define STB0899_SYNTCTRL                       0xf1b6
+#define STB0899_STANDBY                                (0x01 << 7)
+#define STB0899_OFFST_STANDBY                  7
+#define STB0899_WIDTH_STANDBY                  1
+#define STB0899_BYPASSPLL                      (0x01 << 6)
+#define STB0899_OFFST_BYPASSPLL                        6
+#define STB0899_WIDTH_BYPASSPLL                        1
+#define STB0899_SEL1XRATIO                     (0x01 << 5)
+#define STB0899_OFFST_SEL1XRATIO               5
+#define STB0899_WIDTH_SEL1XRATIO               1
+#define STB0899_SELOSCI                                (0x01 << 1)
+#define STB0899_OFFST_SELOSCI                  1
+#define STB0899_WIDTH_SELOSCI                  1
+
+#define STB0899_FILTCTRL                       0xf1b7
+#define STB0899_SYSCTRL                                0xf1b8
+
+#define STB0899_STOPCLK1                       0xf1c2
+#define STB0899_STOP_CKINTBUF108               (0x01 << 7)
+#define STB0899_OFFST_STOP_CKINTBUF108         7
+#define STB0899_WIDTH_STOP_CKINTBUF108         1
+#define STB0899_STOP_CKINTBUF216               (0x01 << 6)
+#define STB0899_OFFST_STOP_CKINTBUF216         6
+#define STB0899_WIDTH_STOP_CKINTBUF216         1
+#define STB0899_STOP_CHK8PSK                   (0x01 << 5)
+#define STB0899_OFFST_STOP_CHK8PSK             5
+#define STB0899_WIDTH_STOP_CHK8PSK             1
+#define STB0899_STOP_CKFEC108                  (0x01 << 4)
+#define STB0899_OFFST_STOP_CKFEC108            4
+#define STB0899_WIDTH_STOP_CKFEC108            1
+#define STB0899_STOP_CKFEC216                  (0x01 << 3)
+#define STB0899_OFFST_STOP_CKFEC216            3
+#define STB0899_WIDTH_STOP_CKFEC216            1
+#define STB0899_STOP_CKCORE216                 (0x01 << 2)
+#define STB0899_OFFST_STOP_CKCORE216           2
+#define STB0899_WIDTH_STOP_CKCORE216           1
+#define STB0899_STOP_CKADCI108                 (0x01 << 1)
+#define STB0899_OFFST_STOP_CKADCI108           1
+#define STB0899_WIDTH_STOP_CKADCI108           1
+#define STB0899_STOP_INVCKADCI108              (0x01 << 0)
+#define STB0899_OFFST_STOP_INVCKADCI108                0
+#define STB0899_WIDTH_STOP_INVCKADCI108                1
+
+#define STB0899_STOPCLK2                       0xf1c3
+#define STB0899_STOP_CKS2DMD108                        (0x01 << 2)
+#define STB0899_OFFST_STOP_CKS2DMD108          2
+#define STB0899_WIDTH_STOP_CKS2DMD108          1
+#define STB0899_STOP_CKPKDLIN108               (0x01 << 1)
+#define STB0899_OFFST_STOP_CKPKDLIN108         1
+#define STB0899_WIDTH_STOP_CKPKDLIN108         1
+#define STB0899_STOP_CKPKDLIN216               (0x01 << 0)
+#define STB0899_OFFST_STOP_CKPKDLIN216         0
+#define STB0899_WIDTH_STOP_CKPKDLIN216         1
+
+#define STB0899_TSTTNR1                                0xf1e0
+#define STB0899_BYPASS_ADC                     (0x01 << 7)
+#define STB0899_OFFST_BYPASS_ADC               7
+#define STB0899_WIDTH_BYPASS_ADC               1
+#define STB0899_INVADCICKOUT                   (0x01 << 6)
+#define STB0899_OFFST_INVADCICKOUT             6
+#define STB0899_WIDTH_INVADCICKOUT             1
+#define STB0899_ADCTEST_VOLTAGE                        (0x03 << 4)
+#define STB0899_OFFST_ADCTEST_VOLTAGE          4
+#define STB0899_WIDTH_ADCTEST_VOLTAGE          1
+#define STB0899_ADC_RESET                      (0x01 << 3)
+#define STB0899_OFFST_ADC_RESET                        3
+#define STB0899_WIDTH_ADC_RESET                        1
+#define STB0899_TSTTNR1_2                      (0x01 << 2)
+#define STB0899_OFFST_TSTTNR1_2                        2
+#define STB0899_WIDTH_TSTTNR1_2                        1
+#define STB0899_ADCPON                         (0x01 << 1)
+#define STB0899_OFFST_ADCPON                   1
+#define STB0899_WIDTH_ADCPON                   1
+#define STB0899_ADCIN_MODE                     (0x01 << 0)
+#define STB0899_OFFST_ADCIN_MODE               0
+#define STB0899_WIDTH_ADCIN_MODE               1
+
+#define STB0899_TSTTNR2                                0xf1e1
+#define STB0899_TSTTNR2_7                      (0x01 << 7)
+#define STB0899_OFFST_TSTTNR2_7                        7
+#define STB0899_WIDTH_TSTTNR2_7                        1
+#define STB0899_NOT_DISRX_WIRED                        (0x01 << 6)
+#define STB0899_OFFST_NOT_DISRX_WIRED          6
+#define STB0899_WIDTH_NOT_DISRX_WIRED          1
+#define STB0899_DISEQC_DCURRENT                        (0x01 << 5)
+#define STB0899_OFFST_DISEQC_DCURRENT          5
+#define STB0899_WIDTH_DISEQC_DCURRENT          1
+#define STB0899_DISEQC_ZCURRENT                        (0x01 << 4)
+#define STB0899_OFFST_DISEQC_ZCURRENT          4
+#define STB0899_WIDTH_DISEQC_ZCURRENT          1
+#define STB0899_DISEQC_SINC_SOURCE             (0x03 << 2)
+#define STB0899_OFFST_DISEQC_SINC_SOURCE       2
+#define STB0899_WIDTH_DISEQC_SINC_SOURCE       2
+#define STB0899_SELIQSRC                       (0x03 << 0)
+#define STB0899_OFFST_SELIQSRC                 0
+#define STB0899_WIDTH_SELIQSRC                 2
+
+#define STB0899_TSTTNR3                                0xf1e2
+
+#define STB0899_I2CCFG                         0xf129
+#define STB0899_I2CCFGRSVD                     (0x0f << 4)
+#define STB0899_OFFST_I2CCFGRSVD               4
+#define STB0899_WIDTH_I2CCFGRSVD               4
+#define STB0899_I2CFASTMODE                    (0x01 << 3)
+#define STB0899_OFFST_I2CFASTMODE              3
+#define STB0899_WIDTH_I2CFASTMODE              1
+#define STB0899_STATUSWR                       (0x01 << 2)
+#define STB0899_OFFST_STATUSWR                 2
+#define STB0899_WIDTH_STATUSWR                 1
+#define STB0899_I2CADDRINC                     (0x03 << 0)
+#define STB0899_OFFST_I2CADDRINC               0
+#define STB0899_WIDTH_I2CADDRINC               2
+
+#define STB0899_I2CRPT                         0xf12a
+#define STB0899_I2CTON                         (0x01 << 7)
+#define STB0899_OFFST_I2CTON                   7
+#define STB0899_WIDTH_I2CTON                   1
+#define STB0899_ENARPTLEVEL                    (0x01 << 6)
+#define STB0899_OFFST_ENARPTLEVEL              6
+#define STB0899_WIDTH_ENARPTLEVEL              2
+#define STB0899_SCLTDELAY                      (0x01 << 3)
+#define STB0899_OFFST_SCLTDELAY                        3
+#define STB0899_WIDTH_SCLTDELAY                        1
+#define STB0899_STOPENA                                (0x01 << 2)
+#define STB0899_OFFST_STOPENA                  2
+#define STB0899_WIDTH_STOPENA                  1
+#define STB0899_STOPSDAT2SDA                   (0x01 << 1)
+#define STB0899_OFFST_STOPSDAT2SDA             1
+#define STB0899_WIDTH_STOPSDAT2SDA             1
+
+#define STB0899_IOPVALUE8                      0xf136
+#define STB0899_IOPVALUE7                      0xf137
+#define STB0899_IOPVALUE6                      0xf138
+#define STB0899_IOPVALUE5                      0xf139
+#define STB0899_IOPVALUE4                      0xf13a
+#define STB0899_IOPVALUE3                      0xf13b
+#define STB0899_IOPVALUE2                      0xf13c
+#define STB0899_IOPVALUE1                      0xf13d
+#define STB0899_IOPVALUE0                      0xf13e
+
+#define STB0899_GPIO00CFG                      0xf140
+
+#define STB0899_GPIO01CFG                      0xf141
+#define STB0899_GPIO02CFG                      0xf142
+#define STB0899_GPIO03CFG                      0xf143
+#define STB0899_GPIO04CFG                      0xf144
+#define STB0899_GPIO05CFG                      0xf145
+#define STB0899_GPIO06CFG                      0xf146
+#define STB0899_GPIO07CFG                      0xf147
+#define STB0899_GPIO08CFG                      0xf148
+#define STB0899_GPIO09CFG                      0xf149
+#define STB0899_GPIO10CFG                      0xf14a
+#define STB0899_GPIO11CFG                      0xf14b
+#define STB0899_GPIO12CFG                      0xf14c
+#define STB0899_GPIO13CFG                      0xf14d
+#define STB0899_GPIO14CFG                      0xf14e
+#define STB0899_GPIO15CFG                      0xf14f
+#define STB0899_GPIO16CFG                      0xf150
+#define STB0899_GPIO17CFG                      0xf151
+#define STB0899_GPIO18CFG                      0xf152
+#define STB0899_GPIO19CFG                      0xf153
+#define STB0899_GPIO20CFG                      0xf154
+
+#define STB0899_SDATCFG                                0xf155
+#define STB0899_SCLTCFG                                0xf156
+#define STB0899_AGCRFCFG                       0xf157
+#define STB0899_GPIO22                         0xf158  /* AGCBB2CFG    */
+#define STB0899_GPIO21                         0xf159  /* AGCBB1CFG    */
+#define STB0899_DIRCLKCFG                      0xf15a
+#define STB0899_CLKOUT27CFG                    0xf15b
+#define STB0899_STDBYCFG                       0xf15c
+#define STB0899_CS0CFG                         0xf15d
+#define STB0899_CS1CFG                         0xf15e
+#define STB0899_DISEQCOCFG                     0xf15f
+
+#define STB0899_GPIO32CFG                      0xf160
+#define STB0899_GPIO33CFG                      0xf161
+#define STB0899_GPIO34CFG                      0xf162
+#define STB0899_GPIO35CFG                      0xf163
+#define STB0899_GPIO36CFG                      0xf164
+#define STB0899_GPIO37CFG                      0xf165
+#define STB0899_GPIO38CFG                      0xf166
+#define STB0899_GPIO39CFG                      0xf167
+
+#define STB0899_IRQSTATUS_3                    0xf120
+#define STB0899_IRQSTATUS_2                    0xf121
+#define STB0899_IRQSTATUS_1                    0xf122
+#define STB0899_IRQSTATUS_0                    0xf123
+
+#define STB0899_IRQMSK_3                       0xf124
+#define STB0899_IRQMSK_2                       0xf125
+#define STB0899_IRQMSK_1                       0xf126
+#define STB0899_IRQMSK_0                       0xf127
+
+#define STB0899_IRQCFG                         0xf128
+
+#define STB0899_GHOSTREG                       0xf000
+
+#define STB0899_S2DEMOD                                0xf3fc
+#define STB0899_S2FEC                          0xfafc
+
+
+#endif
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
new file mode 100644 (file)
index 0000000..ff39275
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+       STB6100 Silicon Tuner
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+#include "stb6100.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+
+
+#define FE_ERROR               0
+#define FE_NOTICE              1
+#define FE_INFO                        2
+#define FE_DEBUG               3
+
+#define dprintk(x, y, z, format, arg...) do {                                          \
+       if (z) {                                                                        \
+               if      ((x > FE_ERROR) && (x > y))                                     \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((x > FE_NOTICE) && (x > y))                                    \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((x > FE_INFO) && (x > y))                                      \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((x > FE_DEBUG) && (x > y))                                     \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (x > y)                                                              \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while(0)
+
+struct stb6100_lkup {
+       u32 val_low;
+       u32 val_high;
+       u8   reg;
+};
+
+static int stb6100_release(struct dvb_frontend *fe);
+
+static const struct stb6100_lkup lkup[] = {
+       {       0,  950000, 0x0a },
+       {  950000, 1000000, 0x0a },
+       { 1000000, 1075000, 0x0c },
+       { 1075000, 1200000, 0x00 },
+       { 1200000, 1300000, 0x01 },
+       { 1300000, 1370000, 0x02 },
+       { 1370000, 1470000, 0x04 },
+       { 1470000, 1530000, 0x05 },
+       { 1530000, 1650000, 0x06 },
+       { 1650000, 1800000, 0x08 },
+       { 1800000, 1950000, 0x0a },
+       { 1950000, 2150000, 0x0c },
+       { 2150000, 9999999, 0x0c },
+       {       0,       0, 0x00 }
+};
+
+/* Register names for easy debugging.  */
+static const char *stb6100_regnames[] = {
+       [STB6100_LD]            = "LD",
+       [STB6100_VCO]           = "VCO",
+       [STB6100_NI]            = "NI",
+       [STB6100_NF_LSB]        = "NF",
+       [STB6100_K]             = "K",
+       [STB6100_G]             = "G",
+       [STB6100_F]             = "F",
+       [STB6100_DLB]           = "DLB",
+       [STB6100_TEST1]         = "TEST1",
+       [STB6100_FCCK]          = "FCCK",
+       [STB6100_LPEN]          = "LPEN",
+       [STB6100_TEST3]         = "TEST3",
+};
+
+/* Template for normalisation, i.e. setting unused or undocumented
+ * bits as required according to the documentation.
+ */
+struct stb6100_regmask {
+       u8 mask;
+       u8 set;
+};
+
+static const struct stb6100_regmask stb6100_template[] = {
+       [STB6100_LD]            = { 0xff, 0x00 },
+       [STB6100_VCO]           = { 0xff, 0x00 },
+       [STB6100_NI]            = { 0xff, 0x00 },
+       [STB6100_NF_LSB]        = { 0xff, 0x00 },
+       [STB6100_K]             = { 0xc7, 0x38 },
+       [STB6100_G]             = { 0xef, 0x10 },
+       [STB6100_F]             = { 0x1f, 0xc0 },
+       [STB6100_DLB]           = { 0x38, 0xc4 },
+       [STB6100_TEST1]         = { 0x00, 0x8f },
+       [STB6100_FCCK]          = { 0x40, 0x0d },
+       [STB6100_LPEN]          = { 0xf0, 0x0b },
+       [STB6100_TEST3]         = { 0x00, 0xde },
+};
+
+static void stb6100_normalise_regs(u8 regs[])
+{
+       int i;
+
+       for (i = 0; i < STB6100_NUMREGS; i++)
+               regs[i] = (regs[i] & stb6100_template[i].mask) | stb6100_template[i].set;
+}
+
+static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
+{
+       int rc;
+       struct i2c_msg msg = {
+               .addr   = state->config->tuner_address,
+               .flags  = I2C_M_RD,
+               .buf    = regs,
+               .len    = STB6100_NUMREGS
+       };
+
+       rc = i2c_transfer(state->i2c, &msg, 1);
+       if (unlikely(rc != 1)) {
+               dprintk(verbose, FE_ERROR, 1, "Read (0x%x) err, rc=[%d]",
+                       state->config->tuner_address, rc);
+
+               return -EREMOTEIO;
+       }
+       if (unlikely(verbose > FE_DEBUG)) {
+               int i;
+
+               dprintk(verbose, FE_DEBUG, 1, "    Read from 0x%02x", state->config->tuner_address);
+               for (i = 0; i < STB6100_NUMREGS; i++)
+                       dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[i], regs[i]);
+       }
+       return 0;
+}
+
+static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
+{
+       u8 regs[STB6100_NUMREGS];
+       int rc;
+
+       if (unlikely(reg >= STB6100_NUMREGS)) {
+               dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
+               return -EINVAL;
+       }
+       if ((rc = stb6100_read_regs(state, regs)) < 0)
+               return rc;
+       return (unsigned int)regs[reg];
+}
+
+static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
+{
+       int rc;
+       u8 cmdbuf[len + 1];
+       struct i2c_msg msg = {
+               .addr   = state->config->tuner_address,
+               .flags  = 0,
+               .buf    = cmdbuf,
+               .len    = len + 1
+       };
+
+       if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) {
+               dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d",
+                       start, len);
+               return -EINVAL;
+       }
+       memcpy(&cmdbuf[1], buf, len);
+       cmdbuf[0] = start;
+
+       if (unlikely(verbose > FE_DEBUG)) {
+               int i;
+
+               dprintk(verbose, FE_DEBUG, 1, "    Write @ 0x%02x: [%d:%d]", state->config->tuner_address, start, len);
+               for (i = 0; i < len; i++)
+                       dprintk(verbose, FE_DEBUG, 1, "        %s: 0x%02x", stb6100_regnames[start + i], buf[i]);
+       }
+       rc = i2c_transfer(state->i2c, &msg, 1);
+       if (unlikely(rc != 1)) {
+               dprintk(verbose, FE_ERROR, 1, "(0x%x) write err [%d:%d], rc=[%d]",
+                       (unsigned int)state->config->tuner_address, start, len, rc);
+               return -EREMOTEIO;
+       }
+       return 0;
+}
+
+static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
+{
+       if (unlikely(reg >= STB6100_NUMREGS)) {
+               dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
+               return -EREMOTEIO;
+       }
+       data = (data & stb6100_template[reg].mask) | stb6100_template[reg].set;
+       return stb6100_write_reg_range(state, &data, reg, 1);
+}
+
+static int stb6100_write_regs(struct stb6100_state *state, u8 regs[])
+{
+       stb6100_normalise_regs(regs);
+       return stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 1);
+}
+
+static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       int rc;
+       struct stb6100_state *state = fe->tuner_priv;
+
+       if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0)
+               return rc;
+
+       return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
+}
+
+static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       int rc;
+       u8 f;
+       struct stb6100_state *state = fe->tuner_priv;
+
+       if ((rc = stb6100_read_reg(state, STB6100_F)) < 0)
+               return rc;
+       f = rc & STB6100_F_F;
+
+       state->status.bandwidth = (f + 5) * 2000;       /* x2 for ZIF   */
+
+       *bandwidth = state->bandwidth = state->status.bandwidth * 1000;
+       dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
+       return 0;
+}
+
+static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+       u32 tmp;
+       int rc;
+       struct stb6100_state *state = fe->tuner_priv;
+
+       dprintk(verbose, FE_DEBUG, 1, "set bandwidth to %u Hz", bandwidth);
+
+       bandwidth /= 2; /* ZIF */
+
+       if (bandwidth >= 36000000)      /* F[4:0] BW/2 max =31+5=36 mhz for F=31        */
+               tmp = 31;
+       else if (bandwidth <= 5000000)  /* bw/2 min = 5Mhz for F=0                      */
+               tmp = 0;
+       else                            /* if 5 < bw/2 < 36                             */
+               tmp = (bandwidth + 500000) / 1000000 - 5;
+
+       /* Turn on LPF bandwidth setting clock control,
+        * set bandwidth, wait 10ms, turn off.
+        */
+       if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0)
+               return rc;
+       if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0)
+               return rc;
+       msleep(1);
+       if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0)
+               return rc;
+
+       return 0;
+}
+
+static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       int rc;
+       u32 nint, nfrac, fvco;
+       int psd2, odiv;
+       struct stb6100_state *state = fe->tuner_priv;
+       u8 regs[STB6100_NUMREGS];
+
+       if ((rc = stb6100_read_regs(state, regs)) < 0)
+               return rc;
+
+       odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
+       psd2 = (regs[STB6100_K] & STB6100_K_PSD2) >> STB6100_K_PSD2_SHIFT;
+       nint = regs[STB6100_NI];
+       nfrac = ((regs[STB6100_K] & STB6100_K_NF_MSB) << 8) | regs[STB6100_NF_LSB];
+       fvco = (nfrac * state->reference >> (9 - psd2)) + (nint * state->reference << psd2);
+       *frequency = state->frequency = fvco >> (odiv + 1);
+
+       dprintk(verbose, FE_DEBUG, 1,
+               "frequency = %u kHz, odiv = %u, psd2 = %u, fxtal = %u kHz, fvco = %u kHz, N(I) = %u, N(F) = %u",
+               state->frequency, odiv, psd2, state->reference, fvco, nint, nfrac);
+       return 0;
+}
+
+
+static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+       int rc;
+       const struct stb6100_lkup *ptr;
+       struct stb6100_state *state = fe->tuner_priv;
+       struct dvb_frontend_parameters p;
+
+       u32 srate = 0, fvco, nint, nfrac;
+       u8 regs[STB6100_NUMREGS];
+       u8 g, psd2, odiv;
+
+       if ((rc = stb6100_read_regs(state, regs)) < 0)
+               return rc;
+
+       if (fe->ops.get_frontend) {
+               dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
+               fe->ops.get_frontend(fe, &p);
+       }
+       srate = p.u.qpsk.symbol_rate;
+
+       regs[STB6100_DLB] = 0xdc;
+       /* Disable LPEN */
+       regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */
+
+       if ((rc = stb6100_write_regs(state, regs)) < 0)
+               return rc;
+
+       /* Baseband gain.       */
+       if (srate >= 15000000)
+               g = 9;  //  +4 dB
+       else if (srate >= 5000000)
+               g = 11; //  +8 dB
+       else
+               g = 14; // +14 dB
+
+       regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g;
+       regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
+       regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
+
+       /* VCO divide ratio (LO divide ratio, VCO prescaler enable).    */
+       if (frequency <= 1075000)
+               odiv = 1;
+       else
+               odiv = 0;
+       regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT);
+
+       if ((frequency > 1075000) && (frequency <= 1325000))
+               psd2 = 0;
+       else
+               psd2 = 1;
+       regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
+
+       /* OSM  */
+       for (ptr = lkup;
+            (ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
+            ptr++);
+       if (ptr->val_high == 0) {
+               printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
+               return -EINVAL;
+       }
+       regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
+
+       /* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4)                 */
+       fvco = frequency << (1 + odiv);
+       /* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1)))    */
+       nint = fvco / (state->reference << psd2);
+       /* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9       */
+       nfrac = (((fvco - (nint * state->reference << psd2)) << (9 - psd2)) + state->reference / 2) / state->reference;
+       dprintk(verbose, FE_DEBUG, 1,
+               "frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
+               frequency, srate, (unsigned int)g, (unsigned int)odiv,
+               (unsigned int)psd2, state->reference,
+               ptr->reg, fvco, nint, nfrac);
+       regs[STB6100_NI] = nint;
+       regs[STB6100_NF_LSB] = nfrac;
+       regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
+       regs[STB6100_VCO] |= STB6100_VCO_OSCH;          /* VCO search enabled           */
+       regs[STB6100_VCO] |= STB6100_VCO_OCK;           /* VCO search clock off         */
+       regs[STB6100_FCCK] |= STB6100_FCCK_FCCK;        /* LPF BW setting clock enabled */
+       regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN;       /* PLL loop disabled            */
+       /* Power up. */
+       regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN;
+
+       msleep(2);
+       if ((rc = stb6100_write_regs(state, regs)) < 0)
+               return rc;
+
+       msleep(2);
+       regs[STB6100_LPEN] |= STB6100_LPEN_LPEN;        /* PLL loop enabled             */
+       if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0)
+               return rc;
+
+       regs[STB6100_VCO] &= ~STB6100_VCO_OCK;          /* VCO fast search              */
+       if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
+               return rc;
+
+       msleep(10);                                     /* wait for LO to lock          */
+       regs[STB6100_VCO] &= ~STB6100_VCO_OSCH;         /* vco search disabled          */
+       regs[STB6100_VCO] |= STB6100_VCO_OCK;           /* search clock off             */
+       if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
+               return rc;
+       regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK;       /* LPF BW clock disabled        */
+       stb6100_normalise_regs(regs);
+       if ((rc = stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 3)) < 0)
+               return rc;
+
+       msleep(100);
+
+       return 0;
+}
+
+static int stb6100_sleep(struct dvb_frontend *fe)
+{
+       /* TODO: power down     */
+       return 0;
+}
+
+static int stb6100_init(struct dvb_frontend *fe)
+{
+       struct stb6100_state *state = fe->tuner_priv;
+       struct tuner_state *status = &state->status;
+
+       status->tunerstep       = 125000;
+       status->ifreq           = 0;
+       status->refclock        = 27000000;     /* Hz   */
+       status->iqsense         = 1;
+       status->bandwidth       = 36000;        /* kHz  */
+       state->bandwidth        = status->bandwidth * 1000;     /* MHz  */
+       state->reference        = status->refclock / 1000;      /* kHz  */
+
+       /* Set default bandwidth.       */
+       return stb6100_set_bandwidth(fe, status->bandwidth);
+}
+
+static int stb6100_get_state(struct dvb_frontend *fe,
+                            enum tuner_param param,
+                            struct tuner_state *state)
+{
+       switch (param) {
+       case DVBFE_TUNER_FREQUENCY:
+               stb6100_get_frequency(fe, &state->frequency);
+               break;
+       case DVBFE_TUNER_TUNERSTEP:
+               break;
+       case DVBFE_TUNER_IFFREQ:
+               break;
+       case DVBFE_TUNER_BANDWIDTH:
+               stb6100_get_bandwidth(fe, &state->bandwidth);
+               break;
+       case DVBFE_TUNER_REFCLOCK:
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int stb6100_set_state(struct dvb_frontend *fe,
+                            enum tuner_param param,
+                            struct tuner_state *state)
+{
+       struct stb6100_state *tstate = fe->tuner_priv;
+
+       switch (param) {
+       case DVBFE_TUNER_FREQUENCY:
+               stb6100_set_frequency(fe, state->frequency);
+               tstate->frequency = state->frequency;
+               break;
+       case DVBFE_TUNER_TUNERSTEP:
+               break;
+       case DVBFE_TUNER_IFFREQ:
+               break;
+       case DVBFE_TUNER_BANDWIDTH:
+               stb6100_set_bandwidth(fe, state->bandwidth);
+               tstate->bandwidth = state->bandwidth;
+               break;
+       case DVBFE_TUNER_REFCLOCK:
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static struct dvb_tuner_ops stb6100_ops = {
+       .info = {
+               .name                   = "STB6100 Silicon Tuner",
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_step         = 0,
+       },
+
+       .init           = stb6100_init,
+       .sleep          = stb6100_sleep,
+       .get_status     = stb6100_get_status,
+       .get_state      = stb6100_get_state,
+       .set_state      = stb6100_set_state,
+       .release        = stb6100_release
+};
+
+struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
+                                   struct stb6100_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct stb6100_state *state = NULL;
+
+       state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->config           = config;
+       state->i2c              = i2c;
+       state->frontend         = fe;
+       state->reference        = config->refclock / 1000; /* kHz */
+       fe->tuner_priv          = state;
+       fe->ops.tuner_ops       = stb6100_ops;
+
+       printk("%s: Attaching STB6100 \n", __func__);
+       return fe;
+
+error:
+       kfree(state);
+       return NULL;
+}
+
+static int stb6100_release(struct dvb_frontend *fe)
+{
+       struct stb6100_state *state = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(state);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(stb6100_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STB6100 Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stb6100.h b/drivers/media/dvb/frontends/stb6100.h
new file mode 100644 (file)
index 0000000..395d056
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+       STB6100 Silicon Tuner
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+#ifndef __STB_6100_REG_H
+#define __STB_6100_REG_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#define STB6100_LD                     0x00
+#define STB6100_LD_LOCK                        (1 << 0)
+
+#define STB6100_VCO                    0x01
+#define STB6100_VCO_OSCH               (0x01 << 7)
+#define STB6100_VCO_OSCH_SHIFT         7
+#define STB6100_VCO_OCK                        (0x03 << 5)
+#define STB6100_VCO_OCK_SHIFT          5
+#define STB6100_VCO_ODIV               (0x01 << 4)
+#define STB6100_VCO_ODIV_SHIFT         4
+#define STB6100_VCO_OSM                        (0x0f << 0)
+
+#define STB6100_NI                     0x02
+#define STB6100_NF_LSB                 0x03
+
+#define STB6100_K                      0x04
+#define STB6100_K_PSD2                 (0x01 << 2)
+#define STB6100_K_PSD2_SHIFT            2
+#define STB6100_K_NF_MSB               (0x03 << 0)
+
+#define STB6100_G                      0x05
+#define STB6100_G_G                    (0x0f << 0)
+#define STB6100_G_GCT                  (0x07 << 5)
+
+#define STB6100_F                      0x06
+#define STB6100_F_F                    (0x1f << 0)
+
+#define STB6100_DLB                    0x07
+
+#define STB6100_TEST1                  0x08
+
+#define STB6100_FCCK                   0x09
+#define STB6100_FCCK_FCCK              (0x01 << 6)
+
+#define STB6100_LPEN                   0x0a
+#define STB6100_LPEN_LPEN              (0x01 << 4)
+#define STB6100_LPEN_SYNP              (0x01 << 5)
+#define STB6100_LPEN_OSCP              (0x01 << 6)
+#define STB6100_LPEN_BEN               (0x01 << 7)
+
+#define STB6100_TEST3                  0x0b
+
+#define STB6100_NUMREGS                 0x0c
+
+
+#define INRANGE(val, x, y)             (((x <= val) && (val <= y)) ||          \
+                                        ((y <= val) && (val <= x)) ? 1 : 0)
+
+#define CHKRANGE(val, x, y)            (((val >= x) && (val < y)) ? 1 : 0)
+
+struct stb6100_config {
+       u8      tuner_address;
+       u32     refclock;
+};
+
+struct stb6100_state {
+       struct i2c_adapter *i2c;
+
+       const struct stb6100_config     *config;
+       struct dvb_tuner_ops            ops;
+       struct dvb_frontend             *frontend;
+       struct tuner_state              status;
+
+       u32 frequency;
+       u32 srate;
+       u32 bandwidth;
+       u32 reference;
+};
+
+#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
+                                          struct stb6100_config *config,
+                                          struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
+                                                 struct stb6100_config *config,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif //CONFIG_DVB_STB6100
+
+#endif
diff --git a/drivers/media/dvb/frontends/stb6100_cfg.h b/drivers/media/dvb/frontends/stb6100_cfg.h
new file mode 100644 (file)
index 0000000..d313340
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+       STB6100 Silicon Tuner
+       Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU 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.
+*/
+
+static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops    *tuner_ops = NULL;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->get_state) {
+               if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+               *frequency = t_state.frequency;
+               printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+       }
+       return 0;
+}
+
+static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops    *tuner_ops = NULL;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       t_state.frequency = frequency;
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->set_state) {
+               if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+       }
+       printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+       return 0;
+}
+
+static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct dvb_frontend_ops *frontend_ops = &fe->ops;
+       struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->get_state) {
+               if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+               *bandwidth = t_state.bandwidth;
+       }
+       printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
+       return 0;
+}
+
+static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops    *tuner_ops = NULL;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       t_state.bandwidth = bandwidth;
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->set_state) {
+               if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+       }
+       printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
+       return 0;
+}
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c
new file mode 100644 (file)
index 0000000..b6d1777
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+       TDA8261 8PSK/QPSK tuner driver
+       Copyright (C) Manu Abraham (abraham.manu@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.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "tda8261.h"
+
+struct tda8261_state {
+       struct dvb_frontend             *fe;
+       struct i2c_adapter              *i2c;
+       const struct tda8261_config     *config;
+
+       /* state cache */
+       u32 frequency;
+       u32 bandwidth;
+};
+
+static int tda8261_read(struct tda8261_state *state, u8 *buf)
+{
+       const struct tda8261_config *config = state->config;
+       int err = 0;
+       struct i2c_msg msg = { .addr    = config->addr, .flags = I2C_M_RD,.buf = buf,  .len = 2 };
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
+               printk("%s: read error, err=%d\n", __func__, err);
+
+       return err;
+}
+
+static int tda8261_write(struct tda8261_state *state, u8 *buf)
+{
+       const struct tda8261_config *config = state->config;
+       int err = 0;
+       struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = 4 };
+
+       if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1)
+               printk("%s: write error, err=%d\n", __func__, err);
+
+       return err;
+}
+
+static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct tda8261_state *state = fe->tuner_priv;
+       u8 result = 0;
+       int err = 0;
+
+       *status = 0;
+
+       if ((err = tda8261_read(state, &result)) < 0) {
+               printk("%s: I/O Error\n", __func__);
+               return err;
+       }
+       if ((result >> 6) & 0x01) {
+               printk("%s: Tuner Phase Locked\n", __func__);
+               *status = 1;
+       }
+
+       return err;
+}
+
+static const u32 div_tab[] = { 2000, 1000,  500,  250,  125 }; /* kHz */
+static const u8  ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
+
+static int tda8261_get_state(struct dvb_frontend *fe,
+                            enum tuner_param param,
+                            struct tuner_state *tstate)
+{
+       struct tda8261_state *state = fe->tuner_priv;
+       int err = 0;
+
+       switch (param) {
+       case DVBFE_TUNER_FREQUENCY:
+               tstate->frequency = state->frequency;
+               break;
+       case DVBFE_TUNER_BANDWIDTH:
+               tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
+               break;
+       default:
+               printk("%s: Unknown parameter (param=%d)\n", __func__, param);
+               err = -EINVAL;
+               break;
+       }
+
+       return err;
+}
+
+static int tda8261_set_state(struct dvb_frontend *fe,
+                            enum tuner_param param,
+                            struct tuner_state *tstate)
+{
+       struct tda8261_state *state = fe->tuner_priv;
+       const struct tda8261_config *config = state->config;
+       u32 frequency, N, status = 0;
+       u8 buf[4];
+       int err = 0;
+
+       if (param & DVBFE_TUNER_FREQUENCY) {
+               /**
+                * N = Max VCO Frequency / Channel Spacing
+                * Max VCO Frequency = VCO frequency + (channel spacing - 1)
+                * (to account for half channel spacing on either side)
+                */
+               frequency = tstate->frequency;
+               if ((frequency < 950000) || (frequency > 2150000)) {
+                       printk("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+                       return -EINVAL;
+               }
+               N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
+               printk("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
+                       __func__, config->step_size, div_tab[config->step_size], N, N);
+
+               buf[0] = (N >> 8) & 0xff;
+               buf[1] = N & 0xff;
+               buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
+
+               if (frequency < 1450000)
+                       buf[3] = 0x00;
+               if (frequency < 2000000)
+                       buf[3] = 0x40;
+               if (frequency < 2150000)
+                       buf[3] = 0x80;
+
+               /* Set params */
+               if ((err = tda8261_write(state, buf)) < 0) {
+                       printk("%s: I/O Error\n", __func__);
+                       return err;
+               }
+               /* sleep for some time */
+               printk("%s: Waiting to Phase LOCK\n", __func__);
+               msleep(20);
+               /* check status */
+               if ((err = tda8261_get_status(fe, &status)) < 0) {
+                       printk("%s: I/O Error\n", __func__);
+                       return err;
+               }
+               if (status == 1) {
+                       printk("%s: Tuner Phase locked: status=%d\n", __func__, status);
+                       state->frequency = frequency; /* cache successful state */
+               } else {
+                       printk("%s: No Phase lock: status=%d\n", __func__, status);
+               }
+       } else {
+               printk("%s: Unknown parameter (param=%d)\n", __func__, param);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tda8261_release(struct dvb_frontend *fe)
+{
+       struct tda8261_state *state = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(state);
+       return 0;
+}
+
+static struct dvb_tuner_ops tda8261_ops = {
+
+       .info = {
+               .name           = "TDA8261",
+//             .tuner_name     = NULL,
+               .frequency_min  =  950000,
+               .frequency_max  = 2150000,
+               .frequency_step = 0
+       },
+
+       .set_state      = tda8261_set_state,
+       .get_state      = tda8261_get_state,
+       .get_status     = tda8261_get_status,
+       .release        = tda8261_release
+};
+
+struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
+                                   const struct tda8261_config *config,
+                                   struct i2c_adapter *i2c)
+{
+       struct tda8261_state *state = NULL;
+
+       if ((state = kzalloc(sizeof (struct tda8261_state), GFP_KERNEL)) == NULL)
+               goto exit;
+
+       state->config           = config;
+       state->i2c              = i2c;
+       state->fe               = fe;
+       fe->tuner_priv          = state;
+       fe->ops.tuner_ops       = tda8261_ops;
+
+       fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
+//     fe->ops.tuner_ops.tuner_name     = &config->buf;
+
+//     printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
+//             __func__, fe->ops.tuner_ops.tuner_name);
+       printk("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
+
+       return fe;
+
+exit:
+       kfree(state);
+       return NULL;
+}
+
+EXPORT_SYMBOL(tda8261_attach);
+MODULE_PARM_DESC(verbose, "Set verbosity level");
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda8261.h b/drivers/media/dvb/frontends/tda8261.h
new file mode 100644 (file)
index 0000000..006e453
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+       TDA8261 8PSK/QPSK tuner driver
+       Copyright (C) Manu Abraham (abraham.manu@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.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You 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 __TDA8261_H
+#define __TDA8261_H
+
+enum tda8261_step {
+       TDA8261_STEP_2000 = 0,  /* 2000 kHz */
+       TDA8261_STEP_1000,      /* 1000 kHz */
+       TDA8261_STEP_500,       /*  500 kHz */
+       TDA8261_STEP_250,       /*  250 kHz */
+       TDA8261_STEP_125        /*  125 kHz */
+};
+
+struct tda8261_config {
+//     u8                      buf[16];
+       u8                      addr;
+       enum tda8261_step       step_size;
+};
+
+#if defined(CONFIG_DVB_TDA8261) || (defined(CONFIG_DVB_TDA8261_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
+                                          const struct tda8261_config *config,
+                                          struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
+                                                 const struct tda8261_config *config,
+                                                 struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif //CONFIG_DVB_TDA8261
+
+#endif// __TDA8261_H
diff --git a/drivers/media/dvb/frontends/tda8261_cfg.h b/drivers/media/dvb/frontends/tda8261_cfg.h
new file mode 100644 (file)
index 0000000..1af1ee4
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+       TDA8261 8PSK/QPSK tuner driver
+       Copyright (C) Manu Abraham (abraham.manu@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.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You 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.
+*/
+
+static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops    *tuner_ops = NULL;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->get_state) {
+               if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+               *frequency = t_state.frequency;
+               printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+       }
+       return 0;
+}
+
+static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+       struct dvb_frontend_ops *frontend_ops = NULL;
+       struct dvb_tuner_ops    *tuner_ops = NULL;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       t_state.frequency = frequency;
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->set_state) {
+               if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+       }
+       printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+       return 0;
+}
+
+static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct dvb_frontend_ops *frontend_ops = &fe->ops;
+       struct dvb_tuner_ops    *tuner_ops = &frontend_ops->tuner_ops;
+       struct tuner_state      t_state;
+       int err = 0;
+
+       if (&fe->ops)
+               frontend_ops = &fe->ops;
+       if (&frontend_ops->tuner_ops)
+               tuner_ops = &frontend_ops->tuner_ops;
+       if (tuner_ops->get_state) {
+               if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+                       printk("%s: Invalid parameter\n", __func__);
+                       return err;
+               }
+               *bandwidth = t_state.bandwidth;
+       }
+       printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
+       return 0;
+}
index 36a5a1c101d5b91386a23796959857cabcd632df..5506f80e180eeddd8c7bf575b963ea280abd3a94 100644 (file)
@@ -220,15 +220,18 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
                /* These are extrapolated from the 7 and 8MHz values */
                zl10353_single_write(fe, MCLK_RATIO, 0x97);
                zl10353_single_write(fe, 0x64, 0x34);
+               zl10353_single_write(fe, 0xcc, 0xdd);
                break;
        case BANDWIDTH_7_MHZ:
                zl10353_single_write(fe, MCLK_RATIO, 0x86);
                zl10353_single_write(fe, 0x64, 0x35);
+               zl10353_single_write(fe, 0xcc, 0x73);
                break;
        case BANDWIDTH_8_MHZ:
        default:
                zl10353_single_write(fe, MCLK_RATIO, 0x75);
                zl10353_single_write(fe, 0x64, 0x36);
+               zl10353_single_write(fe, 0xcc, 0x73);
        }
 
        zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
index e98d6caf2c233843bad9018842bd87d64cb2170b..fd62e0b856213d15029262c293f05a63cb1a9ee7 100644 (file)
@@ -38,6 +38,16 @@ struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
        { USB_DEVICE(0x2040, 0x1801),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+       { USB_DEVICE(0x2040, 0x2000),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2009),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
+       { USB_DEVICE(0x2040, 0x200a),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2010),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
+       { USB_DEVICE(0x2040, 0x2019),
+               .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
        { USB_DEVICE(0x2040, 0x5500),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
        { USB_DEVICE(0x2040, 0x5510),
@@ -96,6 +106,21 @@ static struct sms_board sms_boards[] = {
                .name   = "Hauppauge WinTV MiniStick",
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .led_power = 26,
+               .led_lo    = 27,
+               .led_hi    = 28,
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
+               .name   = "Hauppauge WinTV MiniCard",
+               .type   = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .lna_ctrl  = 29,
+       },
+       [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
+               .name   = "Hauppauge WinTV MiniCard",
+               .type   = SMS_NOVA_B0,
+               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .lna_ctrl  = 1,
        },
 };
 
@@ -106,3 +131,88 @@ struct sms_board *sms_get_board(int id)
        return &sms_boards[id];
 }
 
+static int sms_set_gpio(struct smscore_device_t *coredev, u32 pin, int enable)
+{
+       int ret;
+       struct smscore_gpio_config gpioconfig = {
+               .direction            = SMS_GPIO_DIRECTION_OUTPUT,
+               .pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
+               .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
+               .outputslewrate       = SMS_GPIO_OUTPUTSLEWRATE_FAST,
+               .outputdriving        = SMS_GPIO_OUTPUTDRIVING_4mA,
+       };
+
+       if (pin == 0)
+               return -EINVAL;
+
+       ret = smscore_configure_gpio(coredev, pin, &gpioconfig);
+
+       if (ret < 0)
+               return ret;
+
+       return smscore_set_gpio(coredev, pin, enable);
+}
+
+int sms_board_setup(struct smscore_device_t *coredev)
+{
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+
+       switch (board_id) {
+       case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+               /* turn off all LEDs */
+               sms_set_gpio(coredev, board->led_power, 0);
+               sms_set_gpio(coredev, board->led_hi, 0);
+               sms_set_gpio(coredev, board->led_lo, 0);
+               break;
+       case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+       case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+               /* turn off LNA */
+               sms_set_gpio(coredev, board->lna_ctrl, 0);
+               break;
+       }
+       return 0;
+}
+
+int sms_board_power(struct smscore_device_t *coredev, int onoff)
+{
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+
+       switch (board_id) {
+       case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+               /* power LED */
+               sms_set_gpio(coredev,
+                            board->led_power, onoff ? 1 : 0);
+               break;
+       case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+       case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+               /* LNA */
+               sms_set_gpio(coredev,
+                            board->lna_ctrl, onoff ? 1 : 0);
+               break;
+       }
+       return 0;
+}
+
+int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
+{
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+
+       /* dont touch GPIO if LEDs are already set */
+       if (smscore_led_state(coredev, -1) == led)
+               return 0;
+
+       switch (board_id) {
+       case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+               sms_set_gpio(coredev,
+                            board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
+               sms_set_gpio(coredev,
+                            board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
+
+               smscore_led_state(coredev, led);
+               break;
+       }
+       return 0;
+}
index c8f3da6f9bc1021b60b2db3469a71989b6ab1415..8e0fe9fd261011bafc91e1d265b99797aab6cef0 100644 (file)
 #define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
 #define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
+#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
 
 struct sms_board {
        enum sms_device_type_st type;
        char *name, *fw[DEVICE_MODE_MAX];
+
+       /* gpios */
+       int led_power, led_hi, led_lo, lna_ctrl;
 };
 
 struct sms_board *sms_get_board(int id);
 
+int sms_board_setup(struct smscore_device_t *coredev);
+
+#define SMS_LED_OFF 0
+#define SMS_LED_LO  1
+#define SMS_LED_HI  2
+int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
+int sms_board_power(struct smscore_device_t *coredev, int onoff);
+
 extern struct usb_device_id smsusb_id_table[];
 
 #endif /* __SMS_CARDS_H__ */
index 6576fbb40fc67eb8fcfce1205873f0051ce68fd7..cf613f22fb8d84e68203f7de9f7bed5c3b997978 100644 (file)
@@ -91,6 +91,7 @@ struct smscore_device_t {
        struct completion init_device_done, reload_start_done, resume_done;
 
        int board_id;
+       int led_state;
 };
 
 void smscore_set_board_id(struct smscore_device_t *core, int id)
@@ -98,6 +99,13 @@ void smscore_set_board_id(struct smscore_device_t *core, int id)
        core->board_id = id;
 }
 
+int smscore_led_state(struct smscore_device_t *core, int led)
+{
+       if (led >= 0)
+               core->led_state = led;
+       return core->led_state;
+}
+
 int smscore_get_board_id(struct smscore_device_t *core)
 {
        return core->board_id;
@@ -1187,6 +1195,76 @@ int smsclient_sendrequest(struct smscore_client_t *client,
 }
 
 
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+                          struct smscore_gpio_config *pinconfig)
+{
+       struct {
+               struct SmsMsgHdr_ST hdr;
+               u32 data[6];
+       } msg;
+
+       if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+               msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+               msg.hdr.msgDstId = HIF_TASK;
+               msg.hdr.msgFlags = 0;
+               msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
+               msg.hdr.msgLength = sizeof(msg);
+
+               msg.data[0] = pin;
+               msg.data[1] = pinconfig->pullupdown;
+
+               /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
+               msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
+
+               switch (pinconfig->outputdriving) {
+               case SMS_GPIO_OUTPUTDRIVING_16mA:
+                       msg.data[3] = 7; /* Nova - 16mA */
+                       break;
+               case SMS_GPIO_OUTPUTDRIVING_12mA:
+                       msg.data[3] = 5; /* Nova - 11mA */
+                       break;
+               case SMS_GPIO_OUTPUTDRIVING_8mA:
+                       msg.data[3] = 3; /* Nova - 7mA */
+                       break;
+               case SMS_GPIO_OUTPUTDRIVING_4mA:
+               default:
+                       msg.data[3] = 2; /* Nova - 4mA */
+                       break;
+               }
+
+               msg.data[4] = pinconfig->direction;
+               msg.data[5] = 0;
+       } else /* TODO: SMS_DEVICE_FAMILY1 */
+               return -EINVAL;
+
+       return coredev->sendrequest_handler(coredev->context,
+                                           &msg, sizeof(msg));
+}
+
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
+{
+       struct {
+               struct SmsMsgHdr_ST hdr;
+               u32 data[3];
+       } msg;
+
+       if (pin > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       msg.hdr.msgDstId = HIF_TASK;
+       msg.hdr.msgFlags = 0;
+       msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
+       msg.hdr.msgLength = sizeof(msg);
+
+       msg.data[0] = pin;
+       msg.data[1] = level ? 1 : 0;
+       msg.data[2] = 0;
+
+       return coredev->sendrequest_handler(coredev->context,
+                                           &msg, sizeof(msg));
+}
+
 static int __init smscore_module_init(void)
 {
        int rc = 0;
index 8d973f726fb835c565b30a827828372d8e4eeedc..760e233fcbc587594d965479a7ee35de64760c0e 100644 (file)
@@ -186,6 +186,8 @@ struct smsclient_params_t {
 #define MSG_SW_RELOAD_EXEC_REQ                         704
 #define MSG_SW_RELOAD_EXEC_RES                         705
 #define MSG_SMS_SPI_INT_LINE_SET_REQ           710
+#define MSG_SMS_GPIO_CONFIG_EX_REQ                     712
+#define MSG_SMS_GPIO_CONFIG_EX_RES                     713
 #define MSG_SMS_ISDBT_TUNE_REQ                         776
 #define MSG_SMS_ISDBT_TUNE_RES                         777
 
@@ -341,6 +343,32 @@ struct SmsMsgStatisticsInfo_ST {
 };
 
 
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+       u8 direction;
+
+#define SMS_GPIO_PULLUPDOWN_NONE     0
+#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
+#define SMS_GPIO_PULLUPDOWN_PULLUP   2
+#define SMS_GPIO_PULLUPDOWN_KEEPER   3
+       u8 pullupdown;
+
+#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
+       u8 inputcharacteristics;
+
+#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
+#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
+       u8 outputslewrate;
+
+#define SMS_GPIO_OUTPUTDRIVING_4mA  0
+#define SMS_GPIO_OUTPUTDRIVING_8mA  1
+#define SMS_GPIO_OUTPUTDRIVING_12mA 2
+#define SMS_GPIO_OUTPUTDRIVING_16mA 3
+       u8 outputdriving;
+};
+
 struct smsdvb_client_t {
        struct list_head entry;
 
@@ -353,7 +381,7 @@ struct smsdvb_client_t {
        struct dvb_frontend     frontend;
 
        fe_status_t             fe_status;
-       int                     fe_ber, fe_snr, fe_signal_strength;
+       int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
 
        struct completion       tune_done, stat_done;
 
@@ -396,9 +424,15 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
 extern void smscore_putbuffer(struct smscore_device_t *coredev,
                              struct smscore_buffer_t *cb);
 
+int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
+                          struct smscore_gpio_config *pinconfig);
+int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
+
 void smscore_set_board_id(struct smscore_device_t *core, int id);
 int smscore_get_board_id(struct smscore_device_t *core);
 
+int smscore_led_state(struct smscore_device_t *core, int led);
+
 /* smsdvb.c */
 int smsdvb_register(void);
 void smsdvb_unregister(void);
index 8d490e133f350aa3c41c346b8c1fb2b397488d99..2da953a4f4f56cc08d94e9d6d0e0460dc6a9aa31 100644 (file)
@@ -60,6 +60,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 
                        client->fe_snr = p->Stat.SNR;
                        client->fe_ber = p->Stat.BER;
+                       client->fe_unc = p->Stat.BERErrorCount;
 
                        if (p->Stat.InBandPwr < -95)
                                client->fe_signal_strength = 0;
@@ -72,6 +73,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
                        client->fe_status = 0;
                        client->fe_snr =
                        client->fe_ber =
+                       client->fe_unc =
                        client->fe_signal_strength = 0;
                }
 
@@ -165,8 +167,18 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
        struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
                             DVBT_BDA_CONTROL_MSG_ID,
                             HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
-       return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-                                          &client->stat_done);
+       int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+                                             &client->stat_done);
+       if (ret < 0)
+               return ret;
+
+       if (client->fe_status & FE_HAS_LOCK)
+               sms_board_led_feedback(client->coredev,
+                                      (client->fe_unc == 0) ?
+                                      SMS_LED_HI : SMS_LED_LO);
+       else
+               sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+       return ret;
 }
 
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -217,6 +229,18 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
        return rc;
 }
 
+static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct smsdvb_client_t *client =
+               container_of(fe, struct smsdvb_client_t, frontend);
+       int rc = smsdvb_send_statistics_request(client);
+
+       if (!rc)
+               *ucblocks = client->fe_unc;
+
+       return rc;
+}
+
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
                                    struct dvb_frontend_tune_settings *tune)
 {
@@ -273,6 +297,28 @@ static int smsdvb_get_frontend(struct dvb_frontend *fe,
        /* todo: */
        memcpy(fep, &client->fe_params,
               sizeof(struct dvb_frontend_parameters));
+
+       return 0;
+}
+
+static int smsdvb_init(struct dvb_frontend *fe)
+{
+       struct smsdvb_client_t *client =
+               container_of(fe, struct smsdvb_client_t, frontend);
+
+       sms_board_power(client->coredev, 1);
+
+       return 0;
+}
+
+static int smsdvb_sleep(struct dvb_frontend *fe)
+{
+       struct smsdvb_client_t *client =
+               container_of(fe, struct smsdvb_client_t, frontend);
+
+       sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+       sms_board_power(client->coredev, 0);
+
        return 0;
 }
 
@@ -308,6 +354,10 @@ static struct dvb_frontend_ops smsdvb_fe_ops = {
        .read_ber = smsdvb_read_ber,
        .read_signal_strength = smsdvb_read_signal_strength,
        .read_snr = smsdvb_read_snr,
+       .read_ucblocks = smsdvb_read_ucblocks,
+
+       .init = smsdvb_init,
+       .sleep = smsdvb_sleep,
 };
 
 static int smsdvb_hotplug(struct smscore_device_t *coredev,
@@ -402,6 +452,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 
        sms_info("success");
 
+       sms_board_setup(coredev);
+
        return 0;
 
 client_error:
index 87a3c24454b9903e5ad0fdc6aba160cf512091d6..5d7ca341771995941d1810effabf7a104a83224c 100644 (file)
@@ -432,11 +432,56 @@ static void smsusb_disconnect(struct usb_interface *intf)
        smsusb_term_device(intf);
 }
 
+static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+       struct smsusb_device_t *dev =
+               (struct smsusb_device_t *)usb_get_intfdata(intf);
+       printk(KERN_INFO "%s  Entering status %d.\n", __func__, msg.event);
+       smsusb_stop_streaming(dev);
+       return 0;
+}
+
+static int smsusb_resume(struct usb_interface *intf)
+{
+       int rc, i;
+       struct smsusb_device_t *dev =
+               (struct smsusb_device_t *)usb_get_intfdata(intf);
+       struct usb_device *udev = interface_to_usbdev(intf);
+
+       printk(KERN_INFO "%s  Entering.\n", __func__);
+       usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
+       usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+
+       for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
+               printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
+                      intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
+                      intf->cur_altsetting->endpoint[i].desc.bmAttributes,
+                      intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+
+       if (intf->num_altsetting > 0) {
+               rc = usb_set_interface(udev,
+                                      intf->cur_altsetting->desc.
+                                      bInterfaceNumber, 0);
+               if (rc < 0) {
+                       printk(KERN_INFO
+                              "%s usb_set_interface failed, rc %d\n",
+                              __func__, rc);
+                       return rc;
+               }
+       }
+
+       smsusb_start_streaming(dev);
+       return 0;
+}
+
 static struct usb_driver smsusb_driver = {
        .name                   = "sms1xxx",
        .probe                  = smsusb_probe,
        .disconnect             = smsusb_disconnect,
        .id_table               = smsusb_id_table,
+
+       .suspend                = smsusb_suspend,
+       .resume                 = smsusb_resume,
 };
 
 int smsusb_register(void)
index 401a04effc06817befbc4d6772565c430648d78a..ab0bcd208c78341e454ebafdab9bf21ac1de51b7 100644 (file)
@@ -104,6 +104,8 @@ config DVB_BUDGET_CI
        select DVB_STV0297 if !DVB_FE_CUSTOMISE
        select DVB_STV0299 if !DVB_FE_CUSTOMISE
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+       select DVB_STB0899 if !DVB_FE_CUSTOMISE
+       select DVB_STB6100 if !DVB_FE_CUSTOMISE
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
        select DVB_TDA10023 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMIZE
@@ -131,6 +133,8 @@ config DVB_BUDGET_AV
        select DVB_TDA1004X if !DVB_FE_CUSTOMISE
        select DVB_TDA10021 if !DVB_FE_CUSTOMISE
        select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+       select DVB_STB0899 if !DVB_FE_CUSTOMISE
+       select DVB_TDA8261 if !DVB_FE_CUSTOMISE
        select DVB_TUA6100 if !DVB_FE_CUSTOMISE
        help
          Support for simple SAA7146 based DVB cards
index 1032ea77837e356766cb27aaa2bb3f3295688b84..f996cef79ec1ff0930060f338aa43135074eeb07 100644 (file)
 
 #include "budget.h"
 #include "stv0299.h"
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+#include "tda8261.h"
+#include "tda8261_cfg.h"
 #include "tda1002x.h"
 #include "tda1004x.h"
 #include "tua6100.h"
@@ -882,6 +887,281 @@ static struct stv0299_config philips_sd1878_config = {
        .set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
 };
 
+/* KNC1 DVB-S (STB0899) Inittab        */
+static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {
+
+       { STB0899_DEV_ID                , 0x81 },
+       { STB0899_DISCNTRL1             , 0x32 },
+       { STB0899_DISCNTRL2             , 0x80 },
+       { STB0899_DISRX_ST0             , 0x04 },
+       { STB0899_DISRX_ST1             , 0x00 },
+       { STB0899_DISPARITY             , 0x00 },
+       { STB0899_DISFIFO               , 0x00 },
+       { STB0899_DISSTATUS             , 0x20 },
+       { STB0899_DISF22                , 0x8c },
+       { STB0899_DISF22RX              , 0x9a },
+       { STB0899_SYSREG                , 0x0b },
+       { STB0899_ACRPRESC              , 0x11 },
+       { STB0899_ACRDIV1               , 0x0a },
+       { STB0899_ACRDIV2               , 0x05 },
+       { STB0899_DACR1                 , 0x00 },
+       { STB0899_DACR2                 , 0x00 },
+       { STB0899_OUTCFG                , 0x00 },
+       { STB0899_MODECFG               , 0x00 },
+       { STB0899_IRQSTATUS_3           , 0x30 },
+       { STB0899_IRQSTATUS_2           , 0x00 },
+       { STB0899_IRQSTATUS_1           , 0x00 },
+       { STB0899_IRQSTATUS_0           , 0x00 },
+       { STB0899_IRQMSK_3              , 0xf3 },
+       { STB0899_IRQMSK_2              , 0xfc },
+       { STB0899_IRQMSK_1              , 0xff },
+       { STB0899_IRQMSK_0              , 0xff },
+       { STB0899_IRQCFG                , 0x00 },
+       { STB0899_I2CCFG                , 0x88 },
+       { STB0899_I2CRPT                , 0x58 }, /* Repeater=8, Stop=disabled */
+       { STB0899_IOPVALUE5             , 0x00 },
+       { STB0899_IOPVALUE4             , 0x20 },
+       { STB0899_IOPVALUE3             , 0xc9 },
+       { STB0899_IOPVALUE2             , 0x90 },
+       { STB0899_IOPVALUE1             , 0x40 },
+       { STB0899_IOPVALUE0             , 0x00 },
+       { STB0899_GPIO00CFG             , 0x82 },
+       { STB0899_GPIO01CFG             , 0x82 },
+       { STB0899_GPIO02CFG             , 0x82 },
+       { STB0899_GPIO03CFG             , 0x82 },
+       { STB0899_GPIO04CFG             , 0x82 },
+       { STB0899_GPIO05CFG             , 0x82 },
+       { STB0899_GPIO06CFG             , 0x82 },
+       { STB0899_GPIO07CFG             , 0x82 },
+       { STB0899_GPIO08CFG             , 0x82 },
+       { STB0899_GPIO09CFG             , 0x82 },
+       { STB0899_GPIO10CFG             , 0x82 },
+       { STB0899_GPIO11CFG             , 0x82 },
+       { STB0899_GPIO12CFG             , 0x82 },
+       { STB0899_GPIO13CFG             , 0x82 },
+       { STB0899_GPIO14CFG             , 0x82 },
+       { STB0899_GPIO15CFG             , 0x82 },
+       { STB0899_GPIO16CFG             , 0x82 },
+       { STB0899_GPIO17CFG             , 0x82 },
+       { STB0899_GPIO18CFG             , 0x82 },
+       { STB0899_GPIO19CFG             , 0x82 },
+       { STB0899_GPIO20CFG             , 0x82 },
+       { STB0899_SDATCFG               , 0xb8 },
+       { STB0899_SCLTCFG               , 0xba },
+       { STB0899_AGCRFCFG              , 0x08 }, /* 0x1c */
+       { STB0899_GPIO22                , 0x82 }, /* AGCBB2CFG */
+       { STB0899_GPIO21                , 0x91 }, /* AGCBB1CFG */
+       { STB0899_DIRCLKCFG             , 0x82 },
+       { STB0899_CLKOUT27CFG           , 0x7e },
+       { STB0899_STDBYCFG              , 0x82 },
+       { STB0899_CS0CFG                , 0x82 },
+       { STB0899_CS1CFG                , 0x82 },
+       { STB0899_DISEQCOCFG            , 0x20 },
+       { STB0899_GPIO32CFG             , 0x82 },
+       { STB0899_GPIO33CFG             , 0x82 },
+       { STB0899_GPIO34CFG             , 0x82 },
+       { STB0899_GPIO35CFG             , 0x82 },
+       { STB0899_GPIO36CFG             , 0x82 },
+       { STB0899_GPIO37CFG             , 0x82 },
+       { STB0899_GPIO38CFG             , 0x82 },
+       { STB0899_GPIO39CFG             , 0x82 },
+       { STB0899_NCOARSE               , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+       { STB0899_SYNTCTRL              , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+       { STB0899_FILTCTRL              , 0x00 },
+       { STB0899_SYSCTRL               , 0x00 },
+       { STB0899_STOPCLK1              , 0x20 },
+       { STB0899_STOPCLK2              , 0x00 },
+       { STB0899_INTBUFSTATUS          , 0x00 },
+       { STB0899_INTBUFCTRL            , 0x0a },
+       { 0xffff                        , 0xff },
+};
+
+static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
+       { STB0899_DEMOD                 , 0x00 },
+       { STB0899_RCOMPC                , 0xc9 },
+       { STB0899_AGC1CN                , 0x41 },
+       { STB0899_AGC1REF               , 0x08 },
+       { STB0899_RTC                   , 0x7a },
+       { STB0899_TMGCFG                , 0x4e },
+       { STB0899_AGC2REF               , 0x33 },
+       { STB0899_TLSR                  , 0x84 },
+       { STB0899_CFD                   , 0xee },
+       { STB0899_ACLC                  , 0x87 },
+       { STB0899_BCLC                  , 0x94 },
+       { STB0899_EQON                  , 0x41 },
+       { STB0899_LDT                   , 0xdd },
+       { STB0899_LDT2                  , 0xc9 },
+       { STB0899_EQUALREF              , 0xb4 },
+       { STB0899_TMGRAMP               , 0x10 },
+       { STB0899_TMGTHD                , 0x30 },
+       { STB0899_IDCCOMP               , 0xfb },
+       { STB0899_QDCCOMP               , 0x03 },
+       { STB0899_POWERI                , 0x3b },
+       { STB0899_POWERQ                , 0x3d },
+       { STB0899_RCOMP                 , 0x81 },
+       { STB0899_AGCIQIN               , 0x80 },
+       { STB0899_AGC2I1                , 0x04 },
+       { STB0899_AGC2I2                , 0xf5 },
+       { STB0899_TLIR                  , 0x25 },
+       { STB0899_RTF                   , 0x80 },
+       { STB0899_DSTATUS               , 0x00 },
+       { STB0899_LDI                   , 0xca },
+       { STB0899_CFRM                  , 0xf1 },
+       { STB0899_CFRL                  , 0xf3 },
+       { STB0899_NIRM                  , 0x2a },
+       { STB0899_NIRL                  , 0x05 },
+       { STB0899_ISYMB                 , 0x17 },
+       { STB0899_QSYMB                 , 0xfa },
+       { STB0899_SFRH                  , 0x2f },
+       { STB0899_SFRM                  , 0x68 },
+       { STB0899_SFRL                  , 0x40 },
+       { STB0899_SFRUPH                , 0x2f },
+       { STB0899_SFRUPM                , 0x68 },
+       { STB0899_SFRUPL                , 0x40 },
+       { STB0899_EQUAI1                , 0xfd },
+       { STB0899_EQUAQ1                , 0x04 },
+       { STB0899_EQUAI2                , 0x0f },
+       { STB0899_EQUAQ2                , 0xff },
+       { STB0899_EQUAI3                , 0xdf },
+       { STB0899_EQUAQ3                , 0xfa },
+       { STB0899_EQUAI4                , 0x37 },
+       { STB0899_EQUAQ4                , 0x0d },
+       { STB0899_EQUAI5                , 0xbd },
+       { STB0899_EQUAQ5                , 0xf7 },
+       { STB0899_DSTATUS2              , 0x00 },
+       { STB0899_VSTATUS               , 0x00 },
+       { STB0899_VERROR                , 0xff },
+       { STB0899_IQSWAP                , 0x2a },
+       { STB0899_ECNT1M                , 0x00 },
+       { STB0899_ECNT1L                , 0x00 },
+       { STB0899_ECNT2M                , 0x00 },
+       { STB0899_ECNT2L                , 0x00 },
+       { STB0899_ECNT3M                , 0x00 },
+       { STB0899_ECNT3L                , 0x00 },
+       { STB0899_FECAUTO1              , 0x06 },
+       { STB0899_FECM                  , 0x01 },
+       { STB0899_VTH12                 , 0xf0 },
+       { STB0899_VTH23                 , 0xa0 },
+       { STB0899_VTH34                 , 0x78 },
+       { STB0899_VTH56                 , 0x4e },
+       { STB0899_VTH67                 , 0x48 },
+       { STB0899_VTH78                 , 0x38 },
+       { STB0899_PRVIT                 , 0xff },
+       { STB0899_VITSYNC               , 0x19 },
+       { STB0899_RSULC                 , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+       { STB0899_TSULC                 , 0x42 },
+       { STB0899_RSLLC                 , 0x40 },
+       { STB0899_TSLPL                 , 0x12 },
+       { STB0899_TSCFGH                , 0x0c },
+       { STB0899_TSCFGM                , 0x00 },
+       { STB0899_TSCFGL                , 0x0c },
+       { STB0899_TSOUT                 , 0x0d }, /* 0x0d for CAM */
+       { STB0899_RSSYNCDEL             , 0x00 },
+       { STB0899_TSINHDELH             , 0x02 },
+       { STB0899_TSINHDELM             , 0x00 },
+       { STB0899_TSINHDELL             , 0x00 },
+       { STB0899_TSLLSTKM              , 0x00 },
+       { STB0899_TSLLSTKL              , 0x00 },
+       { STB0899_TSULSTKM              , 0x00 },
+       { STB0899_TSULSTKL              , 0xab },
+       { STB0899_PCKLENUL              , 0x00 },
+       { STB0899_PCKLENLL              , 0xcc },
+       { STB0899_RSPCKLEN              , 0xcc },
+       { STB0899_TSSTATUS              , 0x80 },
+       { STB0899_ERRCTRL1              , 0xb6 },
+       { STB0899_ERRCTRL2              , 0x96 },
+       { STB0899_ERRCTRL3              , 0x89 },
+       { STB0899_DMONMSK1              , 0x27 },
+       { STB0899_DMONMSK0              , 0x03 },
+       { STB0899_DEMAPVIT              , 0x5c },
+       { STB0899_PLPARM                , 0x1f },
+       { STB0899_PDELCTRL              , 0x48 },
+       { STB0899_PDELCTRL2             , 0x00 },
+       { STB0899_BBHCTRL1              , 0x00 },
+       { STB0899_BBHCTRL2              , 0x00 },
+       { STB0899_HYSTTHRESH            , 0x77 },
+       { STB0899_MATCSTM               , 0x00 },
+       { STB0899_MATCSTL               , 0x00 },
+       { STB0899_UPLCSTM               , 0x00 },
+       { STB0899_UPLCSTL               , 0x00 },
+       { STB0899_DFLCSTM               , 0x00 },
+       { STB0899_DFLCSTL               , 0x00 },
+       { STB0899_SYNCCST               , 0x00 },
+       { STB0899_SYNCDCSTM             , 0x00 },
+       { STB0899_SYNCDCSTL             , 0x00 },
+       { STB0899_ISI_ENTRY             , 0x00 },
+       { STB0899_ISI_BIT_EN            , 0x00 },
+       { STB0899_MATSTRM               , 0x00 },
+       { STB0899_MATSTRL               , 0x00 },
+       { STB0899_UPLSTRM               , 0x00 },
+       { STB0899_UPLSTRL               , 0x00 },
+       { STB0899_DFLSTRM               , 0x00 },
+       { STB0899_DFLSTRL               , 0x00 },
+       { STB0899_SYNCSTR               , 0x00 },
+       { STB0899_SYNCDSTRM             , 0x00 },
+       { STB0899_SYNCDSTRL             , 0x00 },
+       { STB0899_CFGPDELSTATUS1        , 0x10 },
+       { STB0899_CFGPDELSTATUS2        , 0x00 },
+       { STB0899_BBFERRORM             , 0x00 },
+       { STB0899_BBFERRORL             , 0x00 },
+       { STB0899_UPKTERRORM            , 0x00 },
+       { STB0899_UPKTERRORL            , 0x00 },
+       { 0xffff                        , 0xff },
+};
+
+/* STB0899 demodulator config for the KNC1 and clones */
+static struct stb0899_config knc1_dvbs2_config = {
+       .init_dev               = knc1_stb0899_s1_init_1,
+       .init_s2_demod          = stb0899_s2_init_2,
+       .init_s1_demod          = knc1_stb0899_s1_init_3,
+       .init_s2_fec            = stb0899_s2_init_4,
+       .init_tst               = stb0899_s1_init_5,
+
+       .postproc               = NULL,
+
+       .demod_address          = 0x68,
+//     .ts_output_mode         = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL      */
+       .block_sync_mode        = STB0899_SYNC_FORCED,  /* DSS, SYNC_FORCED/UNSYNCED    */
+//     .ts_pfbit_toggle        = STB0899_MPEG_NORMAL,  /* DirecTV, MPEG toggling seq   */
+
+       .xtal_freq              = 27000000,
+       .inversion              = IQ_SWAP_OFF, /* 1 */
+
+       .lo_clk                 = 76500000,
+       .hi_clk                 = 90000000,
+
+       .esno_ave               = STB0899_DVBS2_ESNO_AVE,
+       .esno_quant             = STB0899_DVBS2_ESNO_QUANT,
+       .avframes_coarse        = STB0899_DVBS2_AVFRAMES_COARSE,
+       .avframes_fine          = STB0899_DVBS2_AVFRAMES_FINE,
+       .miss_threshold         = STB0899_DVBS2_MISS_THRESHOLD,
+       .uwp_threshold_acq      = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+       .uwp_threshold_track    = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+       .uwp_threshold_sof      = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+       .sof_search_timeout     = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+       .btr_nco_bits           = STB0899_DVBS2_BTR_NCO_BITS,
+       .btr_gain_shift_offset  = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+       .crl_nco_bits           = STB0899_DVBS2_CRL_NCO_BITS,
+       .ldpc_max_iter          = STB0899_DVBS2_LDPC_MAX_ITER,
+
+       .tuner_get_frequency    = tda8261_get_frequency,
+       .tuner_set_frequency    = tda8261_set_frequency,
+       .tuner_set_bandwidth    = NULL,
+       .tuner_get_bandwidth    = tda8261_get_bandwidth,
+       .tuner_set_rfsiggain    = NULL
+};
+
+/*
+ * SD1878/SHA tuner config
+ * 1F, Single I/P, Horizontal mount, High Sensitivity
+ */
+static const struct tda8261_config sd1878c_config = {
+//     .name           = "SD1878/SHA",
+       .addr           = 0x60,
+       .step_size      = TDA8261_STEP_1000 /* kHz */
+};
+
 static u8 read_pwm(struct budget_av *budget_av)
 {
        u8 b = 0xff;
@@ -905,8 +1185,11 @@ static u8 read_pwm(struct budget_av *budget_av)
 #define SUBID_DVBS_TV_STAR             0x0014
 #define SUBID_DVBS_TV_STAR_PLUS_X4     0x0015
 #define SUBID_DVBS_TV_STAR_CI          0x0016
+#define SUBID_DVBS2_KNC1               0x0018
+#define SUBID_DVBS2_KNC1_OEM           0x0019
 #define SUBID_DVBS_EASYWATCH_1         0x001a
 #define SUBID_DVBS_EASYWATCH_2         0x001b
+#define SUBID_DVBS2_EASYWATCH          0x001d
 #define SUBID_DVBS_EASYWATCH           0x001e
 
 #define SUBID_DVBC_EASYWATCH           0x002a
@@ -941,6 +1224,9 @@ static void frontend_init(struct budget_av *budget_av)
                case SUBID_DVBT_KNC1_PLUS:
                case SUBID_DVBC_EASYWATCH:
                case SUBID_DVBC_KNC1_PLUS_MK3:
+               case SUBID_DVBS2_KNC1:
+               case SUBID_DVBS2_KNC1_OEM:
+               case SUBID_DVBS2_EASYWATCH:
                        saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
                        break;
        }
@@ -993,7 +1279,14 @@ static void frontend_init(struct budget_av *budget_av)
                        fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
                }
                break;
+       case SUBID_DVBS2_KNC1:
+       case SUBID_DVBS2_KNC1_OEM:
+       case SUBID_DVBS2_EASYWATCH:
+               budget_av->reinitialise_demod = 1;
+               if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap)))
+                       dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap);
 
+               break;
        case SUBID_DVBS_CINERGY1200:
                fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
                                    &budget_av->budget.i2c_adap);
@@ -1260,6 +1553,8 @@ static struct saa7146_ext_vv vv_data = {
 static struct saa7146_extension budget_extension;
 
 MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2);
+MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2);
 MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
 MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
@@ -1290,6 +1585,9 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
        MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),
        MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
+       MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018),
+       MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019),
+       MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d),
        MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
        MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
        MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
index 0a5aad45435d2c0bb37209b8fb2341513f38e21e..3507463fdac96670bc9f6a11fa32151e404d4a60 100644 (file)
 #include "stv0299.h"
 #include "stv0297.h"
 #include "tda1004x.h"
+#include "stb0899_drv.h"
+#include "stb0899_reg.h"
+#include "stb0899_cfg.h"
+#include "stb6100.h"
+#include "stb6100_cfg.h"
 #include "lnbp21.h"
 #include "bsbe1.h"
 #include "bsru6.h"
@@ -1071,7 +1076,271 @@ static struct tda10023_config tda10023_config = {
        .deltaf = 0xa511,
 };
 
+/* TT S2-3200 DVB-S (STB0899) Inittab */
+static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
+
+       { STB0899_DEV_ID                , 0x81 },
+       { STB0899_DISCNTRL1             , 0x32 },
+       { STB0899_DISCNTRL2             , 0x80 },
+       { STB0899_DISRX_ST0             , 0x04 },
+       { STB0899_DISRX_ST1             , 0x00 },
+       { STB0899_DISPARITY             , 0x00 },
+       { STB0899_DISFIFO               , 0x00 },
+       { STB0899_DISSTATUS             , 0x20 },
+       { STB0899_DISF22                , 0x8c },
+       { STB0899_DISF22RX              , 0x9a },
+       { STB0899_SYSREG                , 0x0b },
+       { STB0899_ACRPRESC              , 0x11 },
+       { STB0899_ACRDIV1               , 0x0a },
+       { STB0899_ACRDIV2               , 0x05 },
+       { STB0899_DACR1                 , 0x00 },
+       { STB0899_DACR2                 , 0x00 },
+       { STB0899_OUTCFG                , 0x00 },
+       { STB0899_MODECFG               , 0x00 },
+       { STB0899_IRQSTATUS_3           , 0x30 },
+       { STB0899_IRQSTATUS_2           , 0x00 },
+       { STB0899_IRQSTATUS_1           , 0x00 },
+       { STB0899_IRQSTATUS_0           , 0x00 },
+       { STB0899_IRQMSK_3              , 0xf3 },
+       { STB0899_IRQMSK_2              , 0xfc },
+       { STB0899_IRQMSK_1              , 0xff },
+       { STB0899_IRQMSK_0              , 0xff },
+       { STB0899_IRQCFG                , 0x00 },
+       { STB0899_I2CCFG                , 0x88 },
+       { STB0899_I2CRPT                , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
+       { STB0899_IOPVALUE5             , 0x00 },
+       { STB0899_IOPVALUE4             , 0x20 },
+       { STB0899_IOPVALUE3             , 0xc9 },
+       { STB0899_IOPVALUE2             , 0x90 },
+       { STB0899_IOPVALUE1             , 0x40 },
+       { STB0899_IOPVALUE0             , 0x00 },
+       { STB0899_GPIO00CFG             , 0x82 },
+       { STB0899_GPIO01CFG             , 0x82 },
+       { STB0899_GPIO02CFG             , 0x82 },
+       { STB0899_GPIO03CFG             , 0x82 },
+       { STB0899_GPIO04CFG             , 0x82 },
+       { STB0899_GPIO05CFG             , 0x82 },
+       { STB0899_GPIO06CFG             , 0x82 },
+       { STB0899_GPIO07CFG             , 0x82 },
+       { STB0899_GPIO08CFG             , 0x82 },
+       { STB0899_GPIO09CFG             , 0x82 },
+       { STB0899_GPIO10CFG             , 0x82 },
+       { STB0899_GPIO11CFG             , 0x82 },
+       { STB0899_GPIO12CFG             , 0x82 },
+       { STB0899_GPIO13CFG             , 0x82 },
+       { STB0899_GPIO14CFG             , 0x82 },
+       { STB0899_GPIO15CFG             , 0x82 },
+       { STB0899_GPIO16CFG             , 0x82 },
+       { STB0899_GPIO17CFG             , 0x82 },
+       { STB0899_GPIO18CFG             , 0x82 },
+       { STB0899_GPIO19CFG             , 0x82 },
+       { STB0899_GPIO20CFG             , 0x82 },
+       { STB0899_SDATCFG               , 0xb8 },
+       { STB0899_SCLTCFG               , 0xba },
+       { STB0899_AGCRFCFG              , 0x1c }, /* 0x11 */
+       { STB0899_GPIO22                , 0x82 }, /* AGCBB2CFG */
+       { STB0899_GPIO21                , 0x91 }, /* AGCBB1CFG */
+       { STB0899_DIRCLKCFG             , 0x82 },
+       { STB0899_CLKOUT27CFG           , 0x7e },
+       { STB0899_STDBYCFG              , 0x82 },
+       { STB0899_CS0CFG                , 0x82 },
+       { STB0899_CS1CFG                , 0x82 },
+       { STB0899_DISEQCOCFG            , 0x20 },
+       { STB0899_GPIO32CFG             , 0x82 },
+       { STB0899_GPIO33CFG             , 0x82 },
+       { STB0899_GPIO34CFG             , 0x82 },
+       { STB0899_GPIO35CFG             , 0x82 },
+       { STB0899_GPIO36CFG             , 0x82 },
+       { STB0899_GPIO37CFG             , 0x82 },
+       { STB0899_GPIO38CFG             , 0x82 },
+       { STB0899_GPIO39CFG             , 0x82 },
+       { STB0899_NCOARSE               , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+       { STB0899_SYNTCTRL              , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+       { STB0899_FILTCTRL              , 0x00 },
+       { STB0899_SYSCTRL               , 0x00 },
+       { STB0899_STOPCLK1              , 0x20 },
+       { STB0899_STOPCLK2              , 0x00 },
+       { STB0899_INTBUFSTATUS          , 0x00 },
+       { STB0899_INTBUFCTRL            , 0x0a },
+       { 0xffff                        , 0xff },
+};
+
+static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
+       { STB0899_DEMOD                 , 0x00 },
+       { STB0899_RCOMPC                , 0xc9 },
+       { STB0899_AGC1CN                , 0x41 },
+       { STB0899_AGC1REF               , 0x10 },
+       { STB0899_RTC                   , 0x7a },
+       { STB0899_TMGCFG                , 0x4e },
+       { STB0899_AGC2REF               , 0x34 },
+       { STB0899_TLSR                  , 0x84 },
+       { STB0899_CFD                   , 0xc7 },
+       { STB0899_ACLC                  , 0x87 },
+       { STB0899_BCLC                  , 0x94 },
+       { STB0899_EQON                  , 0x41 },
+       { STB0899_LDT                   , 0xdd },
+       { STB0899_LDT2                  , 0xc9 },
+       { STB0899_EQUALREF              , 0xb4 },
+       { STB0899_TMGRAMP               , 0x10 },
+       { STB0899_TMGTHD                , 0x30 },
+       { STB0899_IDCCOMP               , 0xfb },
+       { STB0899_QDCCOMP               , 0x03 },
+       { STB0899_POWERI                , 0x3b },
+       { STB0899_POWERQ                , 0x3d },
+       { STB0899_RCOMP                 , 0x81 },
+       { STB0899_AGCIQIN               , 0x80 },
+       { STB0899_AGC2I1                , 0x04 },
+       { STB0899_AGC2I2                , 0xf5 },
+       { STB0899_TLIR                  , 0x25 },
+       { STB0899_RTF                   , 0x80 },
+       { STB0899_DSTATUS               , 0x00 },
+       { STB0899_LDI                   , 0xca },
+       { STB0899_CFRM                  , 0xf1 },
+       { STB0899_CFRL                  , 0xf3 },
+       { STB0899_NIRM                  , 0x2a },
+       { STB0899_NIRL                  , 0x05 },
+       { STB0899_ISYMB                 , 0x17 },
+       { STB0899_QSYMB                 , 0xfa },
+       { STB0899_SFRH                  , 0x2f },
+       { STB0899_SFRM                  , 0x68 },
+       { STB0899_SFRL                  , 0x40 },
+       { STB0899_SFRUPH                , 0x2f },
+       { STB0899_SFRUPM                , 0x68 },
+       { STB0899_SFRUPL                , 0x40 },
+       { STB0899_EQUAI1                , 0xfd },
+       { STB0899_EQUAQ1                , 0x04 },
+       { STB0899_EQUAI2                , 0x0f },
+       { STB0899_EQUAQ2                , 0xff },
+       { STB0899_EQUAI3                , 0xdf },
+       { STB0899_EQUAQ3                , 0xfa },
+       { STB0899_EQUAI4                , 0x37 },
+       { STB0899_EQUAQ4                , 0x0d },
+       { STB0899_EQUAI5                , 0xbd },
+       { STB0899_EQUAQ5                , 0xf7 },
+       { STB0899_DSTATUS2              , 0x00 },
+       { STB0899_VSTATUS               , 0x00 },
+       { STB0899_VERROR                , 0xff },
+       { STB0899_IQSWAP                , 0x2a },
+       { STB0899_ECNT1M                , 0x00 },
+       { STB0899_ECNT1L                , 0x00 },
+       { STB0899_ECNT2M                , 0x00 },
+       { STB0899_ECNT2L                , 0x00 },
+       { STB0899_ECNT3M                , 0x00 },
+       { STB0899_ECNT3L                , 0x00 },
+       { STB0899_FECAUTO1              , 0x06 },
+       { STB0899_FECM                  , 0x01 },
+       { STB0899_VTH12                 , 0xf0 },
+       { STB0899_VTH23                 , 0xa0 },
+       { STB0899_VTH34                 , 0x78 },
+       { STB0899_VTH56                 , 0x4e },
+       { STB0899_VTH67                 , 0x48 },
+       { STB0899_VTH78                 , 0x38 },
+       { STB0899_PRVIT                 , 0xff },
+       { STB0899_VITSYNC               , 0x19 },
+       { STB0899_RSULC                 , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+       { STB0899_TSULC                 , 0x42 },
+       { STB0899_RSLLC                 , 0x40 },
+       { STB0899_TSLPL                 , 0x12 },
+       { STB0899_TSCFGH                , 0x0c },
+       { STB0899_TSCFGM                , 0x00 },
+       { STB0899_TSCFGL                , 0x0c },
+       { STB0899_TSOUT                 , 0x0d }, /* 0x0d for CAM */
+       { STB0899_RSSYNCDEL             , 0x00 },
+       { STB0899_TSINHDELH             , 0x02 },
+       { STB0899_TSINHDELM             , 0x00 },
+       { STB0899_TSINHDELL             , 0x00 },
+       { STB0899_TSLLSTKM              , 0x00 },
+       { STB0899_TSLLSTKL              , 0x00 },
+       { STB0899_TSULSTKM              , 0x00 },
+       { STB0899_TSULSTKL              , 0xab },
+       { STB0899_PCKLENUL              , 0x00 },
+       { STB0899_PCKLENLL              , 0xcc },
+       { STB0899_RSPCKLEN              , 0xcc },
+       { STB0899_TSSTATUS              , 0x80 },
+       { STB0899_ERRCTRL1              , 0xb6 },
+       { STB0899_ERRCTRL2              , 0x96 },
+       { STB0899_ERRCTRL3              , 0x89 },
+       { STB0899_DMONMSK1              , 0x27 },
+       { STB0899_DMONMSK0              , 0x03 },
+       { STB0899_DEMAPVIT              , 0x5c },
+       { STB0899_PLPARM                , 0x1f },
+       { STB0899_PDELCTRL              , 0x48 },
+       { STB0899_PDELCTRL2             , 0x00 },
+       { STB0899_BBHCTRL1              , 0x00 },
+       { STB0899_BBHCTRL2              , 0x00 },
+       { STB0899_HYSTTHRESH            , 0x77 },
+       { STB0899_MATCSTM               , 0x00 },
+       { STB0899_MATCSTL               , 0x00 },
+       { STB0899_UPLCSTM               , 0x00 },
+       { STB0899_UPLCSTL               , 0x00 },
+       { STB0899_DFLCSTM               , 0x00 },
+       { STB0899_DFLCSTL               , 0x00 },
+       { STB0899_SYNCCST               , 0x00 },
+       { STB0899_SYNCDCSTM             , 0x00 },
+       { STB0899_SYNCDCSTL             , 0x00 },
+       { STB0899_ISI_ENTRY             , 0x00 },
+       { STB0899_ISI_BIT_EN            , 0x00 },
+       { STB0899_MATSTRM               , 0x00 },
+       { STB0899_MATSTRL               , 0x00 },
+       { STB0899_UPLSTRM               , 0x00 },
+       { STB0899_UPLSTRL               , 0x00 },
+       { STB0899_DFLSTRM               , 0x00 },
+       { STB0899_DFLSTRL               , 0x00 },
+       { STB0899_SYNCSTR               , 0x00 },
+       { STB0899_SYNCDSTRM             , 0x00 },
+       { STB0899_SYNCDSTRL             , 0x00 },
+       { STB0899_CFGPDELSTATUS1        , 0x10 },
+       { STB0899_CFGPDELSTATUS2        , 0x00 },
+       { STB0899_BBFERRORM             , 0x00 },
+       { STB0899_BBFERRORL             , 0x00 },
+       { STB0899_UPKTERRORM            , 0x00 },
+       { STB0899_UPKTERRORL            , 0x00 },
+       { 0xffff                        , 0xff },
+};
 
+static struct stb0899_config tt3200_config = {
+       .init_dev               = tt3200_stb0899_s1_init_1,
+       .init_s2_demod          = stb0899_s2_init_2,
+       .init_s1_demod          = tt3200_stb0899_s1_init_3,
+       .init_s2_fec            = stb0899_s2_init_4,
+       .init_tst               = stb0899_s1_init_5,
+
+       .postproc               = NULL,
+
+       .demod_address          = 0x68,
+
+       .xtal_freq              = 27000000,
+       .inversion              = IQ_SWAP_ON, /* 1 */
+
+       .lo_clk                 = 76500000,
+       .hi_clk                 = 99000000,
+
+       .esno_ave               = STB0899_DVBS2_ESNO_AVE,
+       .esno_quant             = STB0899_DVBS2_ESNO_QUANT,
+       .avframes_coarse        = STB0899_DVBS2_AVFRAMES_COARSE,
+       .avframes_fine          = STB0899_DVBS2_AVFRAMES_FINE,
+       .miss_threshold         = STB0899_DVBS2_MISS_THRESHOLD,
+       .uwp_threshold_acq      = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+       .uwp_threshold_track    = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+       .uwp_threshold_sof      = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+       .sof_search_timeout     = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+       .btr_nco_bits           = STB0899_DVBS2_BTR_NCO_BITS,
+       .btr_gain_shift_offset  = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+       .crl_nco_bits           = STB0899_DVBS2_CRL_NCO_BITS,
+       .ldpc_max_iter          = STB0899_DVBS2_LDPC_MAX_ITER,
+
+       .tuner_get_frequency    = stb6100_get_frequency,
+       .tuner_set_frequency    = stb6100_set_frequency,
+       .tuner_set_bandwidth    = stb6100_set_bandwidth,
+       .tuner_get_bandwidth    = stb6100_get_bandwidth,
+       .tuner_set_rfsiggain    = NULL
+};
+
+struct stb6100_config tt3200_stb6100_config = {
+       .tuner_address  = 0x60,
+       .refclock       = 27000000,
+};
 
 static void frontend_init(struct budget_ci *budget_ci)
 {
@@ -1152,6 +1421,46 @@ static void frontend_init(struct budget_ci *budget_ci)
                        }
                }
                break;
+
+       case 0x1019:            // TT S2-3200 PCI
+               /*
+                * NOTE! on some STB0899 versions, the internal PLL takes a longer time
+                * to settle, aka LOCK. On the older revisions of the chip, we don't see
+                * this, as a result on the newer chips the entire clock tree, will not
+                * be stable after a freshly POWER 'ed up situation.
+                * In this case, we should RESET the STB0899 (Active LOW) and wait for
+                * PLL stabilization.
+                *
+                * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
+                * connected to the SAA7146 GPIO, GPIO2, Pin 142
+                */
+               /* Reset Demodulator */
+               saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
+               /* Wait for everything to die */
+               msleep(50);
+               /* Pull it up out of Reset state */
+               saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
+               /* Wait for PLL to stabilize */
+               msleep(250);
+               /*
+                * PLL state should be stable now. Ideally, we should check
+                * for PLL LOCK status. But well, never mind!
+                */
+               budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
+               if (budget_ci->budget.dvb_frontend) {
+                       if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
+                               if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
+                                       printk("%s: No LNBP21 found!\n", __FUNCTION__);
+                                       dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+                                       budget_ci->budget.dvb_frontend = NULL;
+                               }
+                       } else {
+                                       dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+                                       budget_ci->budget.dvb_frontend = NULL;
+                       }
+               }
+               break;
+
        }
 
        if (budget_ci->budget.dvb_frontend == NULL) {
@@ -1242,6 +1551,7 @@ MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T    PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
 
 static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@@ -1251,6 +1561,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
        MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
        MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
+       MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
        {
         .vendor = 0,
         }
index 86435bf162601661381d33f323d1e0176cac4774..3ad0c6789ba736fd80e7a02b0810a6b8f4b50db4 100644 (file)
@@ -103,6 +103,7 @@ static struct saa7146_pci_extension_data x_var = { \
 #define BUDGET_CIN1200C_MK3       15
 #define BUDGET_KNC1C_MK3          16
 #define BUDGET_KNC1CP_MK3         17
+#define BUDGET_KNC1S2              18
 
 #define BUDGET_VIDEO_PORTA         0
 #define BUDGET_VIDEO_PORTB         1
index a5ca176a7b083a80ef5201d2ac57d1a3475bbbbb..5474a22c1b2235ef627163c73ba27fe519d1b471 100644 (file)
@@ -1,5 +1,5 @@
-/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
- into both the USB and an analog audio input, so this thing
+/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
The device plugs into both the USB and an analog audio input, so this thing
  only deals with initialisation and frequency setting, the
  audio data has to be handled by a sound driver.
 
 
  History:
 
+ Version 0.44:
+       Add suspend/resume functions, fix unplug of device,
+       a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
+
  Version 0.43:
        Oliver Neukum: avoided DMA coherency issue
 
@@ -93,8 +97,8 @@
  */
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 
-#define DRIVER_VERSION "v0.41"
-#define RADIO_VERSION KERNEL_VERSION(0,4,1)
+#define DRIVER_VERSION "v0.44"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 4)
 
 static struct v4l2_queryctrl radio_qctrl[] = {
        {
@@ -104,7 +108,27 @@ static struct v4l2_queryctrl radio_qctrl[] = {
                .maximum       = 1,
                .default_value = 1,
                .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
+       },
+/* HINT: the disabled controls are only here to satify kradio and such apps */
+       {       .id             = V4L2_CID_AUDIO_VOLUME,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BALANCE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BASS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_TREBLE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_LOUDNESS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
 };
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
@@ -125,12 +149,16 @@ devices, that would be 76 and 91.  */
 #define FREQ_MAX 108.0
 #define FREQ_MUL 16000
 
+#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
 
 static int usb_dsbr100_probe(struct usb_interface *intf,
                             const struct usb_device_id *id);
 static void usb_dsbr100_disconnect(struct usb_interface *intf);
 static int usb_dsbr100_open(struct inode *inode, struct file *file);
 static int usb_dsbr100_close(struct inode *inode, struct file *file);
+static int usb_dsbr100_suspend(struct usb_interface *intf,
+                                               pm_message_t message);
+static int usb_dsbr100_resume(struct usb_interface *intf);
 
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
@@ -138,8 +166,9 @@ module_param(radio_nr, int, 0);
 /* Data for one (physical) device */
 struct dsbr100_device {
        struct usb_device *usbdev;
-       struct video_device *videodev;
+       struct video_device videodev;
        u8 *transfer_buffer;
+       struct mutex lock;      /* buffer locking */
        int curfreq;
        int stereo;
        int users;
@@ -147,7 +176,6 @@ struct dsbr100_device {
        int muted;
 };
 
-
 static struct usb_device_id usb_dsbr100_device_table [] = {
        { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
        { }                                             /* Terminating entry */
@@ -157,10 +185,14 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
 
 /* USB subsystem interface */
 static struct usb_driver usb_dsbr100_driver = {
-       .name =         "dsbr100",
-       .probe =        usb_dsbr100_probe,
-       .disconnect =   usb_dsbr100_disconnect,
-       .id_table =     usb_dsbr100_device_table,
+       .name                   = "dsbr100",
+       .probe                  = usb_dsbr100_probe,
+       .disconnect             = usb_dsbr100_disconnect,
+       .id_table               = usb_dsbr100_device_table,
+       .suspend                = usb_dsbr100_suspend,
+       .resume                 = usb_dsbr100_resume,
+       .reset_resume           = usb_dsbr100_resume,
+       .supports_autosuspend   = 0,
 };
 
 /* Low-level device interface begins here */
@@ -168,95 +200,190 @@ static struct usb_driver usb_dsbr100_driver = {
 /* switch on radio */
 static int dsbr100_start(struct dsbr100_device *radio)
 {
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x00, 0xC7, radio->transfer_buffer, 8, 300) < 0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_ONOFF,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x01, 0x00, radio->transfer_buffer, 8, 300) < 0)
-               return -1;
-       radio->muted=0;
+       int retval;
+       int request;
+
+       mutex_lock(&radio->lock);
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               USB_REQ_GET_STATUS,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x00, 0xC7, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = USB_REQ_GET_STATUS;
+               goto usb_control_msg_failed;
+       }
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               DSB100_ONOFF,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x01, 0x00, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = DSB100_ONOFF;
+               goto usb_control_msg_failed;
+       }
+
+       radio->muted = 0;
+       mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
-}
 
+usb_control_msg_failed:
+       mutex_unlock(&radio->lock);
+       dev_err(&radio->usbdev->dev,
+               "%s - usb_control_msg returned %i, request %i\n",
+                       __func__, retval, request);
+       return retval;
+
+}
 
 /* switch off radio */
 static int dsbr100_stop(struct dsbr100_device *radio)
 {
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x16, 0x1C, radio->transfer_buffer, 8, 300) < 0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_ONOFF,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x00, 0x00, radio->transfer_buffer, 8, 300) < 0)
-               return -1;
-       radio->muted=1;
+       int retval;
+       int request;
+
+       mutex_lock(&radio->lock);
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               USB_REQ_GET_STATUS,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x16, 0x1C, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = USB_REQ_GET_STATUS;
+               goto usb_control_msg_failed;
+       }
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               DSB100_ONOFF,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x00, 0x00, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = DSB100_ONOFF;
+               goto usb_control_msg_failed;
+       }
+
+       radio->muted = 1;
+       mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
+
+usb_control_msg_failed:
+       mutex_unlock(&radio->lock);
+       dev_err(&radio->usbdev->dev,
+               "%s - usb_control_msg returned %i, request %i\n",
+                       __func__, retval, request);
+       return retval;
+
 }
 
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
 static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
 {
+       int retval;
+       int request;
+
        freq = (freq / 16 * 80) / 1000 + 856;
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_TUNE,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       (freq >> 8) & 0x00ff, freq & 0xff,
-                       radio->transfer_buffer, 8, 300) < 0 ||
-          usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x96, 0xB7, radio->transfer_buffer, 8, 300) < 0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS,
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
-                       0x00, 0x24, radio->transfer_buffer, 8, 300) < 0) {
-               radio->stereo = -1;
-               return -1;
+       mutex_lock(&radio->lock);
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               DSB100_TUNE,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               (freq >> 8) & 0x00ff, freq & 0xff,
+               radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = DSB100_TUNE;
+               goto usb_control_msg_failed;
        }
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               USB_REQ_GET_STATUS,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x96, 0xB7, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = USB_REQ_GET_STATUS;
+               goto usb_control_msg_failed;
+       }
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               USB_REQ_GET_STATUS,
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
+               0x00, 0x24, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
+               request = USB_REQ_GET_STATUS;
+               goto usb_control_msg_failed;
+       }
+
        radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
+       mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
+
+usb_control_msg_failed:
+       radio->stereo = -1;
+       mutex_unlock(&radio->lock);
+       dev_err(&radio->usbdev->dev,
+               "%s - usb_control_msg returned %i, request %i\n",
+                       __func__, retval, request);
+       return retval;
 }
 
 /* return the device status.  This is, in effect, just whether it
 sees a stereo signal or not.  Pity. */
 static void dsbr100_getstat(struct dsbr100_device *radio)
 {
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+       int retval;
+
+       mutex_lock(&radio->lock);
+
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
                USB_REQ_GET_STATUS,
                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-               0x00 , 0x24, radio->transfer_buffer, 8, 300) < 0)
+               0x00 , 0x24, radio->transfer_buffer, 8, 300);
+
+       if (retval < 0) {
                radio->stereo = -1;
-       else
+               dev_err(&radio->usbdev->dev,
+                       "%s - usb_control_msg returned %i, request %i\n",
+                               __func__, retval, USB_REQ_GET_STATUS);
+       } else {
                radio->stereo = !(radio->transfer_buffer[0] & 0x01);
-}
+       }
 
+       mutex_unlock(&radio->lock);
+}
 
 /* USB subsystem interface begins here */
 
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it.  If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it. */
+/*
+ * Handle unplugging of the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_dsbr100_video_device_release
+ */
 static void usb_dsbr100_disconnect(struct usb_interface *intf)
 {
        struct dsbr100_device *radio = usb_get_intfdata(intf);
 
        usb_set_intfdata (intf, NULL);
-       if (radio) {
-               video_unregister_device(radio->videodev);
-               radio->videodev = NULL;
-               if (radio->users) {
-                       kfree(radio->transfer_buffer);
-                       kfree(radio);
-               } else {
-                       radio->removed = 1;
-               }
-       }
+
+       mutex_lock(&radio->lock);
+       radio->removed = 1;
+       mutex_unlock(&radio->lock);
+
+       video_unregister_device(&radio->videodev);
 }
 
 
@@ -276,6 +403,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 {
        struct dsbr100_device *radio = video_drvdata(file);
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        if (v->index > 0)
                return -EINVAL;
 
@@ -297,6 +428,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
+       struct dsbr100_device *radio = video_drvdata(file);
+
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        if (v->index > 0)
                return -EINVAL;
 
@@ -307,9 +444,15 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                                struct v4l2_frequency *f)
 {
        struct dsbr100_device *radio = video_drvdata(file);
+       int retval;
+
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
 
        radio->curfreq = f->frequency;
-       if (dsbr100_setfreq(radio, radio->curfreq) == -1)
+       retval = dsbr100_setfreq(radio, radio->curfreq);
+       if (retval < 0)
                dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
        return 0;
 }
@@ -319,6 +462,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
        struct dsbr100_device *radio = video_drvdata(file);
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        f->type = V4L2_TUNER_RADIO;
        f->frequency = radio->curfreq;
        return 0;
@@ -343,6 +490,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct dsbr100_device *radio = video_drvdata(file);
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                ctrl->value = radio->muted;
@@ -355,17 +506,24 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
                                struct v4l2_control *ctrl)
 {
        struct dsbr100_device *radio = video_drvdata(file);
+       int retval;
+
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value) {
-                       if (dsbr100_stop(radio) == -1) {
+                       retval = dsbr100_stop(radio);
+                       if (retval < 0) {
                                dev_warn(&radio->usbdev->dev,
                                         "Radio did not respond properly\n");
                                return -EBUSY;
                        }
                } else {
-                       if (dsbr100_start(radio) == -1) {
+                       retval = dsbr100_start(radio);
+                       if (retval < 0) {
                                dev_warn(&radio->usbdev->dev,
                                         "Radio did not respond properly\n");
                                return -EBUSY;
@@ -417,7 +575,8 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
        radio->users = 1;
        radio->muted = 1;
 
-       if (dsbr100_start(radio) < 0) {
+       retval = dsbr100_start(radio);
+       if (retval < 0) {
                dev_warn(&radio->usbdev->dev,
                         "Radio did not start up properly\n");
                radio->users = 0;
@@ -426,9 +585,9 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
        }
 
        retval = dsbr100_setfreq(radio, radio->curfreq);
-
-       if (retval == -1)
-               printk(KERN_WARNING KBUILD_MODNAME ": Set frequency failed\n");
+       if (retval < 0)
+               dev_warn(&radio->usbdev->dev,
+                       "set frequency failed\n");
 
        unlock_kernel();
        return 0;
@@ -437,17 +596,62 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
 static int usb_dsbr100_close(struct inode *inode, struct file *file)
 {
        struct dsbr100_device *radio = video_drvdata(file);
+       int retval;
 
        if (!radio)
                return -ENODEV;
+
        radio->users = 0;
-       if (radio->removed) {
-               kfree(radio->transfer_buffer);
-               kfree(radio);
+       if (!radio->removed) {
+               retval = dsbr100_stop(radio);
+               if (retval < 0) {
+                       dev_warn(&radio->usbdev->dev,
+                               "dsbr100_stop failed\n");
+               }
+
        }
        return 0;
 }
 
+/* Suspend device - stop device. */
+static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct dsbr100_device *radio = usb_get_intfdata(intf);
+       int retval;
+
+       retval = dsbr100_stop(radio);
+       if (retval < 0)
+               dev_warn(&intf->dev, "dsbr100_stop failed\n");
+
+       dev_info(&intf->dev, "going into suspend..\n");
+
+       return 0;
+}
+
+/* Resume device - start device. */
+static int usb_dsbr100_resume(struct usb_interface *intf)
+{
+       struct dsbr100_device *radio = usb_get_intfdata(intf);
+       int retval;
+
+       retval = dsbr100_start(radio);
+       if (retval < 0)
+               dev_warn(&intf->dev, "dsbr100_start failed\n");
+
+       dev_info(&intf->dev, "coming out of suspend..\n");
+
+       return 0;
+}
+
+/* free data structures */
+static void usb_dsbr100_video_device_release(struct video_device *videodev)
+{
+       struct dsbr100_device *radio = videodev_to_radio(videodev);
+
+       kfree(radio->transfer_buffer);
+       kfree(radio);
+}
+
 /* File system interface */
 static const struct file_operations usb_dsbr100_fops = {
        .owner          = THIS_MODULE,
@@ -476,19 +680,19 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
 };
 
 /* V4L2 interface */
-static struct video_device dsbr100_videodev_template = {
+static struct video_device dsbr100_videodev_data = {
        .name           = "D-Link DSB-R 100",
        .fops           = &usb_dsbr100_fops,
        .ioctl_ops      = &usb_dsbr100_ioctl_ops,
-       .release        = video_device_release,
+       .release        = usb_dsbr100_video_device_release,
 };
 
-/* check if the device is present and register with v4l and
-usb if it is */
+/* check if the device is present and register with v4l and usb if it is */
 static int usb_dsbr100_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
        struct dsbr100_device *radio;
+       int retval;
 
        radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
 
@@ -501,23 +705,18 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
                kfree(radio);
                return -ENOMEM;
        }
-       radio->videodev = video_device_alloc();
 
-       if (!(radio->videodev)) {
-               kfree(radio->transfer_buffer);
-               kfree(radio);
-               return -ENOMEM;
-       }
-       memcpy(radio->videodev, &dsbr100_videodev_template,
-               sizeof(dsbr100_videodev_template));
+       mutex_init(&radio->lock);
+       radio->videodev = dsbr100_videodev_data;
+
        radio->removed = 0;
        radio->users = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = FREQ_MIN * FREQ_MUL;
-       video_set_drvdata(radio->videodev, radio);
-       if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) {
-               dev_warn(&intf->dev, "Could not register video device\n");
-               video_device_release(radio->videodev);
+       video_set_drvdata(&radio->videodev, radio);
+       retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
+       if (retval < 0) {
+               dev_err(&intf->dev, "couldn't register video device\n");
                kfree(radio->transfer_buffer);
                kfree(radio);
                return -EIO;
index 9305e958fc665399e5dd7454d9b56f5939d76709..dd6d3dfcd7d256bee7f8554175f5ec7b2c7021eb 100644 (file)
@@ -1,7 +1,7 @@
 /* radiotrack (radioreveal) driver for Linux radio support
  * (c) 1997 M. Kirkwood
  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- * Converted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * History:
index 0490a1fa999db04d63a21def52448396b00dfa55..bfd37f38b9ab3ad68df8430d16e6807dbf284654 100644 (file)
@@ -23,7 +23,7 @@
  * 2002-01-17  Adam Belay <ambx1@neo.rr.com>
  *             Updated to latest pnp code
  *
- * 2003-01-31  Alan Cox <alan@redhat.com>
+ * 2003-01-31  Alan Cox <alan@lxorguk.ukuu.org.uk>
  *             Cleaned up locking, delay code, general odds and ends
  *
  * 2006-07-30  Hans J. Koch <koch@hjk-az.de>
index d131a5d381287b0069d4e83dad2615feb115adf7..e13118da307bb313eab757c9cead6046c59aa2ee 100644 (file)
@@ -8,7 +8,7 @@
  *    RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
  *
  *    Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
- *    Converted to new API by Alan Cox <Alan.Cox@linux.org>
+ *    Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * TODO: Allow for more than one of these foolish entities :-)
index 256cbeffdcb6c274a80657fab1eb23f107e0b976..e730eddb2bb5b0077c6c43fb693620262e055f17 100644 (file)
@@ -72,6 +72,11 @@ MODULE_LICENSE("GPL");
 #define USB_AMRADIO_VENDOR 0x07ca
 #define USB_AMRADIO_PRODUCT 0xb800
 
+/* dev_warn macro with driver name */
+#define MR800_DRIVER_NAME "radio-mr800"
+#define amradio_dev_warn(dev, fmt, arg...)                             \
+               dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
+
 /* Probably USB_TIMEOUT should be modified in module parameter */
 #define BUFFER_LENGTH 8
 #define USB_TIMEOUT 500
@@ -154,14 +159,14 @@ MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
 
 /* USB subsystem interface */
 static struct usb_driver usb_amradio_driver = {
-       .name                   = "radio-mr800",
+       .name                   = MR800_DRIVER_NAME,
        .probe                  = usb_amradio_probe,
        .disconnect             = usb_amradio_disconnect,
        .suspend                = usb_amradio_suspend,
        .resume                 = usb_amradio_resume,
        .reset_resume           = usb_amradio_resume,
        .id_table               = usb_amradio_device_table,
-       .supports_autosuspend   = 1,
+       .supports_autosuspend   = 0,
 };
 
 /* switch on radio. Send 8 bytes to device. */
@@ -202,6 +207,10 @@ static int amradio_stop(struct amradio_device *radio)
        int retval;
        int size;
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        mutex_lock(&radio->lock);
 
        radio->buffer[0] = 0x00;
@@ -235,6 +244,10 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
        int size;
        unsigned short freq_send = 0x13 + (freq >> 3) / 25;
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        mutex_lock(&radio->lock);
 
        radio->buffer[0] = 0x00;
@@ -288,18 +301,12 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
 {
        struct amradio_device *radio = usb_get_intfdata(intf);
 
-       usb_set_intfdata(intf, NULL);
+       mutex_lock(&radio->lock);
+       radio->removed = 1;
+       mutex_unlock(&radio->lock);
 
-       if (radio) {
-               video_unregister_device(radio->videodev);
-               radio->videodev = NULL;
-               if (radio->users) {
-                       kfree(radio->buffer);
-                       kfree(radio);
-               } else {
-                       radio->removed = 1;
-               }
-       }
+       usb_set_intfdata(intf, NULL);
+       video_unregister_device(radio->videodev);
 }
 
 /* vidioc_querycap - query device capabilities */
@@ -320,6 +327,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        if (v->index > 0)
                return -EINVAL;
 
@@ -346,6 +357,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 static int vidioc_s_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
+       struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        if (v->index > 0)
                return -EINVAL;
        return 0;
@@ -357,9 +374,14 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        radio->curfreq = f->frequency;
        if (amradio_setfreq(radio, radio->curfreq) < 0)
-               warn("Set frequency failed");
+               amradio_dev_warn(&radio->videodev->dev,
+                       "set frequency failed\n");
        return 0;
 }
 
@@ -369,6 +391,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        f->type = V4L2_TUNER_RADIO;
        f->frequency = radio->curfreq;
        return 0;
@@ -382,8 +408,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
                if (qc->id && qc->id == radio_qctrl[i].id) {
-                       memcpy(qc, &(radio_qctrl[i]),
-                                               sizeof(*qc));
+                       memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
                        return 0;
                }
        }
@@ -396,6 +421,10 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                ctrl->value = radio->muted;
@@ -410,16 +439,22 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
 
+       /* safety check */
+       if (radio->removed)
+               return -EIO;
+
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                if (ctrl->value) {
                        if (amradio_stop(radio) < 0) {
-                               warn("amradio_stop() failed");
+                               amradio_dev_warn(&radio->videodev->dev,
+                                       "amradio_stop failed\n");
                                return -1;
                        }
                } else {
                        if (amradio_start(radio) < 0) {
-                               warn("amradio_start() failed");
+                               amradio_dev_warn(&radio->videodev->dev,
+                                       "amradio_start failed\n");
                                return -1;
                        }
                }
@@ -475,30 +510,38 @@ static int usb_amradio_open(struct inode *inode, struct file *file)
        radio->muted = 1;
 
        if (amradio_start(radio) < 0) {
-               warn("Radio did not start up properly");
+               amradio_dev_warn(&radio->videodev->dev,
+                       "radio did not start up properly\n");
                radio->users = 0;
                unlock_kernel();
                return -EIO;
        }
        if (amradio_setfreq(radio, radio->curfreq) < 0)
-               warn("Set frequency failed");
+               amradio_dev_warn(&radio->videodev->dev,
+                       "set frequency failed\n");
 
        unlock_kernel();
        return 0;
 }
 
-/*close device - free driver structures */
+/*close device */
 static int usb_amradio_close(struct inode *inode, struct file *file)
 {
        struct amradio_device *radio = video_get_drvdata(video_devdata(file));
+       int retval;
 
        if (!radio)
                return -ENODEV;
+
        radio->users = 0;
-       if (radio->removed) {
-               kfree(radio->buffer);
-               kfree(radio);
+
+       if (!radio->removed) {
+               retval = amradio_stop(radio);
+               if (retval < 0)
+                       amradio_dev_warn(&radio->videodev->dev,
+                               "amradio_stop failed\n");
        }
+
        return 0;
 }
 
@@ -508,9 +551,9 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
        struct amradio_device *radio = usb_get_intfdata(intf);
 
        if (amradio_stop(radio) < 0)
-               warn("amradio_stop() failed");
+               dev_warn(&intf->dev, "amradio_stop failed\n");
 
-       info("radio-mr800: Going into suspend..");
+       dev_info(&intf->dev, "going into suspend..\n");
 
        return 0;
 }
@@ -521,9 +564,9 @@ static int usb_amradio_resume(struct usb_interface *intf)
        struct amradio_device *radio = usb_get_intfdata(intf);
 
        if (amradio_start(radio) < 0)
-               warn("amradio_start() failed");
+               dev_warn(&intf->dev, "amradio_start failed\n");
 
-       info("radio-mr800: Coming out of suspend..");
+       dev_info(&intf->dev, "coming out of suspend..\n");
 
        return 0;
 }
@@ -555,12 +598,24 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
        .vidioc_s_input     = vidioc_s_input,
 };
 
+static void usb_amradio_device_release(struct video_device *videodev)
+{
+       struct amradio_device *radio = video_get_drvdata(videodev);
+
+       /* we call v4l to free radio->videodev */
+       video_device_release(videodev);
+
+       /* free rest memory */
+       kfree(radio->buffer);
+       kfree(radio);
+}
+
 /* V4L2 interface */
 static struct video_device amradio_videodev_template = {
        .name           = "AverMedia MR 800 USB FM Radio",
        .fops           = &usb_amradio_fops,
        .ioctl_ops      = &usb_amradio_ioctl_ops,
-       .release        = video_device_release,
+       .release        = usb_amradio_device_release,
 };
 
 /* check if the device is present and register with v4l and
@@ -602,7 +657,7 @@ static int usb_amradio_probe(struct usb_interface *intf,
 
        video_set_drvdata(radio->videodev, radio);
        if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
-               warn("Could not register video device");
+               dev_warn(&intf->dev, "could not register video device\n");
                video_device_release(radio->videodev);
                kfree(radio->buffer);
                kfree(radio);
@@ -617,9 +672,13 @@ static int __init amradio_init(void)
 {
        int retval = usb_register(&usb_amradio_driver);
 
-       info(DRIVER_VERSION " " DRIVER_DESC);
+       pr_info(KBUILD_MODNAME
+               ": version " DRIVER_VERSION " " DRIVER_DESC "\n");
+
        if (retval)
-               err("usb_register failed. Error number %d", retval);
+               pr_err(KBUILD_MODNAME
+                       ": usb_register failed. Error number %d\n", retval);
+
        return retval;
 }
 
index a67079777419571e875100f6d488e9c0178d939c..7704f243b6f0cf99c3fb05e4f249de2ed1147ae3 100644 (file)
@@ -1,7 +1,7 @@
 /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
  *
  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
- * Converted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
  *
  * TODO: Allow for more than one of these foolish entities :-)
index 329c90bddadd953836b25cd10dd9668bf2e99329..834d43651c70fc1017ee65fa371ef3e18c86d11f 100644 (file)
@@ -3,7 +3,7 @@
  * (c) 1997 M. Kirkwood
  * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
  *
- * Fitted to new interface by Alan Cox <alan.cox@linux.org>
+ * Fitted to new interface by Alan Cox <alan@lxorguk.ukuu.org.uk>
  * Made working and cleaned up functions <mikael.hedin@irf.se>
  * Support for ISAPnP by Ladislav Michl <ladis@psi.cz>
  *
index 057fd7e160c41f8ddb657dbbb499fdcda6e2bb06..19cf3b8f67c45213c9cb4dc2f7b887f27b102d1c 100644 (file)
@@ -184,7 +184,7 @@ config VIDEO_MSP3400
 
 config VIDEO_CS5345
        tristate "Cirrus Logic CS5345 audio ADC"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Cirrus Logic CS5345 24-bit, 192 kHz
          stereo A/D converter.
@@ -204,7 +204,7 @@ config VIDEO_CS53L32A
 
 config VIDEO_M52790
        tristate "Mitsubishi M52790 A/V switch"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
         Support for the Mitsubishi M52790 A/V switch.
 
@@ -242,7 +242,7 @@ config VIDEO_WM8739
 
 config VIDEO_VP27SMPX
        tristate "Panasonic VP27s internal MPX"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the internal MPX of the Panasonic VP27s tuner.
 
@@ -361,6 +361,17 @@ config VIDEO_SAA7191
          To compile this driver as a module, choose M here: the
          module will be called saa7191.
 
+config VIDEO_TVP514X
+       tristate "Texas Instruments TVP514x video decoder"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the TI TVP5146/47
+         decoder. It is currently working with the TI OMAP3 camera
+         controller.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tvp514x.
+
 config VIDEO_TVP5150
        tristate "Texas Instruments TVP5150 video decoder"
        depends on VIDEO_V4L2 && I2C
@@ -387,7 +398,7 @@ comment "MPEG video encoders"
 
 config VIDEO_CX2341X
        tristate "Conexant CX2341x MPEG encoders"
-       depends on VIDEO_V4L2 && EXPERIMENTAL && VIDEO_V4L2_COMMON
+       depends on VIDEO_V4L2 && VIDEO_V4L2_COMMON
        ---help---
          Support for the Conexant CX23416 MPEG encoders
          and CX23415 MPEG encoder/decoders.
@@ -725,10 +736,16 @@ config MT9M001_PCA9536_SWITCH
          extender to switch between 8 and 10 bit datawidth modes
 
 config SOC_CAMERA_MT9M111
-       tristate "mt9m111 support"
+       tristate "mt9m111 and mt9m112 support"
+       depends on SOC_CAMERA && I2C
+       help
+         This driver supports MT9M111 and MT9M112 cameras from Micron
+
+config SOC_CAMERA_MT9T031
+       tristate "mt9t031 support"
        depends on SOC_CAMERA && I2C
        help
-         This driver supports MT9M111 cameras from Micron
+         This driver supports MT9T031 cameras from Micron.
 
 config SOC_CAMERA_MT9V022
        tristate "mt9v022 support"
@@ -744,12 +761,24 @@ config MT9V022_PCA9536_SWITCH
          Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
          extender to switch between 8 and 10 bit datawidth modes
 
+config SOC_CAMERA_TW9910
+       tristate "tw9910 support"
+       depends on SOC_CAMERA && I2C
+       help
+         This is a tw9910 video driver
+
 config SOC_CAMERA_PLATFORM
        tristate "platform camera support"
        depends on SOC_CAMERA
        help
          This is a generic SoC camera platform driver, useful for testing
 
+config SOC_CAMERA_OV772X
+       tristate "ov772x camera support"
+       depends on SOC_CAMERA && I2C
+       help
+         This is a ov772x camera driver
+
 config VIDEO_PXA27x
        tristate "PXA27x Quick Capture Interface driver"
        depends on VIDEO_DEV && PXA27x && SOC_CAMERA
@@ -764,6 +793,13 @@ config VIDEO_SH_MOBILE_CEU
        ---help---
          This is a v4l2 driver for the SuperH Mobile CEU Interface
 
+config VIDEO_OMAP2
+       tristate "OMAP2 Camera Capture Interface driver"
+       depends on VIDEO_DEV && ARCH_OMAP2
+       select VIDEOBUF_DMA_SG
+       ---help---
+         This is a v4l2 driver for the TI OMAP2 camera capture interface
+
 #
 # USB Multimedia device configuration
 #
index 16962f3aa15767f09d71ffaa492e2d6f3db562c4..1611c33b1aee3593d9a15515a35c971179101d5b 100644 (file)
@@ -8,9 +8,11 @@ msp3400-objs   :=      msp3400-driver.o msp3400-kthreads.o
 
 stkwebcam-objs :=      stk-webcam.o stk-sensor.o
 
-videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o
+omap2cam-objs  :=      omap24xxcam.o omap24xxcam-dma.o
 
-obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o
+videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
+
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-compat-ioctl32.o v4l2-int-device.o
 
 obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
 
@@ -25,6 +27,7 @@ obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
+obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
 
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
@@ -66,6 +69,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
 obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
@@ -129,11 +133,15 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 obj-$(CONFIG_VIDEO_PXA27x)     += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
+obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
 obj-$(CONFIG_SOC_CAMERA)       += soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
 obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
 obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
+obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
index e09b006932308b81e3940dd204226538ac88afbc..2ba6abd92b6f2932f4dd4c0e9ff3317ca224971c 100644 (file)
@@ -396,8 +396,7 @@ out_up:
        return ret;
 }
 
-static int ar_do_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, void *arg)
+static int ar_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
        struct ar_device *ar = video_get_drvdata(dev);
@@ -543,7 +542,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
 static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                    unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, ar_do_ioctl);
+       return video_usercopy(file, cmd, arg, ar_do_ioctl);
 }
 
 #if USE_INT
diff --git a/drivers/media/video/bt8xx/bt832.c b/drivers/media/video/bt8xx/bt832.c
deleted file mode 100644 (file)
index 216fc96..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/* Driver for Bt832 CMOS Camera Video Processor
-    i2c-addresses: 0x88 or 0x8a
-
-  The BT832 interfaces to a Quartzsight Digital Camera (352x288, 25 or 30 fps)
-  via a 9 pin connector ( 4-wire SDATA, 2-wire i2c, SCLK, VCC, GND).
-  It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
-  connected to bt848/bt878 GPIO pins on this purpose.
-  (see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
-
-  Supported Cards:
-  -  Pixelview Rev.4E: 0x8a
-               GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
-
-  (c) Gunther Mayer, 2002
-
-  STATUS:
-  - detect chip and hexdump
-  - reset chip and leave low power mode
-  - detect camera present
-
-  TODO:
-  - make it work (find correct setup for Bt832 and Bt878)
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/types.h>
-#include <linux/videodev.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-
-#include "bttv.h"
-#include "bt832.h"
-
-MODULE_LICENSE("GPL");
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { I2C_ADDR_BT832_ALT1>>1, I2C_ADDR_BT832_ALT2>>1,
-                                      I2C_CLIENT_END };
-I2C_CLIENT_INSMOD;
-
-int debug;    /* debug output */
-module_param(debug,            int, 0644);
-
-/* ---------------------------------------------------------------------- */
-
-static int bt832_detach(struct i2c_client *client);
-
-
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-struct bt832 {
-       struct i2c_client client;
-};
-
-int bt832_hexdump(struct i2c_client *i2c_client_s, unsigned char *buf)
-{
-       int i,rc;
-       buf[0]=0x80; // start at register 0 with auto-increment
-       if (1 != (rc = i2c_master_send(i2c_client_s,buf,1)))
-               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 1)\n",rc);
-
-       for(i=0;i<65;i++)
-               buf[i]=0;
-       if (65 != (rc=i2c_master_recv(i2c_client_s,buf,65)))
-               v4l_err(i2c_client_s,"i2c i/o error: rc == %d (should be 65)\n",rc);
-
-       // Note: On READ the first byte is the current index
-       //  (e.g. 0x80, what we just wrote)
-
-       if(debug>1) {
-               int i;
-               v4l_dbg(2, debug,i2c_client_s,"hexdump:");
-               for(i=1;i<65;i++) {
-                       if(i!=1) {
-                               if(((i-1)%8)==0) printk(" ");
-                               if(((i-1)%16)==0) {
-                                       printk("\n");
-                                       v4l_dbg(2, debug,i2c_client_s,"hexdump:");
-                               }
-                       }
-                       printk(" %02x",buf[i]);
-               }
-               printk("\n");
-       }
-       return 0;
-}
-
-// Return: 1 (is a bt832), 0 (No bt832 here)
-int bt832_init(struct i2c_client *i2c_client_s)
-{
-       unsigned char *buf;
-       int rc;
-
-       buf=kmalloc(65,GFP_KERNEL);
-       if (!buf) {
-               v4l_err(&t->client,
-                       "Unable to allocate memory. Detaching.\n");
-               return 0;
-       }
-       bt832_hexdump(i2c_client_s,buf);
-
-       if(buf[0x40] != 0x31) {
-               v4l_err(i2c_client_s,"This i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
-               kfree(buf);
-               return 0;
-       }
-
-       v4l_err(i2c_client_s,"Write 0 tp VPSTATUS\n");
-       buf[0]=BT832_VP_STATUS; // Reg.52
-       buf[1]= 0x00;
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-
-       // Leave low power mode:
-       v4l_err(i2c_client_s,"leave low power mode.\n");
-       buf[0]=BT832_CAM_SETUP0; //0x39 57
-       buf[1]=0x08;
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error LLPM: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-       v4l_info(i2c_client_s,"Write 0 tp VPSTATUS\n");
-       buf[0]=BT832_VP_STATUS; // Reg.52
-       buf[1]= 0x00;
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error VPS: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-
-       // Enable Output
-       v4l_info(i2c_client_s,"Enable Output\n");
-       buf[0]=BT832_VP_CONTROL1; // Reg.40
-       buf[1]= 0x27 & (~0x01); // Default | !skip
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_err(i2c_client_s,"i2c i/o error EO: rc == %d (should be 2)\n",rc);
-
-       bt832_hexdump(i2c_client_s,buf);
-
-
-       // for testing (even works when no camera attached)
-       v4l_info(i2c_client_s,"*** Generate NTSC M Bars *****\n");
-       buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
-       buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
-       if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
-               v4l_info(i2c_client_s,"i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
-
-       v4l_info(i2c_client_s,"Camera Present: %s\n",
-               (buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
-
-       bt832_hexdump(i2c_client_s,buf);
-       kfree(buf);
-       return 1;
-}
-
-
-
-static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-       struct bt832 *t;
-
-       client_template.adapter = adap;
-       client_template.addr    = addr;
-
-       if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
-               return -ENOMEM;
-       t->client = client_template;
-       i2c_set_clientdata(&t->client, t);
-       i2c_attach_client(&t->client);
-
-       v4l_info(&t->client,"chip found @ 0x%x\n", addr<<1);
-
-       if(! bt832_init(&t->client)) {
-               bt832_detach(&t->client);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int bt832_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, bt832_attach);
-       return 0;
-}
-
-static int bt832_detach(struct i2c_client *client)
-{
-       struct bt832 *t = i2c_get_clientdata(client);
-
-       v4l_info(&t->client,"dettach\n");
-       i2c_detach_client(client);
-       kfree(t);
-       return 0;
-}
-
-static int
-bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-       struct bt832 *t = i2c_get_clientdata(client);
-
-       if (debug>1)
-               v4l_i2c_print_ioctl(&t->client,cmd);
-
-       switch (cmd) {
-               case BT832_HEXDUMP: {
-                       unsigned char *buf;
-                       buf = kmalloc(65, GFP_KERNEL);
-                       if (!buf) {
-                               v4l_err(&t->client,
-                                       "Unable to allocate memory\n");
-                               break;
-                       }
-                       bt832_hexdump(&t->client,buf);
-                       kfree(buf);
-               }
-               break;
-               case BT832_REATTACH:
-                       v4l_info(&t->client,"re-attach\n");
-                       i2c_del_driver(&driver);
-                       i2c_add_driver(&driver);
-               break;
-       }
-       return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "bt832",
-       },
-       .id             = 0, /* FIXME */
-       .attach_adapter = bt832_probe,
-       .detach_client  = bt832_detach,
-       .command        = bt832_command,
-};
-static struct i2c_client client_template =
-{
-       .name       = "bt832",
-       .driver     = &driver,
-};
-
-
-static int __init bt832_init_module(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit bt832_cleanup_module(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(bt832_init_module);
-module_exit(bt832_cleanup_module);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bt8xx/bt832.h b/drivers/media/video/bt8xx/bt832.h
deleted file mode 100644 (file)
index 1ce8fa7..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/* Bt832 CMOS Camera Video Processor (VP)
-
- The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
-  color digital camera directly to video capture devices via an 8-bit,
-  4:2:2 YUV or YCrCb video interface.
-
- i2c addresses: 0x88 or 0x8a
- */
-
-/* The 64 registers: */
-
-// Input Processor
-#define BT832_OFFSET 0
-#define BT832_RCOMP    1
-#define BT832_G1COMP   2
-#define BT832_G2COMP   3
-#define BT832_BCOMP    4
-// Exposures:
-#define BT832_FINEH    5
-#define BT832_FINEL    6
-#define BT832_COARSEH  7
-#define BT832_COARSEL   8
-#define BT832_CAMGAIN  9
-// Main Processor:
-#define BT832_M00      10
-#define BT832_M01      11
-#define BT832_M02      12
-#define BT832_M10      13
-#define BT832_M11      14
-#define BT832_M12      15
-#define BT832_M20      16
-#define BT832_M21      17
-#define BT832_M22      18
-#define BT832_APCOR    19
-#define BT832_GAMCOR   20
-// Level Accumulator Inputs
-#define BT832_VPCONTROL2       21
-#define BT832_ZONECODE0        22
-#define BT832_ZONECODE1        23
-#define BT832_ZONECODE2        24
-#define BT832_ZONECODE3        25
-// Level Accumulator Outputs:
-#define BT832_RACC     26
-#define BT832_GACC     27
-#define BT832_BACC     28
-#define BT832_BLACKACC 29
-#define BT832_EXP_AGC  30
-#define BT832_LACC0    31
-#define BT832_LACC1    32
-#define BT832_LACC2    33
-#define BT832_LACC3    34
-#define BT832_LACC4    35
-#define BT832_LACC5    36
-#define BT832_LACC6    37
-#define BT832_LACC7    38
-// System:
-#define BT832_VP_CONTROL0      39
-#define BT832_VP_CONTROL1      40
-#define BT832_THRESH   41
-#define BT832_VP_TESTCONTROL0  42
-#define BT832_VP_DMCODE        43
-#define BT832_ACB_CONFIG       44
-#define BT832_ACB_GNBASE       45
-#define BT832_ACB_MU   46
-#define BT832_CAM_TEST0        47
-#define BT832_AEC_CONFIG       48
-#define BT832_AEC_TL   49
-#define BT832_AEC_TC   50
-#define BT832_AEC_TH   51
-// Status:
-#define BT832_VP_STATUS        52
-#define BT832_VP_LINECOUNT     53
-#define BT832_CAM_DEVICEL      54 // e.g. 0x19
-#define BT832_CAM_DEVICEH      55 // e.g. 0x40  == 0x194 Mask0, 0x194 = 404 decimal (VVL-404 camera)
-#define BT832_CAM_STATUS               56
- #define BT832_56_CAMERA_PRESENT 0x20
-//Camera Setups:
-#define BT832_CAM_SETUP0       57
-#define BT832_CAM_SETUP1       58
-#define BT832_CAM_SETUP2       59
-#define BT832_CAM_SETUP3       60
-// System:
-#define BT832_DEFCOR           61
-#define BT832_VP_TESTCONTROL1  62
-#define BT832_DEVICE_ID                63
-# define BT832_DEVICE_ID__31           0x31 // Bt832 has ID 0x31
-
-/* STMicroelectronivcs VV5404 camera module
-   i2c: 0x20: sensor address
-   i2c: 0xa0: eeprom for ccd defect map
- */
-#define VV5404_device_h                0x00  // 0x19
-#define VV5404_device_l                0x01  // 0x40
-#define VV5404_status0         0x02
-#define VV5404_linecountc      0x03 // current line counter
-#define VV5404_linecountl      0x04
-#define VV5404_setup0          0x10
-#define VV5404_setup1          0x11
-#define VV5404_setup2          0x12
-#define VV5404_setup4          0x14
-#define VV5404_setup5          0x15
-#define VV5404_fine_h          0x20  // fine exposure
-#define VV5404_fine_l          0x21
-#define VV5404_coarse_h                0x22  //coarse exposure
-#define VV5404_coarse_l                0x23
-#define VV5404_gain            0x24 // ADC pre-amp gain setting
-#define VV5404_clk_div         0x25
-#define VV5404_cr              0x76 // control register
-#define VV5404_as0             0x77 // ADC setup register
-
-
-// IOCTL
-#define BT832_HEXDUMP   _IOR('b',1,int)
-#define BT832_REATTACH _IOR('b',2,int)
-
-/* from BT8x8VXD/capdrv/dialogs.cpp */
-
-/*
-typedef enum { SVI, Logitech, Rockwell } CAMERA;
-
-static COMBOBOX_ENTRY gwCameraOptions[] =
-{
-   { SVI,      "Silicon Vision 512N" },
-   { Logitech, "Logitech VideoMan 1.3"  },
-   { Rockwell, "Rockwell QuartzSight PCI 1.0"   }
-};
-
-// SRAM table values
-//===========================================================================
-typedef enum { TGB_NTSC624, TGB_NTSC780, TGB_NTSC858, TGB_NTSC392 } TimeGenByte;
-
-BYTE SRAMTable[][ 60 ] =
-{
-   // TGB_NTSC624
-   {
-      0x33, // size of table = 51
-      0x0E, 0xC0, 0x00, 0x00, 0x90, 0x02, 0x03, 0x10, 0x03, 0x06,
-      0x10, 0x04, 0x12, 0x12, 0x05, 0x02, 0x13, 0x04, 0x19, 0x00,
-      0x04, 0x39, 0x00, 0x06, 0x59, 0x08, 0x03, 0x85, 0x08, 0x07,
-      0x03, 0x50, 0x00, 0x91, 0x40, 0x00, 0x11, 0x01, 0x01, 0x4D,
-      0x0D, 0x02, 0x03, 0x11, 0x01, 0x05, 0x37, 0x00, 0x37, 0x21, 0x00
-   },
-   // TGB_NTSC780
-   {
-      0x33, // size of table = 51
-      0x0e, 0xc0, 0x00, 0x00, 0x90, 0xe2, 0x03, 0x10, 0x03, 0x06,
-      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
-      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x85, 0x08, 0x97,
-      0x03, 0x50, 0x50, 0xaf, 0x40, 0x30, 0x5f, 0x01, 0xf1, 0x7f,
-      0x0d, 0xf2, 0x03, 0x11, 0xf1, 0x05, 0x37, 0x30, 0x85, 0x21, 0x50
-   },
-   // TGB_NTSC858
-   {
-      0x33, // size of table = 51
-      0x0c, 0xc0, 0x00, 0x00, 0x90, 0xc2, 0x03, 0x10, 0x03, 0x06,
-      0x10, 0x34, 0x12, 0x12, 0x65, 0x02, 0x13, 0x24, 0x19, 0x00,
-      0x24, 0x39, 0x00, 0x96, 0x59, 0x08, 0x93, 0x83, 0x08, 0x97,
-      0x03, 0x50, 0x30, 0xc0, 0x40, 0x30, 0x86, 0x01, 0x01, 0xa6,
-      0x0d, 0x62, 0x03, 0x11, 0x61, 0x05, 0x37, 0x30, 0xac, 0x21, 0x50
-   },
-   // TGB_NTSC392
-   // This table has been modified to be used for Fusion Rev D
-   {
-      0x2A, // size of table = 42
-      0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
-      0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
-      0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
-      0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
-      0x20, 0x00
-   }
-};
-
-//===========================================================================
-// This is the structure of the camera specifications
-//===========================================================================
-typedef struct tag_cameraSpec
-{
-   SignalFormat signal;       // which digital signal format the camera has
-   VideoFormat  vidFormat;    // video standard
-   SyncVideoRef syncRef;      // which sync video reference is used
-   State        syncOutput;   // enable sync output for sync video input?
-   DecInputClk  iClk;         // which input clock is used
-   TimeGenByte  tgb;          // which timing generator byte does the camera use
-   int          HReset;       // select 64, 48, 32, or 16 CLKx1 for HReset
-   PLLFreq      pllFreq;      // what synthesized frequency to set PLL to
-   VSIZEPARMS   vSize;        // video size the camera produces
-   int          lineCount;    // expected total number of half-line per frame - 1
-   BOOL         interlace;    // interlace signal?
-} CameraSpec;
-
-//===========================================================================
-// <UPDATE REQUIRED>
-// Camera specifications database. Update this table whenever camera spec
-// has been changed or added/deleted supported camera models
-//===========================================================================
-static CameraSpec dbCameraSpec[ N_CAMERAOPTIONS ] =
-{  // Silicon Vision 512N
-   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC624, 64, KHz19636,
-      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
-   {         512,           0x64,       480,    0x13,      240 },         0,       TRUE
-   },
-   // Logitech VideoMan 1.3
-   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC780, 64, KHz24545,
-      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
-      {      640,           0x80,       480,    0x1A,      240 },         0,       TRUE
-   },
-   // Rockwell QuartzSight
-   // Note: Fusion Rev D (rev ID 0x02) and later supports 16 pixels for HReset which is preferable.
-   //       Use 32 for earlier version of hardware. Clkx1_HDELAY also changed from 0x27 to 0x20.
-   { Signal_CCIR656, VFormat_NTSC, VRef_alignedCb, Off, DecClk_GPCLK, TGB_NTSC392, 16, KHz28636,
-      // Clkx1_HACTIVE, Clkx1_HDELAY, VActive, VDelay, linesPerField; lineCount, Interlace
-      {      352,           0x20,       576,    0x08,      288 },       607,       FALSE
-   }
-};
-*/
-
-/*
-The corresponding APIs required to be invoked are:
-SetConnector( ConCamera, TRUE/FALSE );
-SetSignalFormat( spec.signal );
-SetVideoFormat( spec.vidFormat );
-SetSyncVideoRef( spec.syncRef );
-SetEnableSyncOutput( spec.syncOutput );
-SetTimGenByte( SRAMTable[ spec.tgb ], SRAMTableSize[ spec.tgb ] );
-SetHReset( spec.HReset );
-SetPLL( spec.pllFreq );
-SetDecInputClock( spec.iClk );
-SetVideoInfo( spec.vSize );
-SetTotalLineCount( spec.lineCount );
-SetInterlaceMode( spec.interlace );
-*/
-
-/* from web:
- Video Sampling
-Digital video is a sampled form of analog video. The most common sampling schemes in use today are:
-                 Pixel Clock   Horiz    Horiz    Vert
-                  Rate         Total    Active
-NTSC square pixel  12.27 MHz    780      640      525
-NTSC CCIR-601      13.5  MHz    858      720      525
-NTSC 4FSc          14.32 MHz    910      768      525
-PAL  square pixel  14.75 MHz    944      768      625
-PAL  CCIR-601      13.5  MHz    864      720      625
-PAL  4FSc          17.72 MHz   1135      948      625
-
-For the CCIR-601 standards, the sampling is based on a static orthogonal sampling grid. The luminance component (Y) is sampled at 13.5 MHz, while the two color difference signals, Cr and Cb are sampled at half that, or 6.75 MHz. The Cr and Cb samples are colocated with alternate Y samples, and they are taken at the same position on each line, such that one sample is coincident with the 50% point of the falling edge of analog sync. The samples are coded to either 8 or 10 bits per component.
-*/
-
-/* from DScaler:*/
-/*
-//===========================================================================
-// CCIR656 Digital Input Support: The tables were taken from DScaler proyect
-//
-// 13 Dec 2000 - Michael Eskin, Conexant Systems - Initial version
-//
-
-//===========================================================================
-// Timing generator SRAM table values for CCIR601 720x480 NTSC
-//===========================================================================
-// For NTSC CCIR656
-BYTE BtCard::SRAMTable_NTSC[] =
-{
-    // SRAM Timing Table for NTSC
-    0x0c, 0xc0, 0x00,
-    0x00, 0x90, 0xc2,
-    0x03, 0x10, 0x03,
-    0x06, 0x10, 0x34,
-    0x12, 0x12, 0x65,
-    0x02, 0x13, 0x24,
-    0x19, 0x00, 0x24,
-    0x39, 0x00, 0x96,
-    0x59, 0x08, 0x93,
-    0x83, 0x08, 0x97,
-    0x03, 0x50, 0x30,
-    0xc0, 0x40, 0x30,
-    0x86, 0x01, 0x01,
-    0xa6, 0x0d, 0x62,
-    0x03, 0x11, 0x61,
-    0x05, 0x37, 0x30,
-    0xac, 0x21, 0x50
-};
-
-//===========================================================================
-// Timing generator SRAM table values for CCIR601 720x576 NTSC
-//===========================================================================
-// For PAL CCIR656
-BYTE BtCard::SRAMTable_PAL[] =
-{
-    // SRAM Timing Table for PAL
-    0x36, 0x11, 0x01,
-    0x00, 0x90, 0x02,
-    0x05, 0x10, 0x04,
-    0x16, 0x14, 0x05,
-    0x11, 0x00, 0x04,
-    0x12, 0xc0, 0x00,
-    0x31, 0x00, 0x06,
-    0x51, 0x08, 0x03,
-    0x89, 0x08, 0x07,
-    0xc0, 0x44, 0x00,
-    0x81, 0x01, 0x01,
-    0xa9, 0x0d, 0x02,
-    0x02, 0x50, 0x03,
-    0x37, 0x3d, 0x00,
-    0xaf, 0x21, 0x00,
-};
-*/
index 13742b0bbe3e10d61fa4970a445dd749a3702850..d24dcc025e3714ff7c866fdff03cbd73fe9cbd6a 100644 (file)
@@ -44,7 +44,6 @@
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
-static void boot_bt832(struct bttv *btv);
 static void hauppauge_eeprom(struct bttv *btv);
 static void avermedia_eeprom(struct bttv *btv);
 static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
@@ -2217,9 +2216,9 @@ struct tvcard bttv_tvcards[] = {
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
-       [BTTV_BOARD_VD009X1_MINIDIN] = {
+       [BTTV_BOARD_VD009X1_VD011_MINIDIN] = {
                /* M.Klahr@phytec.de */
-               .name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
+               .name           = "PHYTEC VD-009-X1 VD-011 MiniDIN (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
                .tuner          = UNSET, /* card has no tuner */
@@ -2227,14 +2226,14 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask       = 0x00,
                .muxsel         = { 2, 3, 1, 0 },
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-               .needs_tvaudio  = 1,
+               .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
        },
-       [BTTV_BOARD_VD009X1_COMBI] = {
-               .name           = "PHYTEC VD-009-X1 Combi (bt878)",
+       [BTTV_BOARD_VD009X1_VD011_COMBI] = {
+               .name           = "PHYTEC VD-009-X1 VD-011 Combi (bt878)",
                .video_inputs   = 4,
                .audio_inputs   = 0,
                .tuner          = UNSET, /* card has no tuner */
@@ -2242,7 +2241,7 @@ struct tvcard bttv_tvcards[] = {
                .gpiomask       = 0x00,
                .muxsel         = { 2, 3, 1, 1 },
                .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
-               .needs_tvaudio  = 1,
+               .needs_tvaudio  = 0,
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
@@ -3061,6 +3060,54 @@ struct tvcard bttv_tvcards[] = {
                .pll            = PLL_28,
                .has_radio      = 1,
                .has_remote     = 1,
+       },
+               [BTTV_BOARD_VD012] = {
+               /* D.Heer@Phytec.de */
+               .name           = "PHYTEC VD-012 (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = UNSET, /* card has no tuner */
+               .svhs           = UNSET, /* card has no s-video */
+               .gpiomask       = 0x00,
+               .muxsel         = { 0, 2, 3, 1 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               [BTTV_BOARD_VD012_X1] = {
+               /* D.Heer@Phytec.de */
+               .name           = "PHYTEC VD-012-X1 (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = UNSET, /* card has no tuner */
+               .svhs           = 3,
+               .gpiomask       = 0x00,
+               .muxsel         = { 2, 3, 1 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+               [BTTV_BOARD_VD012_X2] = {
+               /* D.Heer@Phytec.de */
+               .name           = "PHYTEC VD-012-X2 (bt878)",
+               .video_inputs   = 4,
+               .audio_inputs   = 0,
+               .tuner          = UNSET, /* card has no tuner */
+               .svhs           = 3,
+               .gpiomask       = 0x00,
+               .muxsel         = { 3, 2, 1 },
+               .gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
+               .needs_tvaudio  = 0,
+               .pll            = PLL_28,
+               .tuner_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
        }
 };
 
@@ -3673,13 +3720,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
        if (bttv_tvcards[btv->c.type].audio_mode_gpio)
                btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
 
-       if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
-               /* detect Bt832 chip for quartzsight digital camera */
-               if ((bttv_I2CRead(btv, I2C_ADDR_BT832_ALT1, "Bt832") >=0) ||
-                   (bttv_I2CRead(btv, I2C_ADDR_BT832_ALT2, "Bt832") >=0))
-                       boot_bt832(btv);
-       }
-
        if (!autoload)
                return;
 
@@ -4075,10 +4115,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
                       "init [%d]\n", btv->c.nr, pin);
 }
 
-static void __devinit boot_bt832(struct bttv *btv)
-{
-}
-
 /* ----------------------------------------------------------------------- */
 /*  Imagenation L-Model PXC200 Framegrabber */
 /*  This is basically the same procedure as
index dce6dae5740efa55586cd9bf88e24a675e0cd41e..74c325e594a2eaf3509b139ef6b46a7a2f4d242a 100644 (file)
@@ -42,7 +42,7 @@ static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
        struct bttv_sub_driver *sub = to_bttv_sub_drv(drv);
        int len = strlen(sub->wanted);
 
-       if (0 == strncmp(dev->bus_id, sub->wanted, len))
+       if (0 == strncmp(dev_name(dev), sub->wanted, len))
                return 1;
        return 0;
 }
@@ -91,15 +91,14 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
        sub->dev.parent  = &core->pci->dev;
        sub->dev.bus     = &bttv_sub_bus_type;
        sub->dev.release = release_sub_device;
-       snprintf(sub->dev.bus_id,sizeof(sub->dev.bus_id),"%s%d",
-                name, core->nr);
+       dev_set_name(&sub->dev, "%s%d", name, core->nr);
 
        err = device_register(&sub->dev);
        if (0 != err) {
                kfree(sub);
                return err;
        }
-       printk("bttv%d: add subdevice \"%s\"\n", core->nr, sub->dev.bus_id);
+       printk("bttv%d: add subdevice \"%s\"\n", core->nr, dev_name(&sub->dev));
        list_add_tail(&sub->list,&core->subs);
        return 0;
 }
index 46cb90e0985b2ad7bbe8193da8291d16eaf6a38b..529bf6cf634d9c76c039ac51320f30ac55eae8a1 100644 (file)
 #define BTTV_BOARD_XGUARD                  0x67
 #define BTTV_BOARD_NEBULA_DIGITV           0x68
 #define BTTV_BOARD_PV143                   0x69
-#define BTTV_BOARD_VD009X1_MINIDIN         0x6a
-#define BTTV_BOARD_VD009X1_COMBI           0x6b
+#define BTTV_BOARD_VD009X1_VD011_MINIDIN   0x6a
+#define BTTV_BOARD_VD009X1_VD011_COMBI     0x6b
 #define BTTV_BOARD_VD009_MINIDIN           0x6c
 #define BTTV_BOARD_VD009_COMBI             0x6d
 #define BTTV_BOARD_IVC100                  0x6e
 #define BTTV_BOARD_GEOVISION_GV600        0x96
 #define BTTV_BOARD_KOZUMI_KTV_01C          0x97
 #define BTTV_BOARD_ENLTV_FM_2             0x98
+#define BTTV_BOARD_VD012                  0x99
+#define BTTV_BOARD_VD012_X1               0x9a
+#define BTTV_BOARD_VD012_X2               0x9b
+
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
@@ -308,7 +312,7 @@ struct bttv_sub_device {
 
 struct bttv_sub_driver {
        struct device_driver   drv;
-       char                   wanted[BUS_ID_SIZE];
+       char                   wanted[20];
        int                    (*probe)(struct bttv_sub_device *sub);
        void                   (*remove)(struct bttv_sub_device *sub);
 };
index b4d940b2e44744777fa43a30d0d1f0fc4911b9bd..199a4d225caf6f4ec534b6477077b2280564d3fa 100644 (file)
@@ -459,7 +459,7 @@ struct bttv {
 };
 
 /* our devices */
-#define BTTV_MAX 16
+#define BTTV_MAX 32
 extern unsigned int bttv_num;
 extern struct bttv bttvs[BTTV_MAX];
 
index ace4ff9ea023b69732568db94093fbf3396682ae..17f80d03f38e4e2f6780fa1d10e63aa2b40e9126 100644 (file)
@@ -706,8 +706,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
  *     Video4linux interfacing
  */
 
-static int qcam_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, void *arg)
+static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
        struct qcam_device *qcam=(struct qcam_device *)dev;
@@ -867,7 +866,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
 static int qcam_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
+       return video_usercopy(file, cmd, arg, qcam_do_ioctl);
 }
 
 static ssize_t qcam_read(struct file *file, char __user *buf,
index 0f930d35146619fea78c43a0370b6fec6fdaba0f..21c71eb085db53ba232d17fb73c4ba868f936e19 100644 (file)
@@ -500,8 +500,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
  *     Video4linux interfacing
  */
 
-static int qcam_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, void *arg)
+static int qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
        struct qcam_device *qcam=(struct qcam_device *)dev;
@@ -667,9 +666,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
 }
 
 static int qcam_ioctl(struct inode *inode, struct file *file,
-                    unsigned int cmd, unsigned long arg)
+                     unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
+       return video_usercopy(file, cmd, arg, qcam_do_ioctl);
 }
 
 static ssize_t qcam_read(struct file *file, char __user *buf,
index 16c094f7785294230cdb5d9e1423fbf248454aa7..028a400d2453b64f4658091cfa0c86eb71b833db 100644 (file)
@@ -3333,8 +3333,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf,
        return cam->decompressed_frame.count;
 }
 
-static int cpia_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int ioctlnr, void *arg)
+static int cpia_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *dev = file->private_data;
        struct cam_data *cam = video_get_drvdata(dev);
@@ -3347,9 +3346,9 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
        if (mutex_lock_interruptible(&cam->busy_lock))
                return -EINTR;
 
-       //DBG("cpia_ioctl: %u\n", ioctlnr);
+       /* DBG("cpia_ioctl: %u\n", cmd); */
 
-       switch (ioctlnr) {
+       switch (cmd) {
        /* query capabilities */
        case VIDIOCGCAP:
        {
@@ -3724,7 +3723,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file,
 static int cpia_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
+       return video_usercopy(file, cmd, arg, cpia_do_ioctl);
 }
 
 
index 7e791b6923f986913095339ec5392d420fcc88a0..1cc0df8befff11b64fe69b98b0197841087ea895 100644 (file)
@@ -25,7 +25,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  Stripped of 2.4 stuff ready for main kernel submit by
- *             Alan Cox <alan@redhat.com>
+ *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  ****************************************************************************/
 
index 73511a542077b40c9c7ff32e795fc15789a557b9..dc5b07a20f693a50a4af0cdc7a2b93fb5ff3c2f7 100644 (file)
@@ -25,7 +25,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  Stripped of 2.4 stuff ready for main kernel submit by
- *             Alan Cox <alan@redhat.com>
+ *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  ****************************************************************************/
 
 #include <linux/kernel.h>
index 1c6bd633f1939a5493bcef8a1e20f51df863aed9..3c2d7eac119713d5704075e054ed5b21fa52f040 100644 (file)
@@ -26,7 +26,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  Stripped of 2.4 stuff ready for main kernel submit by
- *             Alan Cox <alan@redhat.com>
+ *             Alan Cox <alan@lxorguk.ukuu.org.uk>
  ****************************************************************************/
 
 #include <linux/version.h>
@@ -1572,8 +1572,7 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
  *  cpia2_ioctl
  *
  *****************************************************************************/
-static int cpia2_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int ioctl_nr, void *arg)
+static int cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct camera_data *cam = video_drvdata(file);
        int retval = 0;
@@ -1591,7 +1590,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
        }
 
        /* Priority check */
-       switch (ioctl_nr) {
+       switch (cmd) {
        case VIDIOCSWIN:
        case VIDIOCMCAPTURE:
        case VIDIOC_S_FMT:
@@ -1618,7 +1617,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
-       switch (ioctl_nr) {
+       switch (cmd) {
        case VIDIOCGCAP:        /* query capabilities */
                retval = ioctl_cap_query(arg, cam);
                break;
@@ -1683,7 +1682,7 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_ENUMINPUT:
        case VIDIOC_G_INPUT:
        case VIDIOC_S_INPUT:
-               retval = ioctl_input(ioctl_nr, arg,cam);
+               retval = ioctl_input(cmd, arg, cam);
                break;
 
        case VIDIOC_ENUM_FMT:
@@ -1843,9 +1842,9 @@ static int cpia2_do_ioctl(struct inode *inode, struct file *file,
 }
 
 static int cpia2_ioctl(struct inode *inode, struct file *file,
-                      unsigned int ioctl_nr, unsigned long iarg)
+                      unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl);
+       return video_usercopy(file, cmd, arg, cpia2_do_ioctl);
 }
 
 /******************************************************************************
index a662b15d5b90b27db329e446528eb01510a28b97..70fcd0d5de13bf50b968d14ba522d545a1e813ff 100644 (file)
@@ -23,9 +23,9 @@
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-i2c-drv.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
 MODULE_AUTHOR("Hans Verkuil");
@@ -40,111 +40,143 @@ MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
 
 /* ----------------------------------------------------------------------- */
 
-static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int cs5345_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static inline int cs5345_read(struct i2c_client *client, u8 reg)
+static inline int cs5345_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int cs5345_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
-       struct v4l2_routing *route = arg;
-       struct v4l2_control *ctrl = arg;
-
-       switch (cmd) {
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               route->input = cs5345_read(client, 0x09) & 7;
-               route->input |= cs5345_read(client, 0x05) & 0x70;
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               if ((route->input & 0xf) > 6) {
-                       v4l_err(client, "Invalid input %d.\n", route->input);
-                       return -EINVAL;
-               }
-               cs5345_write(client, 0x09, route->input & 0xf);
-               cs5345_write(client, 0x05, route->input & 0xf0);
-               break;
-
-       case VIDIOC_G_CTRL:
-               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-                       ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
-                       break;
-               }
-               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-                       return -EINVAL;
-               ctrl->value = cs5345_read(client, 0x07) & 0x3f;
-               if (ctrl->value >= 32)
-                       ctrl->value = ctrl->value - 64;
-               break;
-
-       case VIDIOC_S_CTRL:
-               break;
-               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-                       cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
-                       break;
-               }
-               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-                       return -EINVAL;
-               if (ctrl->value > 24 || ctrl->value < -24)
-                       return -EINVAL;
-               cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
-               cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
-               break;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client,
-                                       reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = cs5345_read(client, reg->reg & 0x1f);
-               else
-                       cs5345_write(client, reg->reg & 0x1f, reg->val & 0xff);
-               break;
+       if ((route->input & 0xf) > 6) {
+               v4l2_err(sd, "Invalid input %d.\n", route->input);
+               return -EINVAL;
        }
-#endif
+       cs5345_write(sd, 0x09, route->input & 0xf);
+       cs5345_write(sd, 0x05, route->input & 0xf0);
+       return 0;
+}
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client,
-                               arg, V4L2_IDENT_CS5345, 0);
-
-       case VIDIOC_LOG_STATUS:
-               {
-                       u8 v = cs5345_read(client, 0x09) & 7;
-                       u8 m = cs5345_read(client, 0x04);
-                       int vol = cs5345_read(client, 0x08) & 0x3f;
-
-                       v4l_info(client, "Input:  %d%s\n", v,
-                                     (m & 0x80) ? " (muted)" : "");
-                       if (vol >= 32)
-                               vol = vol - 64;
-                       v4l_info(client, "Volume: %d dB\n", vol);
-                       break;
-               }
-
-       default:
+static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0;
+               return 0;
+       }
+       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
                return -EINVAL;
+       ctrl->value = cs5345_read(sd, 0x07) & 0x3f;
+       if (ctrl->value >= 32)
+               ctrl->value = ctrl->value - 64;
+       return 0;
+}
+
+static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+               cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0);
+               return 0;
        }
+       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+               return -EINVAL;
+       if (ctrl->value > 24 || ctrl->value < -24)
+               return -EINVAL;
+       cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f);
+       cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f);
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = cs5345_read(sd, reg->reg & 0x1f);
+       return 0;
+}
+
+static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       cs5345_write(sd, reg->reg & 0x1f, reg->val & 0xff);
        return 0;
 }
+#endif
+
+static int cs5345_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_CS5345, 0);
+}
+
+static int cs5345_log_status(struct v4l2_subdev *sd)
+{
+       u8 v = cs5345_read(sd, 0x09) & 7;
+       u8 m = cs5345_read(sd, 0x04);
+       int vol = cs5345_read(sd, 0x08) & 0x3f;
+
+       v4l2_info(sd, "Input:  %d%s\n", v,
+                       (m & 0x80) ? " (muted)" : "");
+       if (vol >= 32)
+               vol = vol - 64;
+       v4l2_info(sd, "Volume: %d dB\n", vol);
+       return 0;
+}
+
+static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cs5345_core_ops = {
+       .log_status = cs5345_log_status,
+       .g_chip_ident = cs5345_g_chip_ident,
+       .g_ctrl = cs5345_g_ctrl,
+       .s_ctrl = cs5345_s_ctrl,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = cs5345_g_register,
+       .s_register = cs5345_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_audio_ops cs5345_audio_ops = {
+       .s_routing = cs5345_s_routing,
+};
+
+static const struct v4l2_subdev_ops cs5345_ops = {
+       .core = &cs5345_core_ops,
+       .audio = &cs5345_audio_ops,
+};
 
 /* ----------------------------------------------------------------------- */
 
 static int cs5345_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
+       struct v4l2_subdev *sd;
+
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
@@ -152,9 +184,25 @@ static int cs5345_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       cs5345_write(client, 0x02, 0x00);
-       cs5345_write(client, 0x04, 0x01);
-       cs5345_write(client, 0x09, 0x01);
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
+
+       cs5345_write(sd, 0x02, 0x00);
+       cs5345_write(sd, 0x04, 0x01);
+       cs5345_write(sd, 0x09, 0x01);
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs5345_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
        return 0;
 }
 
@@ -171,5 +219,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .driverid = I2C_DRIVERID_CS5345,
        .command = cs5345_command,
        .probe = cs5345_probe,
+       .remove = cs5345_remove,
        .id_table = cs5345_id,
 };
index c4444500b330ec711c0365c17cc6a093fdd61d9b..cb65d519cf78e463c0fa71b806521334c17ede3f 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 
@@ -47,84 +47,104 @@ I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
 
-static int cs53l32a_write(struct i2c_client *client, u8 reg, u8 value)
+static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
-static int cs53l32a_read(struct i2c_client *client, u8 reg)
+static int cs53l32a_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int cs53l32a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
-       struct v4l2_routing *route = arg;
-       struct v4l2_control *ctrl = arg;
-
-       switch (cmd) {
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               route->input = (cs53l32a_read(client, 0x01) >> 4) & 3;
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               /* There are 2 physical inputs, but the second input can be
-                  placed in two modes, the first mode bypasses the PGA (gain),
-                  the second goes through the PGA. Hence there are three
-                  possible inputs to choose from. */
-               if (route->input > 2) {
-                       v4l_err(client, "Invalid input %d.\n", route->input);
-                       return -EINVAL;
-               }
-               cs53l32a_write(client, 0x01, 0x01 + (route->input << 4));
-               break;
-
-       case VIDIOC_G_CTRL:
-               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-                       ctrl->value = (cs53l32a_read(client, 0x03) & 0xc0) != 0;
-                       break;
-               }
-               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-                       return -EINVAL;
-               ctrl->value = (s8)cs53l32a_read(client, 0x04);
-               break;
-
-       case VIDIOC_S_CTRL:
-               if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-                       cs53l32a_write(client, 0x03, ctrl->value ? 0xf0 : 0x30);
-                       break;
-               }
-               if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-                       return -EINVAL;
-               if (ctrl->value > 12 || ctrl->value < -96)
-                       return -EINVAL;
-               cs53l32a_write(client, 0x04, (u8) ctrl->value);
-               cs53l32a_write(client, 0x05, (u8) ctrl->value);
-               break;
-
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client,
-                               arg, V4L2_IDENT_CS53l32A, 0);
-
-       case VIDIOC_LOG_STATUS:
-               {
-                       u8 v = cs53l32a_read(client, 0x01);
-                       u8 m = cs53l32a_read(client, 0x03);
-                       s8 vol = cs53l32a_read(client, 0x04);
-
-                       v4l_info(client, "Input:  %d%s\n", (v >> 4) & 3,
-                                     (m & 0xC0) ? " (muted)" : "");
-                       v4l_info(client, "Volume: %d dB\n", vol);
-                       break;
-               }
-
-       default:
+       /* There are 2 physical inputs, but the second input can be
+          placed in two modes, the first mode bypasses the PGA (gain),
+          the second goes through the PGA. Hence there are three
+          possible inputs to choose from. */
+       if (route->input > 2) {
+               v4l2_err(sd, "Invalid input %d.\n", route->input);
                return -EINVAL;
        }
+       cs53l32a_write(sd, 0x01, 0x01 + (route->input << 4));
+       return 0;
+}
+
+static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+               ctrl->value = (cs53l32a_read(sd, 0x03) & 0xc0) != 0;
+               return 0;
+       }
+       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+               return -EINVAL;
+       ctrl->value = (s8)cs53l32a_read(sd, 0x04);
+       return 0;
+}
+
+static int cs53l32a_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+               cs53l32a_write(sd, 0x03, ctrl->value ? 0xf0 : 0x30);
+               return 0;
+       }
+       if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+               return -EINVAL;
+       if (ctrl->value > 12 || ctrl->value < -96)
+               return -EINVAL;
+       cs53l32a_write(sd, 0x04, (u8) ctrl->value);
+       cs53l32a_write(sd, 0x05, (u8) ctrl->value);
        return 0;
 }
 
+static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client,
+                       chip, V4L2_IDENT_CS53l32A, 0);
+}
+
+static int cs53l32a_log_status(struct v4l2_subdev *sd)
+{
+       u8 v = cs53l32a_read(sd, 0x01);
+       u8 m = cs53l32a_read(sd, 0x03);
+       s8 vol = cs53l32a_read(sd, 0x04);
+
+       v4l2_info(sd, "Input:  %d%s\n", (v >> 4) & 3,
+                       (m & 0xC0) ? " (muted)" : "");
+       v4l2_info(sd, "Volume: %d dB\n", vol);
+       return 0;
+}
+
+static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {
+       .log_status = cs53l32a_log_status,
+       .g_chip_ident = cs53l32a_g_chip_ident,
+       .g_ctrl = cs53l32a_g_ctrl,
+       .s_ctrl = cs53l32a_s_ctrl,
+};
+
+static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
+       .s_routing = cs53l32a_s_routing,
+};
+
+static const struct v4l2_subdev_ops cs53l32a_ops = {
+       .core = &cs53l32a_core_ops,
+       .audio = &cs53l32a_audio_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 /* i2c implementation */
@@ -137,6 +157,7 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
 static int cs53l32a_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
+       struct v4l2_subdev *sd;
        int i;
 
        /* Check if the adapter supports the needed features */
@@ -149,32 +170,46 @@ static int cs53l32a_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
+       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
+
        for (i = 1; i <= 7; i++) {
-               u8 v = cs53l32a_read(client, i);
+               u8 v = cs53l32a_read(sd, i);
 
-               v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
+               v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
        }
 
        /* Set cs53l32a internal register for Adaptec 2010/2410 setup */
 
-       cs53l32a_write(client, 0x01, (u8) 0x21);
-       cs53l32a_write(client, 0x02, (u8) 0x29);
-       cs53l32a_write(client, 0x03, (u8) 0x30);
-       cs53l32a_write(client, 0x04, (u8) 0x00);
-       cs53l32a_write(client, 0x05, (u8) 0x00);
-       cs53l32a_write(client, 0x06, (u8) 0x00);
-       cs53l32a_write(client, 0x07, (u8) 0x00);
+       cs53l32a_write(sd, 0x01, (u8) 0x21);
+       cs53l32a_write(sd, 0x02, (u8) 0x29);
+       cs53l32a_write(sd, 0x03, (u8) 0x30);
+       cs53l32a_write(sd, 0x04, (u8) 0x00);
+       cs53l32a_write(sd, 0x05, (u8) 0x00);
+       cs53l32a_write(sd, 0x06, (u8) 0x00);
+       cs53l32a_write(sd, 0x07, (u8) 0x00);
 
        /* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
 
        for (i = 1; i <= 7; i++) {
-               u8 v = cs53l32a_read(client, i);
+               u8 v = cs53l32a_read(sd, i);
 
-               v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
+               v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
        }
        return 0;
 }
 
+static int cs53l32a_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
+       return 0;
+}
+
 static const struct i2c_device_id cs53l32a_id[] = {
        { "cs53l32a", 0 },
        { }
@@ -185,6 +220,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "cs53l32a",
        .driverid = I2C_DRIVERID_CS53L32A,
        .command = cs53l32a_command,
+       .remove = cs53l32a_remove,
        .probe = cs53l32a_probe,
        .id_table = cs53l32a_id,
 };
index 0b55837880a711d5ef11805a01371c6e91bd122a..a2f0ad57043461cf72f3ac72ed1d4ae71dd94f1d 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from cx25840-audio.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -30,98 +31,165 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
        if (freq != 32000 && freq != 44100 && freq != 48000)
                return -EINVAL;
 
-       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
-       cx18_av_write(cx, 0x127, 0x50);
+       /*
+        * The PLL parameters are based on the external crystal frequency that
+        * would ideally be:
+        *
+        * NTSC Color subcarrier freq * 8 =
+        *      4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+        *
+        * The accidents of history and rationale that explain from where this
+        * combination of magic numbers originate can be found in:
+        *
+        * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+        * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+        *
+        * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+        * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+        *
+        * As Mike Bradley has rightly pointed out, it's not the exact crystal
+        * frequency that matters, only that all parts of the driver and
+        * firmware are using the same value (close to the ideal value).
+        *
+        * Since I have a strong suspicion that, if the firmware ever assumes a
+        * crystal value at all, it will assume 28.636360 MHz, the crystal
+        * freq used in calculations in this driver will be:
+        *
+        *      xtal_freq = 28.636360 MHz
+        *
+        * an error of less than 0.13 ppm which is way, way better than any off
+        * the shelf crystal will have for accuracy anyway.
+        *
+        * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error.
+        *
+        * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+        * investigation, experimentation, testing, and suggested solutions of
+        * of audio/video sync problems with SVideo and CVBS captures.
+        */
 
        if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
                switch (freq) {
                case 32000:
-                       /* VID_PLL and AUX_PLL */
-                       cx18_av_write4(cx, 0x108, 0x1408040f);
+                       /*
+                        * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+                        * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+                        */
+                       cx18_av_write4(cx, 0x108, 0x200d040f);
 
-                       /* AUX_PLL_FRAC */
-                       /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */
-                       cx18_av_write4(cx, 0x110, 0x012a0863);
+                       /* VID_PLL Fraction = 0x2be2fe */
+                       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+                       cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+                       /* AUX_PLL Fraction = 0x176740c */
+                       /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/
+                       cx18_av_write4(cx, 0x110, 0x0176740c);
 
                        /* src3/4/6_ctl */
-                       /* 0x1.f77f = (4 * 15734.26) / 32000 */
+                       /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */
                        cx18_av_write4(cx, 0x900, 0x0801f77f);
                        cx18_av_write4(cx, 0x904, 0x0801f77f);
                        cx18_av_write4(cx, 0x90c, 0x0801f77f);
 
-                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
-                       cx18_av_write(cx, 0x127, 0x54);
+                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+                       cx18_av_write(cx, 0x127, 0x60);
 
                        /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */
                        cx18_av_write4(cx, 0x12c, 0x11202fff);
 
                        /*
-                        * EN_AV_LOCK = 1
+                        * EN_AV_LOCK = 0
                         * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
                         *  ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
                         */
-                       cx18_av_write4(cx, 0x128, 0xa10d2ef8);
+                       cx18_av_write4(cx, 0x128, 0xa00d2ef8);
                        break;
 
                case 44100:
-                       /* VID_PLL and AUX_PLL */
-                       cx18_av_write4(cx, 0x108, 0x1009040f);
+                       /*
+                        * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+                        * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18
+                        */
+                       cx18_av_write4(cx, 0x108, 0x180e040f);
+
+                       /* VID_PLL Fraction = 0x2be2fe */
+                       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+                       cx18_av_write4(cx, 0x10c, 0x002be2fe);
 
-                       /* AUX_PLL_FRAC */
-                       /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */
-                       cx18_av_write4(cx, 0x110, 0x00ec6bce);
+                       /* AUX_PLL Fraction = 0x062a1f2 */
+                       /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/
+                       cx18_av_write4(cx, 0x110, 0x0062a1f2);
 
                        /* src3/4/6_ctl */
-                       /* 0x1.6d59 = (4 * 15734.26) / 44100 */
+                       /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */
                        cx18_av_write4(cx, 0x900, 0x08016d59);
                        cx18_av_write4(cx, 0x904, 0x08016d59);
                        cx18_av_write4(cx, 0x90c, 0x08016d59);
 
+                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */
+                       cx18_av_write(cx, 0x127, 0x58);
+
                        /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */
                        cx18_av_write4(cx, 0x12c, 0x112092ff);
 
                        /*
-                        * EN_AV_LOCK = 1
+                        * EN_AV_LOCK = 0
                         * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
                         *  ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
                         */
-                       cx18_av_write4(cx, 0x128, 0xa11d4bf8);
+                       cx18_av_write4(cx, 0x128, 0xa01d4bf8);
                        break;
 
                case 48000:
-                       /* VID_PLL and AUX_PLL */
-                       cx18_av_write4(cx, 0x108, 0x100a040f);
+                       /*
+                        * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+                        * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16
+                        */
+                       cx18_av_write4(cx, 0x108, 0x160e040f);
 
-                       /* AUX_PLL_FRAC */
-                       /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */
-                       cx18_av_write4(cx, 0x110, 0x0098d6dd);
+                       /* VID_PLL Fraction = 0x2be2fe */
+                       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+                       cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+                       /* AUX_PLL Fraction = 0x05227ad */
+                       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/
+                       cx18_av_write4(cx, 0x110, 0x005227ad);
 
                        /* src3/4/6_ctl */
-                       /* 0x1.4faa = (4 * 15734.26) / 48000 */
+                       /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */
                        cx18_av_write4(cx, 0x900, 0x08014faa);
                        cx18_av_write4(cx, 0x904, 0x08014faa);
                        cx18_av_write4(cx, 0x90c, 0x08014faa);
 
+                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+                       cx18_av_write(cx, 0x127, 0x56);
+
                        /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */
                        cx18_av_write4(cx, 0x12c, 0x11205fff);
 
                        /*
-                        * EN_AV_LOCK = 1
+                        * EN_AV_LOCK = 0
                         * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
                         *  ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
                         */
-                       cx18_av_write4(cx, 0x128, 0xa11193f8);
+                       cx18_av_write4(cx, 0x128, 0xa01193f8);
                        break;
                }
        } else {
                switch (freq) {
                case 32000:
-                       /* VID_PLL and AUX_PLL */
-                       cx18_av_write4(cx, 0x108, 0x1e08040f);
+                       /*
+                        * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+                        * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30
+                        */
+                       cx18_av_write4(cx, 0x108, 0x300d040f);
+
+                       /* VID_PLL Fraction = 0x2be2fe */
+                       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+                       cx18_av_write4(cx, 0x10c, 0x002be2fe);
 
-                       /* AUX_PLL_FRAC */
-                       /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */
-                       cx18_av_write4(cx, 0x110, 0x012a0863);
+                       /* AUX_PLL Fraction = 0x176740c */
+                       /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/
+                       cx18_av_write4(cx, 0x110, 0x0176740c);
 
                        /* src1_ctl */
                        /* 0x1.0000 = 32000/32000 */
@@ -133,27 +201,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
                        cx18_av_write4(cx, 0x904, 0x08020000);
                        cx18_av_write4(cx, 0x90c, 0x08020000);
 
-                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
-                       cx18_av_write(cx, 0x127, 0x54);
+                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */
+                       cx18_av_write(cx, 0x127, 0x70);
 
                        /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */
                        cx18_av_write4(cx, 0x12c, 0x11201fff);
 
                        /*
-                        * EN_AV_LOCK = 1
+                        * EN_AV_LOCK = 0
                         * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 =
                         *  ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8
                         */
-                       cx18_av_write4(cx, 0x128, 0xa10d2ef8);
+                       cx18_av_write4(cx, 0x128, 0xa00d2ef8);
                        break;
 
                case 44100:
-                       /* VID_PLL and AUX_PLL */
-                       cx18_av_write4(cx, 0x108, 0x1809040f);
+                       /*
+                        * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+                        * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24
+                        */
+                       cx18_av_write4(cx, 0x108, 0x240e040f);
 
-                       /* AUX_PLL_FRAC */
-                       /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */
-                       cx18_av_write4(cx, 0x110, 0x00ec6bce);
+                       /* VID_PLL Fraction = 0x2be2fe */
+                       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+                       cx18_av_write4(cx, 0x10c, 0x002be2fe);
+
+                       /* AUX_PLL Fraction = 0x062a1f2 */
+                       /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/
+                       cx18_av_write4(cx, 0x110, 0x0062a1f2);
 
                        /* src1_ctl */
                        /* 0x1.60cd = 44100/32000 */
@@ -165,24 +240,34 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
                        cx18_av_write4(cx, 0x904, 0x08017385);
                        cx18_av_write4(cx, 0x90c, 0x08017385);
 
+                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */
+                       cx18_av_write(cx, 0x127, 0x64);
+
                        /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */
                        cx18_av_write4(cx, 0x12c, 0x112061ff);
 
                        /*
-                        * EN_AV_LOCK = 1
+                        * EN_AV_LOCK = 0
                         * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 =
                         *  ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8
                         */
-                       cx18_av_write4(cx, 0x128, 0xa11d4bf8);
+                       cx18_av_write4(cx, 0x128, 0xa01d4bf8);
                        break;
 
                case 48000:
-                       /* VID_PLL and AUX_PLL */
-                       cx18_av_write4(cx, 0x108, 0x180a040f);
+                       /*
+                        * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
+                        * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20
+                        */
+                       cx18_av_write4(cx, 0x108, 0x200d040f);
+
+                       /* VID_PLL Fraction = 0x2be2fe */
+                       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/
+                       cx18_av_write4(cx, 0x10c, 0x002be2fe);
 
-                       /* AUX_PLL_FRAC */
-                       /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */
-                       cx18_av_write4(cx, 0x110, 0x0098d6dd);
+                       /* AUX_PLL Fraction = 0x176740c */
+                       /* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/
+                       cx18_av_write4(cx, 0x110, 0x0176740c);
 
                        /* src1_ctl */
                        /* 0x1.8000 = 48000/32000 */
@@ -194,15 +279,18 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
                        cx18_av_write4(cx, 0x904, 0x08015555);
                        cx18_av_write4(cx, 0x90c, 0x08015555);
 
+                       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */
+                       cx18_av_write(cx, 0x127, 0x60);
+
                        /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */
                        cx18_av_write4(cx, 0x12c, 0x11203fff);
 
                        /*
-                        * EN_AV_LOCK = 1
+                        * EN_AV_LOCK = 0
                         * VID_COUNT = 0x1193f8 = 143999.000 * 8 =
                         *  ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8
                         */
-                       cx18_av_write4(cx, 0x128, 0xa11193f8);
+                       cx18_av_write4(cx, 0x128, 0xa01193f8);
                        break;
                }
        }
@@ -215,12 +303,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
 void cx18_av_audio_set_path(struct cx18 *cx)
 {
        struct cx18_av_state *state = &cx->av_state;
+       u8 v;
 
        /* stop microcontroller */
-       cx18_av_and_or(cx, 0x803, ~0x10, 0);
+       v = cx18_av_read(cx, 0x803) & ~0x10;
+       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
 
        /* assert soft reset */
-       cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
+       v = cx18_av_read(cx, 0x810) | 0x01;
+       cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
 
        /* Mute everything to prevent the PFFT! */
        cx18_av_write(cx, 0x8d3, 0x1f);
@@ -240,12 +331,14 @@ void cx18_av_audio_set_path(struct cx18 *cx)
        set_audclk_freq(cx, state->audclk_freq);
 
        /* deassert soft reset */
-       cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
+       v = cx18_av_read(cx, 0x810) & ~0x01;
+       cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
 
        if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
                /* When the microcontroller detects the
                 * audio format, it will unmute the lines */
-               cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+               v = cx18_av_read(cx, 0x803) | 0x10;
+               cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
        }
 }
 
@@ -347,19 +440,23 @@ static int get_mute(struct cx18 *cx)
 static void set_mute(struct cx18 *cx, int mute)
 {
        struct cx18_av_state *state = &cx->av_state;
+       u8 v;
 
        if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
                /* Must turn off microcontroller in order to mute sound.
                 * Not sure if this is the best method, but it does work.
                 * If the microcontroller is running, then it will undo any
                 * changes to the mute register. */
+               v = cx18_av_read(cx, 0x803);
                if (mute) {
                        /* disable microcontroller */
-                       cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+                       v &= ~0x10;
+                       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
                        cx18_av_write(cx, 0x8d3, 0x1f);
                } else {
                        /* enable microcontroller */
-                       cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+                       v |= 0x10;
+                       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
                }
        } else {
                /* SRC1_MUTE_EN */
@@ -375,16 +472,26 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
 
        switch (cmd) {
        case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+       {
+               u8 v;
                if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
-                       cx18_av_and_or(cx, 0x803, ~0x10, 0);
+                       v = cx18_av_read(cx, 0x803) & ~0x10;
+                       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
                        cx18_av_write(cx, 0x8d3, 0x1f);
                }
-               cx18_av_and_or(cx, 0x810, ~0x1, 1);
+               v = cx18_av_read(cx, 0x810) | 0x1;
+               cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+
                retval = set_audclk_freq(cx, *(u32 *)arg);
-               cx18_av_and_or(cx, 0x810, ~0x1, 0);
-               if (state->aud_input > CX18_AV_AUDIO_SERIAL2)
-                       cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+
+               v = cx18_av_read(cx, 0x810) & ~0x1;
+               cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
+               if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
+                       v = cx18_av_read(cx, 0x803) | 0x10;
+                       cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+               }
                return retval;
+       }
 
        case VIDIOC_G_CTRL:
                switch (ctrl->id) {
index 73f5141a42d1270608f4017787230e52a49752c0..0b1c84b4ddd6eadd105373f152d82577dea5269e 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from cx25840-core.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -36,12 +37,31 @@ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
        return 0;
 }
 
+int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask)
+{
+       u32 reg = 0xc40000 + (addr & ~3);
+       int shift = (addr & 3) * 8;
+       u32 x = cx18_read_reg(cx, reg);
+
+       x = (x & ~((u32)0xff << shift)) | ((u32)value << shift);
+       cx18_write_reg_expect(cx, x, reg,
+                               ((u32)eval << shift), ((u32)mask << shift));
+       return 0;
+}
+
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
 {
        cx18_write_reg(cx, value, 0xc40000 + addr);
        return 0;
 }
 
+int
+cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask)
+{
+       cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask);
+       return 0;
+}
+
 int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value)
 {
        cx18_write_reg_noretry(cx, value, 0xc40000 + addr);
@@ -61,11 +81,6 @@ u32 cx18_av_read4(struct cx18 *cx, u16 addr)
        return cx18_read_reg(cx, 0xc40000 + addr);
 }
 
-u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr)
-{
-       return cx18_read_reg_noretry(cx, 0xc40000 + addr);
-}
-
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
                   u8 or_value)
 {
@@ -98,14 +113,16 @@ static void cx18_av_initialize(struct cx18 *cx)
 
        cx18_av_loadfw(cx);
        /* Stop 8051 code execution */
-       cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000);
+       cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000,
+                                                0x03000000, 0x13000000);
 
        /* initallize the PLL by toggling sleep bit */
        v = cx18_av_read4(cx, CXADEC_HOST_REG1);
-       /* enable sleep mode */
-       cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1);
+       /* enable sleep mode - register appears to be read only... */
+       cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe);
        /* disable sleep mode */
-       cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe);
+       cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe,
+                                                   v & 0xfffe, 0xffff);
 
        /* initialize DLLs */
        v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
@@ -125,9 +142,10 @@ static void cx18_av_initialize(struct cx18 *cx)
 
        v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
        /* enable TUNE_FIL_RST */
-       cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v);
+       cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F);
        /* disable TUNE_FIL_RST */
-       cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE);
+       cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3,
+                             v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F);
 
        /* enable 656 output */
        cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
@@ -251,10 +269,9 @@ void cx18_av_std_setup(struct cx18 *cx)
                        pll_int, pll_frac, pll_post);
 
        if (pll_post) {
-               int fin, fsc;
-               int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+               int fin, fsc, pll;
 
-               pll >>= 25;
+               pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
                pll /= pll_post;
                CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
                                        pll / 1000000, pll % 1000000);
@@ -324,6 +341,7 @@ static void input_change(struct cx18 *cx)
 {
        struct cx18_av_state *state = &cx->av_state;
        v4l2_std_id std = state->std;
+       u8 v;
 
        /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
        cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
@@ -333,31 +351,34 @@ static void input_change(struct cx18 *cx)
        if (std & V4L2_STD_525_60) {
                if (std == V4L2_STD_NTSC_M_JP) {
                        /* Japan uses EIAJ audio standard */
-                       cx18_av_write(cx, 0x808, 0xf7);
-                       cx18_av_write(cx, 0x80b, 0x02);
+                       cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff);
+                       cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f);
                } else if (std == V4L2_STD_NTSC_M_KR) {
                        /* South Korea uses A2 audio standard */
-                       cx18_av_write(cx, 0x808, 0xf8);
-                       cx18_av_write(cx, 0x80b, 0x03);
+                       cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff);
+                       cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
                } else {
                        /* Others use the BTSC audio standard */
-                       cx18_av_write(cx, 0x808, 0xf6);
-                       cx18_av_write(cx, 0x80b, 0x01);
+                       cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff);
+                       cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f);
                }
        } else if (std & V4L2_STD_PAL) {
                /* Follow tuner change procedure for PAL */
-               cx18_av_write(cx, 0x808, 0xff);
-               cx18_av_write(cx, 0x80b, 0x03);
+               cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
+               cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
        } else if (std & V4L2_STD_SECAM) {
                /* Select autodetect for SECAM */
-               cx18_av_write(cx, 0x808, 0xff);
-               cx18_av_write(cx, 0x80b, 0x03);
+               cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
+               cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
        }
 
-       if (cx18_av_read(cx, 0x803) & 0x10) {
+       v = cx18_av_read(cx, 0x803);
+       if (v & 0x10) {
                /* restart audio decoder microcontroller */
-               cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
-               cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+               v &= ~0x10;
+               cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
+               v |= 0x10;
+               cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
        }
 }
 
@@ -368,6 +389,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
        u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
                           vid_input <= CX18_AV_COMPOSITE8);
        u8 reg;
+       u8 v;
 
        CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
                        vid_input, aud_input);
@@ -413,16 +435,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                return -EINVAL;
        }
 
-       cx18_av_write(cx, 0x103, reg);
+       cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
        /* Set INPUT_MODE to Composite (0) or S-Video (1) */
        cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+
        /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-       cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+       v = cx18_av_read(cx, 0x102);
+       if (reg & 0x80)
+               v &= ~0x2;
+       else
+               v |= 0x2;
        /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
        if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-               cx18_av_and_or(cx, 0x102, ~0x4, 4);
+               v |= 0x4;
        else
-               cx18_av_and_or(cx, 0x102, ~0x4, 0);
+               v &= ~0x4;
+       cx18_av_write_expect(cx, 0x102, v, v, 0x17);
+
        /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
 
        state->vid_input = vid_input;
@@ -799,40 +828,47 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
        }
 
        case VIDIOC_S_TUNER:
+       {
+               u8 v;
+
                if (state->radio)
                        break;
 
+               v = cx18_av_read(cx, 0x809);
+               v &= ~0xf;
+
                switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
                        /* mono      -> mono
                           stereo    -> mono
                           bilingual -> lang1 */
-                       cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
                        break;
                case V4L2_TUNER_MODE_STEREO:
                case V4L2_TUNER_MODE_LANG1:
                        /* mono      -> mono
                           stereo    -> stereo
                           bilingual -> lang1 */
-                       cx18_av_and_or(cx, 0x809, ~0xf, 0x04);
+                       v |= 0x4;
                        break;
                case V4L2_TUNER_MODE_LANG1_LANG2:
                        /* mono      -> mono
                           stereo    -> stereo
                           bilingual -> lang1/lang2 */
-                       cx18_av_and_or(cx, 0x809, ~0xf, 0x07);
+                       v |= 0x7;
                        break;
                case V4L2_TUNER_MODE_LANG2:
                        /* mono      -> mono
                           stereo    -> stereo
                           bilingual -> lang2 */
-                       cx18_av_and_or(cx, 0x809, ~0xf, 0x01);
+                       v |= 0x1;
                        break;
                default:
                        return -EINVAL;
                }
+               cx18_av_write_expect(cx, 0x809, v, v, 0xff);
                state->audmode = vt->audmode;
                break;
+       }
 
        case VIDIOC_G_FMT:
                return get_v4lfmt(cx, (struct v4l2_format *)arg);
index b67d8df20cc66a7533a34e93c95982a91ac6accb..cf68a6039091a7dc684249ef5953ba651aec985c 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from cx25840-core.h
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -302,9 +303,11 @@ struct cx18_av_state {
 int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
 int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
 int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value);
+int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask);
+int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval,
+                         u32 mask);
 u8 cx18_av_read(struct cx18 *cx, u16 addr);
 u32 cx18_av_read4(struct cx18 *cx, u16 addr);
-u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr);
 int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
 int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
 int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
index 522a035b2e8fb5c065e334ad3fc2482af654c000..c64fd0a05a9773c9e1eeb67cbba887fd7287601f 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 ADEC firmware functions
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -43,11 +44,13 @@ int cx18_av_loadfw(struct cx18 *cx)
        /* The firmware load often has byte errors, so allow for several
           retries, both at byte level and at the firmware load level. */
        while (retries1 < 5) {
-               cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
-               cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6);
+               cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000,
+                                         0x00008430, 0xffffffff); /* cx25843 */
+               cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff);
 
-               /* Reset the Mako core (Register is undocumented.) */
-               cx18_av_write4(cx, 0x8100, 0x00010000);
+               /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
+               cx18_av_write4_expect(cx, 0x8100, 0x00010000,
+                                         0x00008430, 0xffffffff); /* cx25843 */
 
                /* Put the 8051 in reset and enable firmware upload */
                cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
@@ -61,13 +64,12 @@ int cx18_av_loadfw(struct cx18 *cx)
                        int retries2;
                        int unrec_err = 0;
 
-                       for (retries2 = 0; retries2 < CX18_MAX_MMIO_RETRIES;
+                       for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES;
                             retries2++) {
                                cx18_av_write4_noretry(cx, CXADEC_DL_CTL,
                                                       dl_control);
                                udelay(10);
-                               value = cx18_av_read4_noretry(cx,
-                                                             CXADEC_DL_CTL);
+                               value = cx18_av_read4(cx, CXADEC_DL_CTL);
                                if (value == dl_control)
                                        break;
                                /* Check if we can correct the byte by changing
@@ -78,9 +80,7 @@ int cx18_av_loadfw(struct cx18 *cx)
                                        break;
                                }
                        }
-                       cx18_log_write_retries(cx, retries2,
-                                       cx->reg_mem + 0xc40000 + CXADEC_DL_CTL);
-                       if (unrec_err || retries2 >= CX18_MAX_MMIO_RETRIES)
+                       if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES)
                                break;
                }
                if (i == size)
@@ -93,7 +93,8 @@ int cx18_av_loadfw(struct cx18 *cx)
                return -EIO;
        }
 
-       cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
+       cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+                               0x13000000 | fw->size, 0x13000000, 0x13000000);
 
        /* Output to the 416 */
        cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
@@ -118,7 +119,8 @@ int cx18_av_loadfw(struct cx18 *cx)
           passthrough */
        cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
 
-       cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6);
+       cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
+                                                                 0x3F00FFFF);
        /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
 
        /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
@@ -136,7 +138,7 @@ int cx18_av_loadfw(struct cx18 *cx)
        v |= 0xFF;   /* Auto by default */
        v |= 0x400;  /* Stereo by default */
        v |= 0x14000000;
-       cx18_av_write4(cx, CXADEC_STD_DET_CTL, v);
+       cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
 
        release_firmware(fw);
 
index 02fdf57bb678f1faf5ed0f1671ee435bd1db252b..1527ea4f6b06b83be93e4cdadc6eb9d73537c677 100644 (file)
@@ -141,10 +141,11 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
                u8 lcr[24];
 
                fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+                   fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
                        return -EINVAL;
                svbi = &fmt->fmt.sliced;
-               if (svbi->service_set == 0) {
+               if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                        /* raw VBI */
                        memset(svbi, 0, sizeof(*svbi));
 
index 5efe01ebe9db368e258f8716525223d3ee1425c6..e274043657ddb01638b0c2155d1e4bb8ba84e7ee 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-cards.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -50,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
 static const struct cx18_card cx18_card_hvr1600_esmt = {
        .type = CX18_CARD_HVR_1600_ESMT,
        .name = "Hauppauge HVR-1600",
-       .comment = "VBI is not yet supported\n",
+       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_muxer = CX18_HW_CS5345,
@@ -96,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = {
 static const struct cx18_card cx18_card_hvr1600_samsung = {
        .type = CX18_CARD_HVR_1600_SAMSUNG,
        .name = "Hauppauge HVR-1600 (Preproduction)",
-       .comment = "VBI is not yet supported\n",
+       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_muxer = CX18_HW_CS5345,
@@ -151,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = {
 static const struct cx18_card cx18_card_h900 = {
        .type = CX18_CARD_COMPRO_H900,
        .name = "Compro VideoMate H900",
-       .comment = "VBI is not yet supported\n",
+       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_all = CX18_HW_TUNER,
@@ -248,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
 static const struct cx18_card cx18_card_cnxt_raptor_pal = {
        .type = CX18_CARD_CNXT_RAPTOR_PAL,
        .name = "Conexant Raptor PAL/SECAM",
-       .comment = "VBI is not yet supported\n",
+       .comment = "Raw VBI supported; Sliced VBI is not yet supported\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
        .hw_audio_ctrl = CX18_HW_CX23418,
        .hw_muxer = CX18_HW_GPIO,
index 32155f6e6fe41b35700d69870aff057010f3dcdb..6fa7bcb42dded2376e8b6ade7d29efba1d4c5de9 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-cards.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -47,8 +48,9 @@
 
 /* V4L2 capability aliases */
 #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
-                         V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
-/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+                         V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
+                         V4L2_CAP_VBI_CAPTURE)
+/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
 
 struct cx18_card_video_input {
        u8  video_type;         /* video input type */
index f46c7e5ed747c61c7f7b50ce58fb4aa09c01f58f..17edf305d6499e7abcfc53b88c21627315f05443 100644 (file)
@@ -259,6 +259,7 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
                return err;
        }
        if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+               struct cx18_api_func_private priv;
                struct cx2341x_mpeg_params p = cx->params;
                int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
                                                c, VIDIOC_S_EXT_CTRLS);
@@ -278,7 +279,9 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
                        fmt.fmt.pix.height = cx->params.height;
                        cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
                }
-               err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+               priv.cx = cx;
+               priv.s = &cx->streams[id->type];
+               err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
                if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
                        err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
                cx->params = p;
index 7874d9790a519917c88da2d4a91e738a48c14ec0..f50cf2167adc1a6082789aef840915a53142f9f6 100644 (file)
@@ -75,48 +75,76 @@ static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1,
                                     -1, -1, -1, -1, -1, -1, -1, -1 };
-static int mmio_ndelay[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
-                                          -1, -1, -1, -1, -1, -1, -1, -1,
-                                          -1, -1, -1, -1, -1, -1, -1, -1,
-                                          -1, -1, -1, -1, -1, -1, -1, -1 };
 static unsigned cardtype_c = 1;
 static unsigned tuner_c = 1;
 static unsigned radio_c = 1;
-static unsigned mmio_ndelay_c = 1;
 static char pal[] = "--";
 static char secam[] = "--";
 static char ntsc[] = "-";
 
 /* Buffers */
-static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
 static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS;
 static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
 static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
 static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
 
+static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE;
+static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE;
+static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE;
+static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE;
+/* VBI bufsize based on standards supported by card tuner for now */
+static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE;
+
+static int enc_ts_bufs = -1;
+static int enc_mpg_bufs = -1;
+static int enc_idx_bufs = -1;
+static int enc_yuv_bufs = -1;
+static int enc_vbi_bufs = -1;
+static int enc_pcm_bufs = -1;
+
+
 static int cx18_pci_latency = 1;
 
-int cx18_retry_mmio = 1;
+static int mmio_ndelay;
+static int retry_mmio = 1;
+
 int cx18_debug;
 
 module_param_array(tuner, int, &tuner_c, 0644);
 module_param_array(radio, bool, &radio_c, 0644);
 module_param_array(cardtype, int, &cardtype_c, 0644);
-module_param_array(mmio_ndelay, int, &mmio_ndelay_c, 0644);
 module_param_string(pal, pal, sizeof(pal), 0644);
 module_param_string(secam, secam, sizeof(secam), 0644);
 module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
 module_param_named(debug, cx18_debug, int, 0644);
-module_param_named(retry_mmio, cx18_retry_mmio, int, 0644);
+module_param(mmio_ndelay, int, 0644);
+module_param(retry_mmio, int, 0644);
 module_param(cx18_pci_latency, int, 0644);
 module_param(cx18_first_minor, int, 0644);
 
-module_param(enc_mpg_buffers, int, 0644);
 module_param(enc_ts_buffers, int, 0644);
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_idx_buffers, int, 0644);
 module_param(enc_yuv_buffers, int, 0644);
 module_param(enc_vbi_buffers, int, 0644);
 module_param(enc_pcm_buffers, int, 0644);
 
+module_param(enc_ts_bufsize, int, 0644);
+module_param(enc_mpg_bufsize, int, 0644);
+module_param(enc_idx_bufsize, int, 0644);
+module_param(enc_yuv_bufsize, int, 0644);
+/* VBI bufsize based on standards supported by card tuner for now */
+module_param(enc_pcm_bufsize, int, 0644);
+
+module_param(enc_ts_bufs, int, 0644);
+module_param(enc_mpg_bufs, int, 0644);
+module_param(enc_idx_bufs, int, 0644);
+module_param(enc_yuv_bufs, int, 0644);
+module_param(enc_vbi_bufs, int, 0644);
+module_param(enc_pcm_bufs, int, 0644);
+
 MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
                        "\t\t\tsee tuner.h for values");
 MODULE_PARM_DESC(radio,
@@ -152,28 +180,62 @@ MODULE_PARM_DESC(cx18_pci_latency,
                 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
                 "\t\t\tDefault: Yes");
 MODULE_PARM_DESC(retry_mmio,
-                "Check and retry memory mapped IO accesses\n"
-                "\t\t\tDefault: 1 [Yes]");
+                "(Deprecated) MMIO writes are now always checked and retried\n"
+                "\t\t\tEffectively: 1 [Yes]");
 MODULE_PARM_DESC(mmio_ndelay,
-                "Delay (ns) for each CX23418 memory mapped IO access.\n"
-                "\t\t\tTry larger values that are close to a multiple of the\n"
-                "\t\t\tPCI clock period, 30.3 ns, if your card doesn't work.\n"
-                "\t\t\tDefault: " __stringify(CX18_DEFAULT_MMIO_NDELAY));
-MODULE_PARM_DESC(enc_mpg_buffers,
-                "Encoder MPG Buffers (in MB)\n"
-                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+                "(Deprecated) MMIO accesses are now never purposely delayed\n"
+                "\t\t\tEffectively: 0 ns");
 MODULE_PARM_DESC(enc_ts_buffers,
-                "Encoder TS Buffers (in MB)\n"
+                "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n"
                 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_ts_bufsize,
+                "Size of an encoder TS buffer (kB)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE));
+MODULE_PARM_DESC(enc_ts_bufs,
+                "Number of encoder TS buffers\n"
+                "\t\t\tDefault is computed from other enc_ts_* parameters");
+MODULE_PARM_DESC(enc_mpg_buffers,
+                "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_mpg_bufsize,
+                "Size of an encoder MPG buffer (kB)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE));
+MODULE_PARM_DESC(enc_mpg_bufs,
+                "Number of encoder MPG buffers\n"
+                "\t\t\tDefault is computed from other enc_mpg_* parameters");
+MODULE_PARM_DESC(enc_idx_buffers,
+                "Encoder IDX buffer memory (MB). (enc_idx_bufs can override)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFFERS));
+MODULE_PARM_DESC(enc_idx_bufsize,
+                "Size of an encoder IDX buffer (kB)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFSIZE));
+MODULE_PARM_DESC(enc_idx_bufs,
+                "Number of encoder IDX buffers\n"
+                "\t\t\tDefault is computed from other enc_idx_* parameters");
 MODULE_PARM_DESC(enc_yuv_buffers,
-                "Encoder YUV Buffers (in MB)\n"
+                "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n"
                 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_bufsize,
+                "Size of an encoder YUV buffer (kB)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE));
+MODULE_PARM_DESC(enc_yuv_bufs,
+                "Number of encoder YUV buffers\n"
+                "\t\t\tDefault is computed from other enc_yuv_* parameters");
 MODULE_PARM_DESC(enc_vbi_buffers,
-                "Encoder VBI Buffers (in MB)\n"
+                "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n"
                 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_bufs,
+                "Number of encoder VBI buffers\n"
+                "\t\t\tDefault is computed from enc_vbi_buffers & tuner std");
 MODULE_PARM_DESC(enc_pcm_buffers,
-                "Encoder PCM buffers (in MB)\n"
+                "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n"
                 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_bufsize,
+                "Size of an encoder PCM buffer (kB)\n"
+                "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE));
+MODULE_PARM_DESC(enc_pcm_bufs,
+                "Number of encoder PCM buffers\n"
+                "\t\t\tDefault is computed from other enc_pcm_* parameters");
 
 MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
 
@@ -187,7 +249,7 @@ MODULE_VERSION(CX18_VERSION);
 /* Generic utility functions */
 int cx18_msleep_timeout(unsigned int msecs, int intr)
 {
-       int timeout = msecs_to_jiffies(msecs);
+       long int timeout = msecs_to_jiffies(msecs);
        int sig;
 
        do {
@@ -366,20 +428,69 @@ static void cx18_process_options(struct cx18 *cx)
 {
        int i, j;
 
-       cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
        cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+       cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+       cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers;
        cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
        cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
        cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+       cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */
+
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs;
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs;
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs;
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs;
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs;
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs;
+       cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */
+
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize;
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize;
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize;
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize;
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize;
+       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */
+
+       /* Except for VBI ensure stream_buffers & stream_buf_size are valid */
+       for (i = 0; i < CX18_MAX_STREAMS; i++) {
+               /* User said to use 0 buffers */
+               if (cx->stream_buffers[i] == 0) {
+                       cx->options.megabytes[i] = 0;
+                       cx->stream_buf_size[i] = 0;
+                       continue;
+               }
+               /* User said to use 0 MB total */
+               if (cx->options.megabytes[i] <= 0) {
+                       cx->options.megabytes[i] = 0;
+                       cx->stream_buffers[i] = 0;
+                       cx->stream_buf_size[i] = 0;
+                       continue;
+               }
+               /* VBI is computed later or user said buffer has size 0 */
+               if (cx->stream_buf_size[i] <= 0) {
+                       if (i != CX18_ENC_STREAM_TYPE_VBI) {
+                               cx->options.megabytes[i] = 0;
+                               cx->stream_buffers[i] = 0;
+                               cx->stream_buf_size[i] = 0;
+                       }
+                       continue;
+               }
+               if (cx->stream_buffers[i] < 0) {
+                       cx->stream_buffers[i] = cx->options.megabytes[i] * 1024
+                                               / cx->stream_buf_size[i];
+               } else {
+                       /* N.B. This might round down to 0 */
+                       cx->options.megabytes[i] =
+                         cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024;
+               }
+               cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */
+       }
+
        cx->options.cardtype = cardtype[cx->num];
        cx->options.tuner = tuner[cx->num];
        cx->options.radio = radio[cx->num];
 
-       if (mmio_ndelay[cx->num] < 0)
-               cx->options.mmio_ndelay = CX18_DEFAULT_MMIO_NDELAY;
-       else
-               cx->options.mmio_ndelay = mmio_ndelay[cx->num];
-
        cx->std = cx18_parse_std(cx);
        if (cx->options.cardtype == -1) {
                CX18_INFO("Ignore card\n");
@@ -440,22 +551,30 @@ done:
  */
 static int __devinit cx18_init_struct1(struct cx18 *cx)
 {
+       int i;
+
        cx->base_addr = pci_resource_start(cx->dev, 0);
 
        mutex_init(&cx->serialize_lock);
        mutex_init(&cx->i2c_bus_lock[0]);
        mutex_init(&cx->i2c_bus_lock[1]);
        mutex_init(&cx->gpio_lock);
+       mutex_init(&cx->epu2apu_mb_lock);
+       mutex_init(&cx->epu2cpu_mb_lock);
 
        spin_lock_init(&cx->lock);
 
        cx->work_queue = create_singlethread_workqueue(cx->name);
        if (cx->work_queue == NULL) {
-               CX18_ERR("Could not create work queue\n");
-               return -1;
+               CX18_ERR("Unable to create work hander thread\n");
+               return -ENOMEM;
        }
 
-       INIT_WORK(&cx->work, cx18_work_handler);
+       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
+               cx->epu_work_order[i].cx = cx;
+               cx->epu_work_order[i].str = cx->epu_debug_str;
+               INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler);
+       }
 
        /* start counting open_id at 1 */
        cx->open_id = 1;
@@ -472,20 +591,55 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        init_waitqueue_head(&cx->cap_w);
        init_waitqueue_head(&cx->mb_apu_waitq);
        init_waitqueue_head(&cx->mb_cpu_waitq);
-       init_waitqueue_head(&cx->mb_epu_waitq);
-       init_waitqueue_head(&cx->mb_hpu_waitq);
        init_waitqueue_head(&cx->dma_waitq);
 
        /* VBI */
-       cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+       cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
        cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
-       cx->vbi.raw_size = 1456;
-       cx->vbi.raw_decoder_line_size = 1456;
-       cx->vbi.raw_decoder_sav_odd_field = 0x20;
-       cx->vbi.raw_decoder_sav_even_field = 0x60;
-       cx->vbi.sliced_decoder_line_size = 272;
-       cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
-       cx->vbi.sliced_decoder_sav_even_field = 0xF0;
+
+       /*
+        * The VBI line sizes depend on the pixel clock and the horiz rate
+        *
+        * (1/Fh)*(2*Fp) = Samples/line
+        *     = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples
+        *
+        *  Sliced VBI is sent as ancillary data during horizontal blanking
+        *  Raw VBI is sent as active video samples during vertcal blanking
+        *
+        *  We use a  BT.656 pxiel clock of 13.5 MHz and a BT.656 active line
+        *  length of 720 pixels @ 4:2:2 sampling.  Thus...
+        *
+        *  For systems that use a 15.734 kHz horizontal rate, such as
+        *  NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have:
+        *
+        *  (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line =
+        *  4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples
+        *
+        *  For systems that use a 15.625 kHz horizontal rate, such as
+        *  PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have:
+        *
+        *  (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line =
+        *  4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples
+        *
+        */
+
+       /* FIXME: init these based on tuner std & modify when std changes */
+       /* CX18-AV-Core number of VBI samples output per horizontal line */
+       cx->vbi.raw_decoder_line_size = 1444;   /* 4 byte SAV + 2 * 720 */
+       cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */
+
+       /* CX18-AV-Core VBI samples/line possibly rounded up */
+       cx->vbi.raw_size = 1444;   /* Real max size is 1444 */
+       cx->vbi.sliced_size = 284; /* Real max size is  284 */
+
+       /*
+        * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode
+        * Task Field VerticalBlank HorizontalBlank 0 0 0 0
+        */
+       cx->vbi.raw_decoder_sav_odd_field = 0x20;     /*   V  */
+       cx->vbi.raw_decoder_sav_even_field = 0x60;    /*  FV  */
+       cx->vbi.sliced_decoder_sav_odd_field = 0xB0;  /* T VH - actually EAV */
+       cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */
        return 0;
 }
 
@@ -518,6 +672,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx)
        cx->av_state.aud_input = CX18_AV_AUDIO8;
        cx->av_state.audclk_freq = 48000;
        cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+       /* FIXME - 8 is NTSC value, investigate */
        cx->av_state.vbi_line_offset = 8;
 }
 
@@ -662,12 +817,9 @@ static int __devinit cx18_probe(struct pci_dev *dev,
 
        /* PCI Device Setup */
        retval = cx18_setup_pci(cx, dev, pci_id);
-       if (retval != 0) {
-               if (retval == -EIO)
-                       goto free_workqueue;
-               else if (retval == -ENXIO)
-                       goto free_mem;
-       }
+       if (retval != 0)
+               goto free_workqueue;
+
        /* save cx in the pci struct for later use */
        pci_set_drvdata(dev, cx);
 
@@ -726,6 +878,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                goto free_i2c;
        }
        cx18_init_memory(cx);
+       cx18_init_scb(cx);
 
        /* Register IRQ */
        retval = request_irq(cx->dev->irq, cx18_irq_handler,
@@ -739,8 +892,6 @@ static int __devinit cx18_probe(struct pci_dev *dev,
                cx->std = V4L2_STD_NTSC_M;
 
        if (cx->options.tuner == -1) {
-               int i;
-
                for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
                        if ((cx->std & cx->card->tuners[i].std) == 0)
                                continue;
@@ -777,13 +928,23 @@ static int __devinit cx18_probe(struct pci_dev *dev,
        }
        cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
 
-       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
-       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
-       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
-       cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
+       /*
+        * FIXME: setting the buffer size based on the tuner standard is
+        * suboptimal, as the CVBS and SVideo inputs could use a different std
+        * and the buffer could end up being too small in that case.
+        */
        vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
        cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
 
+       if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0)
+               cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] =
+                  cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024
+                  / vbi_buf_size;
+       else
+               cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] =
+                    cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size
+                    / (1024 * 1024);
+
        if (cx->options.radio > 0)
                cx->v4l2_cap |= V4L2_CAP_RADIO;
 
@@ -844,7 +1005,6 @@ err:
        if (retval == 0)
                retval = -ENODEV;
        CX18_ERR("Error %d on initialization\n", retval);
-       cx18_log_statistics(cx);
 
        i = cx->num;
        spin_lock(&cx18_cards_lock);
@@ -923,6 +1083,13 @@ int cx18_init_on_first_open(struct cx18 *cx)
        return 0;
 }
 
+static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
+               cancel_work_sync(&cx->epu_work_order[i].work);
+}
+
 static void cx18_remove(struct pci_dev *pci_dev)
 {
        struct cx18 *cx = pci_get_drvdata(pci_dev);
@@ -940,7 +1107,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
        cx18_halt_firmware(cx);
 
-       flush_workqueue(cx->work_queue);
+       cx18_cancel_epu_work_orders(cx);
+
        destroy_workqueue(cx->work_queue);
 
        cx18_streams_cleanup(cx, 1);
@@ -955,7 +1123,6 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
        pci_disable_device(cx->dev);
 
-       cx18_log_statistics(cx);
        CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
 }
 
@@ -1004,6 +1171,7 @@ static void module_cleanup(void)
                        continue;
                kfree(cx18_cards[i]);
        }
+
 }
 
 module_init(module_start);
index bbdd5f25041df9348e1c6a3ba264b30400141705..0d2edebc39b4e199ca3cf5c1c1a20b0cc11580d0 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-driver.h
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -64,9 +65,6 @@
 #  error "This driver requires kernel PCI support."
 #endif
 
-/* Default delay to throttle mmio access to the CX23418 */
-#define CX18_DEFAULT_MMIO_NDELAY 0 /* 0 ns = 0 PCI clock(s) / 33 MHz */
-
 #define CX18_MEM_OFFSET        0x00000000
 #define CX18_MEM_SIZE  0x04000000
 #define CX18_REG_OFFSET        0x02000000
 #define CX18_DEFAULT_ENC_VBI_BUFFERS 1
 #define CX18_DEFAULT_ENC_PCM_BUFFERS 1
 
+/* Maximum firmware DMA buffers per stream */
+#define CX18_MAX_FW_MDLS_PER_STREAM 63
+
+/* DMA buffer, default size in kB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFSIZE   32
+#define CX18_DEFAULT_ENC_MPG_BUFSIZE  32
+#define CX18_DEFAULT_ENC_IDX_BUFSIZE  32
+#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128
+/* Default VBI bufsize based on standards supported by card tuner for now */
+#define CX18_DEFAULT_ENC_PCM_BUFSIZE   4
+
 /* i2c stuff */
 #define I2C_CLIENTS_MAX 16
 
 
 #define CX18_MAX_PGM_INDEX (400)
 
-extern int cx18_retry_mmio;    /* enable check & retry of mmio accesses */
 extern int cx18_debug;
 
 
@@ -185,7 +193,6 @@ struct cx18_options {
        int cardtype;           /* force card type on load */
        int tuner;              /* set tuner on load */
        int radio;              /* enable/disable radio */
-       unsigned long mmio_ndelay; /* delay in ns after every PCI mmio access */
 };
 
 /* per-buffer bit flags */
@@ -203,11 +210,8 @@ struct cx18_options {
 #define CX18_F_I_EOS                   4       /* End of encoder stream */
 #define CX18_F_I_RADIO_USER            5       /* radio tuner is selected */
 #define CX18_F_I_ENC_PAUSED            13      /* the encoder is paused */
-#define CX18_F_I_HAVE_WORK             15      /* there is work to be done */
-#define CX18_F_I_WORK_HANDLER_DVB      18      /* work to be done for DVB */
 #define CX18_F_I_INITED                        21      /* set after first open */
 #define CX18_F_I_FAILED                        22      /* set if first open failed */
-#define CX18_F_I_WORK_INITED           23      /* worker thread initialized */
 
 /* These are the VBI types as they appear in the embedded VBI private packets. */
 #define CX18_SLICED_TYPE_TELETEXT_B     (1)
@@ -220,6 +224,7 @@ struct cx18_buffer {
        dma_addr_t dma_handle;
        u32 id;
        unsigned long b_flags;
+       unsigned skipped;
        char *buf;
 
        u32 bytesused;
@@ -248,6 +253,27 @@ struct cx18_dvb {
 struct cx18;    /* forward reference */
 struct cx18_scb; /* forward reference */
 
+
+#define CX18_MAX_MDL_ACKS 2
+#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
+/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
+
+#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
+#define CX18_F_EWO_MB_STALE_WHILE_PROC   0x2
+#define CX18_F_EWO_MB_STALE \
+            (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
+
+struct cx18_epu_work_order {
+       struct work_struct work;
+       atomic_t pending;
+       struct cx18 *cx;
+       unsigned long flags;
+       int rpu;
+       struct cx18_mailbox mb;
+       struct cx18_mdl_ack mdl_ack[CX18_MAX_MDL_ACKS];
+       char *str;
+};
+
 #define CX18_INVALID_TASK_HANDLE 0xffffffff
 
 struct cx18_stream {
@@ -261,7 +287,7 @@ struct cx18_stream {
        unsigned mdl_offset;
 
        u32 id;
-       spinlock_t qlock;       /* locks access to the queues */
+       struct mutex qlock;     /* locks access to the queues */
        unsigned long s_flags;  /* status flags, see above */
        int dma;                /* can be PCI_DMA_TODEVICE,
                                   PCI_DMA_FROMDEVICE or
@@ -275,8 +301,8 @@ struct cx18_stream {
 
        /* Buffer Queues */
        struct cx18_queue q_free;       /* free buffers */
-       struct cx18_queue q_full;       /* full buffers */
-       struct cx18_queue q_io;         /* waiting for I/O */
+       struct cx18_queue q_busy;       /* busy buffers - in use by firmware */
+       struct cx18_queue q_full;       /* full buffers - data for user apps */
 
        /* DVB / Digital Transport */
        struct cx18_dvb dvb;
@@ -353,12 +379,7 @@ struct cx18_i2c_algo_callback_data {
        int bus_index;   /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
 };
 
-#define CX18_MAX_MMIO_RETRIES 10
-
-struct cx18_mmio_stats {
-       atomic_t retried_write[CX18_MAX_MMIO_RETRIES+1];
-       atomic_t retried_read[CX18_MAX_MMIO_RETRIES+1];
-};
+#define CX18_MAX_MMIO_WR_RETRIES 10
 
 /* Struct to hold info about cx18 cards */
 struct cx18 {
@@ -378,7 +399,9 @@ struct cx18 {
        u32 v4l2_cap;           /* V4L2 capabilities of card */
        u32 hw_flags;           /* Hardware description of the board */
        unsigned mdl_offset;
-       struct cx18_scb __iomem *scb;   /* pointer to SCB */
+       struct cx18_scb __iomem *scb; /* pointer to SCB */
+       struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/
+       struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/
 
        struct cx18_av_state av_state;
 
@@ -397,6 +420,7 @@ struct cx18 {
 
        struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
        struct cx18_options options;    /* User options */
+       int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */
        int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
        struct cx18_stream streams[CX18_MAX_STREAMS];   /* Stream data */
        unsigned long i_flags;  /* global cx18 flags */
@@ -428,14 +452,17 @@ struct cx18 {
 
        wait_queue_head_t mb_apu_waitq;
        wait_queue_head_t mb_cpu_waitq;
-       wait_queue_head_t mb_epu_waitq;
-       wait_queue_head_t mb_hpu_waitq;
        wait_queue_head_t cap_w;
        /* when the current DMA is finished this queue is woken up */
        wait_queue_head_t dma_waitq;
 
+       u32 sw1_irq_mask;
+       u32 sw2_irq_mask;
+       u32 hw2_irq_mask;
+
        struct workqueue_struct *work_queue;
-       struct work_struct work;
+       struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
+       char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 
        /* i2c */
        struct i2c_adapter i2c_adap[2];
@@ -450,9 +477,6 @@ struct cx18 {
        u32 gpio_val;
        struct mutex gpio_lock;
 
-       /* Statistics */
-       struct cx18_mmio_stats mmio_stats;
-
        /* v4l2 and User settings */
 
        /* codec settings */
@@ -481,4 +505,10 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
 /* First-open initialization: load firmware, etc. */
 int cx18_init_on_first_open(struct cx18 *cx);
 
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int cx18_raw_vbi(const struct cx18 *cx)
+{
+       return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
 #endif /* CX18_DRIVER_H */
index 4542e2e5e3d76323668ee9b1f3b5132dfeaf090c..bd5e6f3fd4d0a0c041bc8b9fae6300790f89c4d5 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 functions for DVB support
  *
  *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -23,8 +24,6 @@
 #include "cx18-dvb.h"
 #include "cx18-io.h"
 #include "cx18-streams.h"
-#include "cx18-queue.h"
-#include "cx18-scb.h"
 #include "cx18-cards.h"
 #include "s5h1409.h"
 #include "mxl5005s.h"
@@ -109,20 +108,23 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
        if (!demux->dmx.frontend)
                return -EINVAL;
 
-       if (stream) {
-               mutex_lock(&stream->dvb.feedlock);
-               if (stream->dvb.feeding++ == 0) {
-                       CX18_DEBUG_INFO("Starting Transport DMA\n");
-                       ret = cx18_start_v4l2_encode_stream(stream);
-                       if (ret < 0) {
-                               CX18_DEBUG_INFO(
-                                       "Failed to start Transport DMA\n");
-                               stream->dvb.feeding--;
-                       }
-               } else
-                       ret = 0;
-               mutex_unlock(&stream->dvb.feedlock);
-       }
+       if (!stream)
+               return -EINVAL;
+
+       mutex_lock(&stream->dvb.feedlock);
+       if (stream->dvb.feeding++ == 0) {
+               CX18_DEBUG_INFO("Starting Transport DMA\n");
+               set_bit(CX18_F_S_STREAMING, &stream->s_flags);
+               ret = cx18_start_v4l2_encode_stream(stream);
+               if (ret < 0) {
+                       CX18_DEBUG_INFO("Failed to start Transport DMA\n");
+                       stream->dvb.feeding--;
+                       if (stream->dvb.feeding == 0)
+                               clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
+               }
+       } else
+               ret = 0;
+       mutex_unlock(&stream->dvb.feedlock);
 
        return ret;
 }
@@ -215,6 +217,10 @@ int cx18_dvb_register(struct cx18_stream *stream)
        dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
 
        CX18_INFO("DVB Frontend registered\n");
+       CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n",
+                 stream->dvb.dvb_adapter.num, stream->name,
+                 stream->buffers, stream->buf_size/1024);
+
        mutex_init(&dvb->feedlock);
        dvb->enabled = 1;
        return ret;
@@ -302,24 +308,3 @@ static int dvb_register(struct cx18_stream *stream)
 
        return ret;
 }
-
-void cx18_dvb_work_handler(struct cx18 *cx)
-{
-       struct cx18_buffer *buf;
-       struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS];
-
-       while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) {
-               if (s->dvb.enabled)
-                       dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
-                                        buf->bytesused);
-
-               cx18_enqueue(s, buf, &s->q_free);
-               cx18_buf_sync_for_device(s, buf);
-               if (s->handle == CX18_INVALID_TASK_HANDLE) /* FIXME: improve */
-                       continue;
-
-               cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
-                      (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
-                      1, buf->id, s->buf_size);
-       }
-}
index bbdcefc87f288c4fa92b70cf68e56d572df17b47..bf8d8f6f54558ab3264dd783ad13dc9246632b40 100644 (file)
@@ -23,4 +23,3 @@
 
 int cx18_dvb_register(struct cx18_stream *stream);
 void cx18_dvb_unregister(struct cx18_stream *stream);
-void cx18_dvb_work_handler(struct cx18 *cx);
index 5f9089907544c091f1e276eee7601a81a946ca77..425271a29517e91534e6762163ced38f61a0cbe7 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-fileops.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -66,12 +67,11 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type)
        }
        s->id = id->open_id;
 
-       /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
-          CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+       /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
           (provided VBI insertion is on and sliced VBI is selected), for all
           other streams we're done */
        if (type == CX18_ENC_STREAM_TYPE_MPG &&
-                  cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+           cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) {
                vbi_type = CX18_ENC_STREAM_TYPE_VBI;
        } else {
                return 0;
@@ -185,8 +185,10 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
                            !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
                                while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
                                        /* byteswap and process VBI data */
-/*                                     cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
-                                       cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
+                                       cx18_process_vbi_data(cx, buf,
+                                                             s_vbi->dma_pts,
+                                                             s_vbi->type);
+                                       cx18_stream_put_buf_fw(s_vbi, buf);
                                }
                        }
                        buf = &cx->vbi.sliced_mpeg_buf;
@@ -194,11 +196,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block,
                                return buf;
                }
 
-               /* do we have leftover data? */
-               buf = cx18_dequeue(s, &s->q_io);
-               if (buf)
-                       return buf;
-
                /* do we have new data? */
                buf = cx18_dequeue(s, &s->q_full);
                if (buf) {
@@ -262,7 +259,7 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
        if (len > ucount)
                len = ucount;
        if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
-           cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+           !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
                const char *start = buf->buf + buf->readpos;
                const char *p = start + 1;
                const u8 *q;
@@ -337,8 +334,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
        /* Each VBI buffer is one frame, the v4l2 API says that for VBI the
           frames should arrive one-by-one, so make sure we never output more
           than one VBI frame at a time */
-       if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
-           cx->vbi.sliced_in->service_set)
+       if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx))
                single_frame = 1;
 
        for (;;) {
@@ -365,16 +361,10 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
                                tot_count - tot_written);
 
                if (buf != &cx->vbi.sliced_mpeg_buf) {
-                       if (buf->readpos == buf->bytesused) {
-                               cx18_buf_sync_for_device(s, buf);
-                               cx18_enqueue(s, buf, &s->q_free);
-                               cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
-                                       s->handle,
-                                       (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
-                                         cx->enc_mem,
-                                       1, buf->id, s->buf_size);
-                       } else
-                               cx18_enqueue(s, buf, &s->q_io);
+                       if (buf->readpos == buf->bytesused)
+                               cx18_stream_put_buf_fw(s, buf);
+                       else
+                               cx18_push(s, buf, &s->q_full);
                } else if (buf->readpos == buf->bytesused) {
                        int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
 
@@ -518,7 +508,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
        CX18_DEBUG_HI_FILE("Encoder poll\n");
        poll_wait(filp, &s->waitq, wait);
 
-       if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers))
+       if (atomic_read(&s->q_full.buffers))
                return POLLIN | POLLRDNORM;
        if (eof)
                return POLLHUP;
index 51534428cd00c9dbe1b231516ccf2df078bc9f16..1fa95da1575e63120c0f5e0b8e8d7318d7d6de54 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 firmware functions
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -25,6 +26,7 @@
 #include "cx18-irq.h"
 #include "cx18-firmware.h"
 #include "cx18-cards.h"
+#include "cx18-av-core.h"
 #include <linux/firmware.h>
 
 #define CX18_PROC_SOFT_RESET           0xc70010
@@ -121,6 +123,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
                        if (cx18_raw_readl(cx, dst) != *src) {
                                CX18_ERR("Mismatch at offset %x\n", i);
                                release_firmware(fw);
+                               cx18_setup_page(cx, 0);
                                return -EIO;
                        }
                        dst++;
@@ -131,10 +134,12 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
                CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
        size = fw->size;
        release_firmware(fw);
+       cx18_setup_page(cx, SCB_OFFSET);
        return size;
 }
 
-static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
+static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
+                               u32 *entry_addr)
 {
        const struct firmware *fw = NULL;
        int i, j;
@@ -149,9 +154,11 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
        if (request_firmware(&fw, fn, &cx->dev->dev)) {
                CX18_ERR("unable to open firmware %s\n", fn);
                CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+               cx18_setup_page(cx, 0);
                return -ENOMEM;
        }
 
+       *entry_addr = 0;
        src = (const u32 *)fw->data;
        vers = fw->data + sizeof(seghdr);
        sz = fw->size;
@@ -168,10 +175,12 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
                }
                CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
                                seghdr.addr + seghdr.size - 1);
+               if (*entry_addr == 0)
+                       *entry_addr = seghdr.addr;
                if (offset + seghdr.size > sz)
                        break;
                for (i = 0; i < seghdr.size; i += 4096) {
-                       cx18_setup_page(cx, offset + i);
+                       cx18_setup_page(cx, seghdr.addr + i);
                        for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
                                /* no need for endianness conversion on the ppc */
                                cx18_raw_writel(cx, src[(offset + j) / 4],
@@ -181,6 +190,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
                                        CX18_ERR("Mismatch at offset %x\n",
                                                 offset + j);
                                        release_firmware(fw);
+                                       cx18_setup_page(cx, 0);
                                        return -EIO;
                                }
                        }
@@ -192,16 +202,17 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
                                fn, apu_version, fw->size);
        size = fw->size;
        release_firmware(fw);
-       /* Clear bit0 for APU to start from 0 */
-       cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030);
+       cx18_setup_page(cx, 0);
        return size;
 }
 
 void cx18_halt_firmware(struct cx18 *cx)
 {
        CX18_DEBUG_INFO("Preparing for firmware halt.\n");
-       cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
-       cx18_write_reg(cx, 0x00020002, CX18_ADEC_CONTROL);
+       cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
+                                 0x0000000F, 0x000F000F);
+       cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
+                                 0x00000002, 0x00020002);
 }
 
 void cx18_init_power(struct cx18 *cx, int lowpwr)
@@ -211,9 +222,48 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
        cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
 
        /* ADEC out of sleep */
-       cx18_write_reg(cx, 0x00020000, CX18_ADEC_CONTROL);
-
-       /* The fast clock is at 200/245 MHz */
+       cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
+                                 0x00000000, 0x00020002);
+
+       /*
+        * The PLL parameters are based on the external crystal frequency that
+        * would ideally be:
+        *
+        * NTSC Color subcarrier freq * 8 =
+        *      4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
+        *
+        * The accidents of history and rationale that explain from where this
+        * combination of magic numbers originate can be found in:
+        *
+        * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
+        * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
+        *
+        * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
+        * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
+        *
+        * As Mike Bradley has rightly pointed out, it's not the exact crystal
+        * frequency that matters, only that all parts of the driver and
+        * firmware are using the same value (close to the ideal value).
+        *
+        * Since I have a strong suspicion that, if the firmware ever assumes a
+        * crystal value at all, it will assume 28.636360 MHz, the crystal
+        * freq used in calculations in this driver will be:
+        *
+        *      xtal_freq = 28.636360 MHz
+        *
+        * an error of less than 0.13 ppm which is way, way better than any off
+        * the shelf crystal will have for accuracy anyway.
+        *
+        * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+        *
+        * Many thanks to Jeff Campbell and Mike Bradley for their extensive
+        * investigation, experimentation, testing, and suggested solutions of
+        * of audio/video sync problems with SVideo and CVBS captures.
+        */
+
+       /* the fast clock is at 200/245 MHz */
+       /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
+       /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
        cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
        cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
                                                CX18_FAST_CLOCK_PLL_FRAC);
@@ -223,16 +273,36 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
        cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
 
        /* set slow clock to 125/120 MHz */
-       cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
-       cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8,
+       /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
+       /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
+       cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
+       cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
                                                CX18_SLOW_CLOCK_PLL_FRAC);
-       cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST);
+       cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
 
        /* mpeg clock pll 54MHz */
+       /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
        cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
-       cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+       cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
        cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
 
+       /*
+        * VDCLK  Integer = 0x0f, Post Divider = 0x04
+        * AIMCLK Integer = 0x0e, Post Divider = 0x16
+        */
+       cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+       /* VDCLK Fraction = 0x2be2fe */
+       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+       cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+       /* AIMCLK Fraction = 0x05227ad */
+       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */
+       cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+
        /* Defaults */
        /* APU = SC or SC/2 = 125/62.5 */
        /* EPU = SC = 125 */
@@ -248,22 +318,34 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
        /* VFC = disabled */
        /* USB = disabled */
 
-       cx18_write_reg(cx, lowpwr ? 0xFFFF0020 : 0x00060004,
-                                                       CX18_CLOCK_SELECT1);
-       cx18_write_reg(cx, lowpwr ? 0xFFFF0004 : 0x00060006,
-                                                       CX18_CLOCK_SELECT2);
-
-       cx18_write_reg(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
-       cx18_write_reg(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
+       if (lowpwr) {
+               cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
+                                         0x00000020, 0xFFFFFFFF);
+               cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
+                                         0x00000004, 0xFFFFFFFF);
+       } else {
+               /* This doesn't explicitly set every clock select */
+               cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
+                                         0x00000004, 0x00060006);
+               cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
+                                         0x00000006, 0x00060006);
+       }
 
-       cx18_write_reg(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1);
-       cx18_write_reg(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2);
+       cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
+                                 0x00000002, 0xFFFFFFFF);
+       cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
+                                 0x00000104, 0xFFFFFFFF);
+       cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
+                                 0x00009026, 0xFFFFFFFF);
+       cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
+                                 0x00003105, 0xFFFFFFFF);
 }
 
 void cx18_init_memory(struct cx18 *cx)
 {
        cx18_msleep_timeout(10, 0);
-       cx18_write_reg(cx, 0x10000, CX18_DDR_SOFT_RESET);
+       cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
+                                 0x00000000, 0x00010001);
        cx18_msleep_timeout(10, 0);
 
        cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
@@ -282,13 +364,15 @@ void cx18_init_memory(struct cx18 *cx)
 
        cx18_msleep_timeout(10, 0);
 
-       cx18_write_reg(cx, 0x20000, CX18_DDR_SOFT_RESET);
+       cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
+                                 0x00000000, 0x00020002);
        cx18_msleep_timeout(10, 0);
 
        /* use power-down mode when idle */
        cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
 
-       cx18_write_reg(cx, 0x10001, CX18_REG_BUS_TIMEOUT_EN);
+       cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
+                                 0x00000001, 0x00010001);
 
        cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
        cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
@@ -307,51 +391,76 @@ void cx18_init_memory(struct cx18 *cx)
 
 int cx18_firmware_init(struct cx18 *cx)
 {
+       u32 fw_entry_addr;
+       int sz, retries;
+       u32 api_args[MAX_MB_ARGUMENTS];
+
        /* Allow chip to control CLKRUN */
        cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
 
-       cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+       /* Stop the firmware */
+       cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
+                                 0x0000000F, 0x000F000F);
 
        cx18_msleep_timeout(1, 0);
 
+       /* If the CPU is still running */
+       if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
+               CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
+               return -EIO;
+       }
+
        cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
        cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
-       /* Only if the processor is not running */
-       if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) {
-               int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
-                              cx->enc_mem, cx);
-
-               cx18_write_enc(cx, 0xE51FF004, 0);
-               cx18_write_enc(cx, 0xa00000, 4);  /* todo: not hardcoded */
-               /* Start APU */
-               cx18_write_reg(cx, 0x00010000, CX18_PROC_SOFT_RESET);
-               cx18_msleep_timeout(500, 0);
-
-               sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
-                                       cx->enc_mem, cx);
-
-               if (sz > 0) {
-                       int retries = 0;
-
-                       /* start the CPU */
-                       cx18_write_reg(cx, 0x00080000, CX18_PROC_SOFT_RESET);
-                       while (retries++ < 50) { /* Loop for max 500mS */
-                               if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
-                                    & 1) == 0)
-                                       break;
-                               cx18_msleep_timeout(10, 0);
-                       }
-                       cx18_msleep_timeout(200, 0);
-                       if (retries == 51) {
-                               CX18_ERR("Could not start the CPU\n");
-                               return -EIO;
-                       }
-               }
-               if (sz <= 0)
-                       return -EIO;
+       sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx);
+       if (sz <= 0)
+               return sz;
+
+       /* The SCB & IPC area *must* be correct before starting the firmwares */
+       cx18_init_scb(cx);
+
+       fw_entry_addr = 0;
+       sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx,
+                               &fw_entry_addr);
+       if (sz <= 0)
+               return sz;
+
+       /* Start the CPU. The CPU will take care of the APU for us. */
+       cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
+                                 0x00000000, 0x00080008);
+
+       /* Wait up to 500 ms for the APU to come out of reset */
+       for (retries = 0;
+            retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
+            retries++)
+               cx18_msleep_timeout(10, 0);
+
+       cx18_msleep_timeout(200, 0);
+
+       if (retries == 50 &&
+           (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
+               CX18_ERR("Could not start the CPU\n");
+               return -EIO;
        }
+
+       /*
+        * The CPU had once before set up to receive an interrupt for it's
+        * outgoing IRQ_CPU_TO_EPU_ACK to us.  If it ever does this, we get an
+        * interrupt when it sends us an ack, but by the time we process it,
+        * that flag in the SW2 status register has been cleared by the CPU
+        * firmware.  We'll prevent that not so useful condition from happening
+        * by clearing the CPU's interrupt enables for Ack IRQ's we want to
+        * process.
+        */
+       cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+       /* Try a benign command to see if the CPU is alive and well */
+       sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
+       if (sz < 0)
+               return sz;
+
        /* initialize GPIO */
-       cx18_write_reg(cx, 0x14001400, 0xC78110);
+       cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
        return 0;
 }
index 0e560421989e4bb69f124a0ce28047d7c10665a3..1a99329f33cb5b6375edd1736cfe7529976c5069 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-gpio.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 
 static void gpio_write(struct cx18 *cx)
 {
-       u32 dir = cx->gpio_dir;
-       u32 val = cx->gpio_val;
-
-       cx18_write_reg(cx, (dir & 0xffff) << 16, CX18_REG_GPIO_DIR1);
-       cx18_write_reg(cx, ((dir & 0xffff) << 16) | (val & 0xffff),
-                       CX18_REG_GPIO_OUT1);
-       cx18_write_reg(cx, dir & 0xffff0000, CX18_REG_GPIO_DIR2);
-       cx18_write_reg_sync(cx, (dir & 0xffff0000) | ((val & 0xffff0000) >> 16),
-                       CX18_REG_GPIO_OUT2);
+       u32 dir_lo = cx->gpio_dir & 0xffff;
+       u32 val_lo = cx->gpio_val & 0xffff;
+       u32 dir_hi = cx->gpio_dir >> 16;
+       u32 val_hi = cx->gpio_val >> 16;
+
+       cx18_write_reg_expect(cx, dir_lo << 16,
+                                       CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo);
+       cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo,
+                                       CX18_REG_GPIO_OUT1, val_lo, dir_lo);
+       cx18_write_reg_expect(cx, dir_hi << 16,
+                                       CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi);
+       cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi,
+                                       CX18_REG_GPIO_OUT2, val_hi, dir_hi);
 }
 
 void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
index beb7424b9944f928b7239be5a162d9114486b112..39ffccc19d8a447dbbb646eb025ba18e92e5458b 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-gpio.h
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index aa09e557b195ceef2d2e0bfc506e1a59412e8c80..8941f58bed7f042ce5cce8a97bbfeb33ef20bd79 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-i2c.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -27,6 +28,7 @@
 #include "cx18-gpio.h"
 #include "cx18-av-core.h"
 #include "cx18-i2c.h"
+#include "cx18-irq.h"
 
 #define CX18_REG_I2C_1_WR   0xf15000
 #define CX18_REG_I2C_1_RD   0xf15008
@@ -160,9 +162,9 @@ static void cx18_setscl(void *data, int state)
        u32 r = cx18_read_reg(cx, addr);
 
        if (state)
-               cx18_write_reg_sync(cx, r | SETSCL_BIT, addr);
+               cx18_write_reg(cx, r | SETSCL_BIT, addr);
        else
-               cx18_write_reg_sync(cx, r & ~SETSCL_BIT, addr);
+               cx18_write_reg(cx, r & ~SETSCL_BIT, addr);
 }
 
 static void cx18_setsda(void *data, int state)
@@ -173,9 +175,9 @@ static void cx18_setsda(void *data, int state)
        u32 r = cx18_read_reg(cx, addr);
 
        if (state)
-               cx18_write_reg_sync(cx, r | SETSDL_BIT, addr);
+               cx18_write_reg(cx, r | SETSDL_BIT, addr);
        else
-               cx18_write_reg_sync(cx, r & ~SETSDL_BIT, addr);
+               cx18_write_reg(cx, r & ~SETSDL_BIT, addr);
 }
 
 static int cx18_getscl(void *data)
@@ -396,30 +398,33 @@ int init_cx18_i2c(struct cx18 *cx)
        if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
                /* Reset/Unreset I2C hardware block */
                /* Clock select 220MHz */
-               cx18_write_reg(cx, 0x10000000, 0xc71004);
+               cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
+                                         0x00000000, 0x10001000);
                /* Clock Enable */
-               cx18_write_reg_sync(cx, 0x10001000, 0xc71024);
+               cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
+                                         0x00001000, 0x10001000);
        }
        /* courtesy of Steven Toth <stoth@hauppauge.com> */
-       cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c);
+       cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
        mdelay(10);
-       cx18_write_reg_sync(cx, 0x00c000c0, 0xc7001c);
+       cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
        mdelay(10);
-       cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c);
+       cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
        mdelay(10);
 
        /* Set to edge-triggered intrs. */
-       cx18_write_reg_sync(cx, 0x00c00000, 0xc730c8);
+       cx18_write_reg(cx, 0x00c00000, 0xc730c8);
        /* Clear any stale intrs */
-       cx18_write_reg_sync(cx, 0x00c00000, 0xc730c4);
+       cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
+                      ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);
 
        /* Hw I2C1 Clock Freq ~100kHz */
-       cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+       cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);
        cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
 
        /* Hw I2C2 Clock Freq ~100kHz */
-       cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+       cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR);
        cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
        cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
 
index 220fae8d4ad757a766fc08e6de3a5bf9e892bd03..ec5b3d7bcc6b0802cca9d7f4366f08d9643758d0 100644 (file)
 #include "cx18-io.h"
 #include "cx18-irq.h"
 
-void cx18_log_statistics(struct cx18 *cx)
-{
-       int i;
-
-       if (!(cx18_debug & CX18_DBGFLG_INFO))
-               return;
-
-       for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++)
-               CX18_DEBUG_INFO("retried_write[%d] = %d\n", i,
-                               atomic_read(&cx->mmio_stats.retried_write[i]));
-       for (i = 0; i <= CX18_MAX_MMIO_RETRIES; i++)
-               CX18_DEBUG_INFO("retried_read[%d] = %d\n", i,
-                               atomic_read(&cx->mmio_stats.retried_read[i]));
-       return;
-}
-
-void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr)
-{
-       int i;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               cx18_raw_writel_noretry(cx, val, addr);
-               if (val == cx18_raw_readl_noretry(cx, addr))
-                       break;
-       }
-       cx18_log_write_retries(cx, i, addr);
-}
-
-u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr)
-{
-       int i;
-       u32 val;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               val = cx18_raw_readl_noretry(cx, addr);
-               if (val != 0xffffffff) /* PCI bus read error */
-                       break;
-       }
-       cx18_log_read_retries(cx, i, addr);
-       return val;
-}
-
-u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr)
-{
-       int i;
-       u16 val;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               val = cx18_raw_readw_noretry(cx, addr);
-               if (val != 0xffff) /* PCI bus read error */
-                       break;
-       }
-       cx18_log_read_retries(cx, i, addr);
-       return val;
-}
-
-void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr)
-{
-       int i;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               cx18_writel_noretry(cx, val, addr);
-               if (val == cx18_readl_noretry(cx, addr))
-                       break;
-       }
-       cx18_log_write_retries(cx, i, addr);
-}
-
-void _cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr,
-                        u32 eval, u32 mask)
-{
-       int i;
-       eval &= mask;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               cx18_writel_noretry(cx, val, addr);
-               if (eval == (cx18_readl_noretry(cx, addr) & mask))
-                       break;
-       }
-       cx18_log_write_retries(cx, i, addr);
-}
-
-void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr)
-{
-       int i;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               cx18_writew_noretry(cx, val, addr);
-               if (val == cx18_readw_noretry(cx, addr))
-                       break;
-       }
-       cx18_log_write_retries(cx, i, addr);
-}
-
-void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr)
-{
-       int i;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               cx18_writeb_noretry(cx, val, addr);
-               if (val == cx18_readb_noretry(cx, addr))
-                       break;
-       }
-       cx18_log_write_retries(cx, i, addr);
-}
-
-u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr)
-{
-       int i;
-       u32 val;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               val = cx18_readl_noretry(cx, addr);
-               if (val != 0xffffffff) /* PCI bus read error */
-                       break;
-       }
-       cx18_log_read_retries(cx, i, addr);
-       return val;
-}
-
-u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr)
-{
-       int i;
-       u16 val;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               val = cx18_readw_noretry(cx, addr);
-               if (val != 0xffff) /* PCI bus read error */
-                       break;
-       }
-       cx18_log_read_retries(cx, i, addr);
-       return val;
-}
-
-u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr)
-{
-       int i;
-       u8 val;
-       for (i = 0; i < CX18_MAX_MMIO_RETRIES; i++) {
-               val = cx18_readb_noretry(cx, addr);
-               if (val != 0xff) /* PCI bus read error */
-                       break;
-       }
-       cx18_log_read_retries(cx, i, addr);
-       return val;
-}
-
-void cx18_memcpy_fromio(struct cx18 *cx, void *to,
-                       const void __iomem *from, unsigned int len)
-{
-       const u8 __iomem *src = from;
-       u8 *dst = to;
-
-       /* Align reads on the CX23418's addresses */
-       if ((len > 0) && ((unsigned long) src & 1)) {
-               *dst = cx18_readb(cx, src);
-               len--;
-               dst++;
-               src++;
-       }
-       if ((len > 1) && ((unsigned long) src & 2)) {
-               *((u16 *)dst) = cx18_raw_readw(cx, src);
-               len -= 2;
-               dst += 2;
-               src += 2;
-       }
-       while (len > 3) {
-               *((u32 *)dst) = cx18_raw_readl(cx, src);
-               len -= 4;
-               dst += 4;
-               src += 4;
-       }
-       if (len > 1) {
-               *((u16 *)dst) = cx18_raw_readw(cx, src);
-               len -= 2;
-               dst += 2;
-               src += 2;
-       }
-       if (len > 0)
-               *dst = cx18_readb(cx, src);
-}
-
 void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count)
 {
        u8 __iomem *dst = addr;
@@ -230,32 +57,35 @@ void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count)
 
 void cx18_sw1_irq_enable(struct cx18 *cx, u32 val)
 {
-       u32 r;
        cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val);
-       r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
-       cx18_write_reg(cx, r | val, SW1_INT_ENABLE_PCI);
+       cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | val;
+       cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI);
 }
 
 void cx18_sw1_irq_disable(struct cx18 *cx, u32 val)
 {
-       u32 r;
-       r = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
-       cx18_write_reg(cx, r & ~val, SW1_INT_ENABLE_PCI);
+       cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) & ~val;
+       cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI);
 }
 
 void cx18_sw2_irq_enable(struct cx18 *cx, u32 val)
 {
-       u32 r;
        cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val);
-       r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
-       cx18_write_reg(cx, r | val, SW2_INT_ENABLE_PCI);
+       cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | val;
+       cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI);
 }
 
 void cx18_sw2_irq_disable(struct cx18 *cx, u32 val)
+{
+       cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) & ~val;
+       cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI);
+}
+
+void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val)
 {
        u32 r;
-       r = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
-       cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_PCI);
+       r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU);
+       cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU);
 }
 
 void cx18_setup_page(struct cx18 *cx, u32 addr)
index 425244453ea7d2ca349644200ef2f2e05e40422a..2635b3a8cc96cafea7db8068ae1ab77066f16e01 100644 (file)
 
 #include "cx18-driver.h"
 
-static inline void cx18_io_delay(struct cx18 *cx)
-{
-       if (cx->options.mmio_ndelay)
-               ndelay(cx->options.mmio_ndelay);
-}
-
 /*
  * Readback and retry of MMIO access for reliability:
  * The concept was suggested by Steve Toth <stoth@linuxtv.org>.
  * The implmentation is the fault of Andy Walls <awalls@radix.net>.
+ *
+ * *write* functions are implied to retry the mmio unless suffixed with _noretry
+ * *read* functions never retry the mmio (it never helps to do so)
  */
 
-/* Statistics gathering */
-static inline
-void cx18_log_write_retries(struct cx18 *cx, int i, const void __iomem *addr)
-{
-       if (i > CX18_MAX_MMIO_RETRIES)
-               i = CX18_MAX_MMIO_RETRIES;
-       atomic_inc(&cx->mmio_stats.retried_write[i]);
-       return;
-}
-
-static inline
-void cx18_log_read_retries(struct cx18 *cx, int i, const void __iomem *addr)
+/* Non byteswapping memory mapped IO */
+static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
 {
-       if (i > CX18_MAX_MMIO_RETRIES)
-               i = CX18_MAX_MMIO_RETRIES;
-       atomic_inc(&cx->mmio_stats.retried_read[i]);
-       return;
+       return __raw_readl(addr);
 }
 
-void cx18_log_statistics(struct cx18 *cx);
-
-/* Non byteswapping memory mapped IO */
 static inline
 void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
 {
        __raw_writel(val, addr);
-       cx18_io_delay(cx);
 }
 
-void cx18_raw_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr);
-
 static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr)
 {
-       if (cx18_retry_mmio)
-               cx18_raw_writel_retry(cx, val, addr);
-       else
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
                cx18_raw_writel_noretry(cx, val, addr);
+               if (val == cx18_raw_readl(cx, addr))
+                       break;
+       }
 }
 
-
-static inline
-u32 cx18_raw_readl_noretry(struct cx18 *cx, const void __iomem *addr)
-{
-       u32 ret = __raw_readl(addr);
-       cx18_io_delay(cx);
-       return ret;
-}
-
-u32 cx18_raw_readl_retry(struct cx18 *cx, const void __iomem *addr);
-
-static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr)
+/* Normal memory mapped IO */
+static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
 {
-       if (cx18_retry_mmio)
-               return cx18_raw_readl_retry(cx, addr);
-
-       return cx18_raw_readl_noretry(cx, addr);
+       return readl(addr);
 }
 
-
 static inline
-u16 cx18_raw_readw_noretry(struct cx18 *cx, const void __iomem *addr)
+void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
 {
-       u16 ret = __raw_readw(addr);
-       cx18_io_delay(cx);
-       return ret;
+       writel(val, addr);
 }
 
-u16 cx18_raw_readw_retry(struct cx18 *cx, const void __iomem *addr);
-
-static inline u16 cx18_raw_readw(struct cx18 *cx, const void __iomem *addr)
+static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
 {
-       if (cx18_retry_mmio)
-               return cx18_raw_readw_retry(cx, addr);
-
-       return cx18_raw_readw_noretry(cx, addr);
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+               cx18_writel_noretry(cx, val, addr);
+               if (val == cx18_readl(cx, addr))
+                       break;
+       }
 }
 
-
-/* Normal memory mapped IO */
 static inline
-void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
+void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr,
+                       u32 eval, u32 mask)
 {
-       writel(val, addr);
-       cx18_io_delay(cx);
+       int i;
+       u32 r;
+       eval &= mask;
+       for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
+               cx18_writel_noretry(cx, val, addr);
+               r = cx18_readl(cx, addr);
+               if (r == 0xffffffff && eval != 0xffffffff)
+                       continue;
+               if (eval == (r & mask))
+                       break;
+       }
 }
 
-void cx18_writel_retry(struct cx18 *cx, u32 val, void __iomem *addr);
-
-static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr)
+static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr)
 {
-       if (cx18_retry_mmio)
-               cx18_writel_retry(cx, val, addr);
-       else
-               cx18_writel_noretry(cx, val, addr);
+       return readw(addr);
 }
 
-void _cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr,
-                        u32 eval, u32 mask);
-
 static inline
 void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr)
 {
        writew(val, addr);
-       cx18_io_delay(cx);
 }
 
-void cx18_writew_retry(struct cx18 *cx, u16 val, void __iomem *addr);
-
 static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr)
 {
-       if (cx18_retry_mmio)
-               cx18_writew_retry(cx, val, addr);
-       else
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
                cx18_writew_noretry(cx, val, addr);
+               if (val == cx18_readw(cx, addr))
+                       break;
+       }
 }
 
+static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr)
+{
+       return readb(addr);
+}
 
 static inline
 void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr)
 {
        writeb(val, addr);
-       cx18_io_delay(cx);
 }
 
-void cx18_writeb_retry(struct cx18 *cx, u8 val, void __iomem *addr);
-
 static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr)
 {
-       if (cx18_retry_mmio)
-               cx18_writeb_retry(cx, val, addr);
-       else
+       int i;
+       for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) {
                cx18_writeb_noretry(cx, val, addr);
-}
-
-
-static inline u32 cx18_readl_noretry(struct cx18 *cx, const void __iomem *addr)
-{
-       u32 ret = readl(addr);
-       cx18_io_delay(cx);
-       return ret;
-}
-
-u32 cx18_readl_retry(struct cx18 *cx, const void __iomem *addr);
-
-static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr)
-{
-       if (cx18_retry_mmio)
-               return cx18_readl_retry(cx, addr);
-
-       return cx18_readl_noretry(cx, addr);
-}
-
-
-static inline u16 cx18_readw_noretry(struct cx18 *cx, const void __iomem *addr)
-{
-       u16 ret = readw(addr);
-       cx18_io_delay(cx);
-       return ret;
-}
-
-u16 cx18_readw_retry(struct cx18 *cx, const void __iomem *addr);
-
-static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr)
-{
-       if (cx18_retry_mmio)
-               return cx18_readw_retry(cx, addr);
-
-       return cx18_readw_noretry(cx, addr);
-}
-
-
-static inline u8 cx18_readb_noretry(struct cx18 *cx, const void __iomem *addr)
-{
-       u8 ret = readb(addr);
-       cx18_io_delay(cx);
-       return ret;
-}
-
-u8 cx18_readb_retry(struct cx18 *cx, const void __iomem *addr);
-
-static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr)
-{
-       if (cx18_retry_mmio)
-               return cx18_readb_retry(cx, addr);
-
-       return cx18_readb_noretry(cx, addr);
-}
-
-
-static inline
-u32 cx18_write_sync_noretry(struct cx18 *cx, u32 val, void __iomem *addr)
-{
-       cx18_writel_noretry(cx, val, addr);
-       return cx18_readl_noretry(cx, addr);
+               if (val == cx18_readb(cx, addr))
+                       break;
+       }
 }
 
 static inline
-u32 cx18_write_sync_retry(struct cx18 *cx, u32 val, void __iomem *addr)
-{
-       cx18_writel_retry(cx, val, addr);
-       return cx18_readl_retry(cx, addr);
-}
-
-static inline u32 cx18_write_sync(struct cx18 *cx, u32 val, void __iomem *addr)
+void cx18_memcpy_fromio(struct cx18 *cx, void *to,
+                       const void __iomem *from, unsigned int len)
 {
-       if (cx18_retry_mmio)
-               return cx18_write_sync_retry(cx, val, addr);
-
-       return cx18_write_sync_noretry(cx, val, addr);
+       memcpy_fromio(to, from, len);
 }
 
-
-void cx18_memcpy_fromio(struct cx18 *cx, void *to,
-                       const void __iomem *from, unsigned int len);
 void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count);
 
 
@@ -260,136 +153,39 @@ static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg)
        cx18_writel_noretry(cx, val, cx->reg_mem + reg);
 }
 
-static inline void cx18_write_reg_retry(struct cx18 *cx, u32 val, u32 reg)
-{
-       cx18_writel_retry(cx, val, cx->reg_mem + reg);
-}
-
 static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg)
 {
-       if (cx18_retry_mmio)
-               cx18_write_reg_retry(cx, val, reg);
-       else
-               cx18_write_reg_noretry(cx, val, reg);
-}
-
-static inline void _cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg,
-                                         u32 eval, u32 mask)
-{
-       _cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask);
+       cx18_writel(cx, val, cx->reg_mem + reg);
 }
 
 static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg,
                                         u32 eval, u32 mask)
 {
-       if (cx18_retry_mmio)
-               _cx18_write_reg_expect(cx, val, reg, eval, mask);
-       else
-               cx18_write_reg_noretry(cx, val, reg);
-}
-
-
-static inline u32 cx18_read_reg_noretry(struct cx18 *cx, u32 reg)
-{
-       return cx18_readl_noretry(cx, cx->reg_mem + reg);
-}
-
-static inline u32 cx18_read_reg_retry(struct cx18 *cx, u32 reg)
-{
-       return cx18_readl_retry(cx, cx->reg_mem + reg);
+       cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask);
 }
 
 static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg)
 {
-       if (cx18_retry_mmio)
-               return cx18_read_reg_retry(cx, reg);
-
-       return cx18_read_reg_noretry(cx, reg);
-}
-
-
-static inline u32 cx18_write_reg_sync_noretry(struct cx18 *cx, u32 val, u32 reg)
-{
-       return cx18_write_sync_noretry(cx, val, cx->reg_mem + reg);
-}
-
-static inline u32 cx18_write_reg_sync_retry(struct cx18 *cx, u32 val, u32 reg)
-{
-       return cx18_write_sync_retry(cx, val, cx->reg_mem + reg);
-}
-
-static inline u32 cx18_write_reg_sync(struct cx18 *cx, u32 val, u32 reg)
-{
-       if (cx18_retry_mmio)
-               return cx18_write_reg_sync_retry(cx, val, reg);
-
-       return cx18_write_reg_sync_noretry(cx, val, reg);
+       return cx18_readl(cx, cx->reg_mem + reg);
 }
 
 
 /* Access "encoder memory" region of CX23418 memory mapped I/O */
-static inline void cx18_write_enc_noretry(struct cx18 *cx, u32 val, u32 addr)
-{
-       cx18_writel_noretry(cx, val, cx->enc_mem + addr);
-}
-
-static inline void cx18_write_enc_retry(struct cx18 *cx, u32 val, u32 addr)
-{
-       cx18_writel_retry(cx, val, cx->enc_mem + addr);
-}
-
 static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr)
 {
-       if (cx18_retry_mmio)
-               cx18_write_enc_retry(cx, val, addr);
-       else
-               cx18_write_enc_noretry(cx, val, addr);
-}
-
-
-static inline u32 cx18_read_enc_noretry(struct cx18 *cx, u32 addr)
-{
-       return cx18_readl_noretry(cx, cx->enc_mem + addr);
-}
-
-static inline u32 cx18_read_enc_retry(struct cx18 *cx, u32 addr)
-{
-       return cx18_readl_retry(cx, cx->enc_mem + addr);
+       cx18_writel(cx, val, cx->enc_mem + addr);
 }
 
 static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr)
 {
-       if (cx18_retry_mmio)
-               return cx18_read_enc_retry(cx, addr);
-
-       return cx18_read_enc_noretry(cx, addr);
-}
-
-static inline
-u32 cx18_write_enc_sync_noretry(struct cx18 *cx, u32 val, u32 addr)
-{
-       return cx18_write_sync_noretry(cx, val, cx->enc_mem + addr);
-}
-
-static inline
-u32 cx18_write_enc_sync_retry(struct cx18 *cx, u32 val, u32 addr)
-{
-       return cx18_write_sync_retry(cx, val, cx->enc_mem + addr);
-}
-
-static inline
-u32 cx18_write_enc_sync(struct cx18 *cx, u32 val, u32 addr)
-{
-       if (cx18_retry_mmio)
-               return cx18_write_enc_sync_retry(cx, val, addr);
-
-       return cx18_write_enc_sync_noretry(cx, val, addr);
+       return cx18_readl(cx, cx->enc_mem + addr);
 }
 
 void cx18_sw1_irq_enable(struct cx18 *cx, u32 val);
 void cx18_sw1_irq_disable(struct cx18 *cx, u32 val);
 void cx18_sw2_irq_enable(struct cx18 *cx, u32 val);
 void cx18_sw2_irq_disable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val);
 void cx18_setup_page(struct cx18 *cx, u32 addr);
 
 #endif /* CX18_IO_H */
index f0ca50f5fddeb3d290d1567f8d27a4e9d1378230..e6087486f889d77b997c9eafd62ae01d69f0fbfa 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-ioctl.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -237,13 +238,12 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
        if (ret)
                return ret;
 
-       if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
-                       cx->vbi.sliced_in->service_set &&
-                       atomic_read(&cx->ana_capturing) > 0)
+       if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
                return -EBUSY;
 
        cx->vbi.sliced_in->service_set = 0;
-       cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+       cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+       cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
        return cx18_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -745,14 +745,12 @@ static int cx18_log_status(struct file *file, void *fh)
                        continue;
                CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
                          s->name, s->s_flags,
-                         (s->buffers - atomic_read(&s->q_free.buffers))
-                               * 100 / s->buffers,
+                         atomic_read(&s->q_full.buffers) * 100 / s->buffers,
                          (s->buffers * s->buf_size) / 1024, s->buffers);
        }
        CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
                        (long long)cx->mpg_data_received,
                        (long long)cx->vbi_data_inserted);
-       cx18_log_statistics(cx);
        CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);
        return 0;
 }
index 2222f679d86d5f2f68b7c5add6695a018242daca..08fe24e9510e816926b54714bd964271134ca28c 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-ioctl.h
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 5fbfbd0f14935eff36a19d27c8d852d8df2af483..af2f504eda2b3020efab592ffb834c08087b4d49 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 interrupt handling
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 
 #include "cx18-driver.h"
 #include "cx18-io.h"
-#include "cx18-firmware.h"
-#include "cx18-fileops.h"
-#include "cx18-queue.h"
 #include "cx18-irq.h"
-#include "cx18-ioctl.h"
 #include "cx18-mailbox.h"
-#include "cx18-vbi.h"
 #include "cx18-scb.h"
-#include "cx18-dvb.h"
-
-void cx18_work_handler(struct work_struct *work)
-{
-       struct cx18 *cx = container_of(work, struct cx18, work);
-       if (test_and_clear_bit(CX18_F_I_WORK_INITED, &cx->i_flags)) {
-               struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-               /* This thread must use the FIFO scheduler as it
-                * is realtime sensitive. */
-               sched_setscheduler(current, SCHED_FIFO, &param);
-       }
-       if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags))
-               cx18_dvb_work_handler(cx);
-}
-
-static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
-{
-       u32 handle = mb->args[0];
-       struct cx18_stream *s = NULL;
-       struct cx18_buffer *buf;
-       u32 off;
-       int i;
-       int id;
-
-       for (i = 0; i < CX18_MAX_STREAMS; i++) {
-               s = &cx->streams[i];
-               if ((handle == s->handle) && (s->dvb.enabled))
-                       break;
-               if (s->v4l2dev && handle == s->handle)
-                       break;
-       }
-       if (i == CX18_MAX_STREAMS) {
-               CX18_WARN("Got DMA done notification for unknown/inactive"
-                         " handle %d\n", handle);
-               mb->error = CXERR_NOT_OPEN;
-               mb->cmd = 0;
-               cx18_mb_ack(cx, mb);
-               return;
-       }
-
-       off = mb->args[1];
-       if (mb->args[2] != 1)
-               CX18_WARN("Ack struct = %d for %s\n",
-                       mb->args[2], s->name);
-       id = cx18_read_enc(cx, off);
-       buf = cx18_queue_get_buf_irq(s, id, cx18_read_enc(cx, off + 4));
-       CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
-       if (buf) {
-               cx18_buf_sync_for_cpu(s, buf);
-               if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
-                       CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
-                                       buf->bytesused);
-
-                       set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags);
-                       set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags);
-               } else
-                       set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
-       } else {
-               CX18_WARN("Could not find buf %d for stream %s\n",
-                               cx18_read_enc(cx, off), s->name);
-       }
-       mb->error = 0;
-       mb->cmd = 0;
-       cx18_mb_ack(cx, mb);
-       wake_up(&cx->dma_waitq);
-       if (s->id != -1)
-               wake_up(&s->waitq);
-}
-
-static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
-{
-       char str[256] = { 0 };
-       char *p;
-
-       if (mb->args[1]) {
-               cx18_setup_page(cx, mb->args[1]);
-               cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
-               str[252] = 0;
-       }
-       cx18_mb_ack(cx, mb);
-       CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
-       p = strchr(str, '.');
-       if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
-               CX18_INFO("FW version: %s\n", p - 1);
-}
-
-static void epu_cmd(struct cx18 *cx, u32 sw1)
-{
-       struct cx18_mailbox mb;
-
-       if (sw1 & IRQ_CPU_TO_EPU) {
-               cx18_memcpy_fromio(cx, &mb, &cx->scb->cpu2epu_mb, sizeof(mb));
-               mb.error = 0;
-
-               switch (mb.cmd) {
-               case CX18_EPU_DMA_DONE:
-                       epu_dma_done(cx, &mb);
-                       break;
-               case CX18_EPU_DEBUG:
-                       epu_debug(cx, &mb);
-                       break;
-               default:
-                       CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n",
-                                 mb.cmd);
-                       break;
-               }
-       }
-
-       if (sw1 & IRQ_APU_TO_EPU) {
-               cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb));
-               CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd);
-       }
-
-       if (sw1 & IRQ_HPU_TO_EPU) {
-               cx18_memcpy_fromio(cx, &mb, &cx->scb->hpu2epu_mb, sizeof(mb));
-               CX18_WARN("Unknown HPU_TO_EPU mailbox command %#08x\n", mb.cmd);
-       }
-}
 
 static void xpu_ack(struct cx18 *cx, u32 sw2)
 {
@@ -154,23 +32,24 @@ static void xpu_ack(struct cx18 *cx, u32 sw2)
                wake_up(&cx->mb_cpu_waitq);
        if (sw2 & IRQ_APU_TO_EPU_ACK)
                wake_up(&cx->mb_apu_waitq);
-       if (sw2 & IRQ_HPU_TO_EPU_ACK)
-               wake_up(&cx->mb_hpu_waitq);
+}
+
+static void epu_cmd(struct cx18 *cx, u32 sw1)
+{
+       if (sw1 & IRQ_CPU_TO_EPU)
+               cx18_api_epu_cmd_irq(cx, CPU);
+       if (sw1 & IRQ_APU_TO_EPU)
+               cx18_api_epu_cmd_irq(cx, APU);
 }
 
 irqreturn_t cx18_irq_handler(int irq, void *dev_id)
 {
        struct cx18 *cx = (struct cx18 *)dev_id;
-       u32 sw1, sw1_mask;
-       u32 sw2, sw2_mask;
-       u32 hw2, hw2_mask;
+       u32 sw1, sw2, hw2;
 
-       sw1_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI);
-       sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & sw1_mask;
-       sw2_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI);
-       sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & sw2_mask;
-       hw2_mask = cx18_read_reg(cx, HW2_INT_MASK5_PCI);
-       hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & hw2_mask;
+       sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask;
+       sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & cx->sw2_irq_mask;
+       hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & cx->hw2_irq_mask;
 
        if (sw1)
                cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1);
@@ -180,7 +59,15 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
                cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2);
 
        if (sw1 || sw2 || hw2)
-               CX18_DEBUG_HI_IRQ("SW1: %x  SW2: %x  HW2: %x\n", sw1, sw2, hw2);
+               CX18_DEBUG_HI_IRQ("received interrupts "
+                                 "SW1: %x  SW2: %x  HW2: %x\n", sw1, sw2, hw2);
+
+       /*
+        * SW1 responses have to happen first.  The sending XPU times out the
+        * incoming mailboxes on us rather rapidly.
+        */
+       if (sw1)
+               epu_cmd(cx, sw1);
 
        /* To do: interrupt-based I2C handling
        if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) {
@@ -190,11 +77,5 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
        if (sw2)
                xpu_ack(cx, sw2);
 
-       if (sw1)
-               epu_cmd(cx, sw1);
-
-       if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags))
-               queue_work(cx->work_queue, &cx->work);
-
        return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE;
 }
index 6173ca3bc9e4b74e9d2e211c6dd4ef6ea83be558..91f0b5278ef9fb0d5368a350a5e2698f9a5a6dd8 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 interrupt handling
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -28,8 +29,7 @@
 #define SW1_INT_ENABLE_PCI              0xc7311c
 #define SW2_INT_SET                     0xc73140
 #define SW2_INT_STATUS                  0xc73144
+#define SW2_INT_ENABLE_CPU              0xc73158
 #define SW2_INT_ENABLE_PCI              0xc7315c
 
 irqreturn_t cx18_irq_handler(int irq, void *dev_id);
-
-void cx18_work_handler(struct work_struct *work);
index acff7dfb60dfa4d57e8c88b39a22bdb7c9ec6c99..de5e723fdf445bbbbd66181c8ac26f5175f716e0 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 mailbox functions
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include "cx18-scb.h"
 #include "cx18-irq.h"
 #include "cx18-mailbox.h"
+#include "cx18-queue.h"
+#include "cx18-streams.h"
+
+static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" };
 
 #define API_FAST (1 << 2) /* Short timeout */
 #define API_SLOW (1 << 3) /* Additional 300ms timeout */
 
-#define APU 0
-#define CPU 1
-#define EPU 2
-#define HPU 3
-
 struct cx18_api_info {
        u32 cmd;
        u8 flags;               /* Flags, see above */
@@ -82,8 +82,9 @@ static const struct cx18_api_info api_info[] = {
        API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,                 0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,                     API_FAST),
-       API_ENTRY(CPU, CX18_APU_RESETAI,                        API_FAST),
        API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,                 API_SLOW),
+       API_ENTRY(APU, CX18_APU_RESETAI,                        0),
+       API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32,                   0),
        API_ENTRY(0, 0,                                         0),
 };
 
@@ -97,70 +98,175 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
        return NULL;
 }
 
-static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu,
-               u32 *state, u32 *irq, u32 *req)
+static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
 {
-       struct cx18_mailbox __iomem *mb = NULL;
-       int wait_count = 0;
-       u32 ack;
-
-       switch (rpu) {
-       case APU:
-               mb = &cx->scb->epu2apu_mb;
-               *state = cx18_readl(cx, &cx->scb->apu_state);
-               *irq = cx18_readl(cx, &cx->scb->epu2apu_irq);
-               break;
+       char argstr[MAX_MB_ARGUMENTS*11+1];
+       char *p;
+       int i;
 
-       case CPU:
-               mb = &cx->scb->epu2cpu_mb;
-               *state = cx18_readl(cx, &cx->scb->cpu_state);
-               *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq);
-               break;
+       if (!(cx18_debug & CX18_DBGFLG_API))
+               return;
 
-       case HPU:
-               mb = &cx->scb->epu2hpu_mb;
-               *state = cx18_readl(cx, &cx->scb->hpu_state);
-               *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq);
-               break;
+       for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) {
+               /* kernel snprintf() appends '\0' always */
+               snprintf(p, 12, " %#010x", mb->args[i]);
        }
+       CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s"
+               "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr);
+}
 
-       if (mb == NULL)
-               return mb;
 
-       do {
-               *req = cx18_readl(cx, &mb->request);
-               ack = cx18_readl(cx, &mb->ack);
-               wait_count++;
-       } while (*req != ack && wait_count < 600);
+/*
+ * Functions that run in a work_queue work handling context
+ */
 
-       if (*req == ack) {
-               (*req)++;
-               if (*req == 0 || *req == 0xffffffff)
-                       *req = 1;
-               return mb;
+static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       u32 handle, mdl_ack_count, id;
+       struct cx18_mailbox *mb;
+       struct cx18_mdl_ack *mdl_ack;
+       struct cx18_stream *s;
+       struct cx18_buffer *buf;
+       int i;
+
+       mb = &order->mb;
+       handle = mb->args[0];
+       s = cx18_handle_to_stream(cx, handle);
+
+       if (s == NULL) {
+               CX18_WARN("Got DMA done notification for unknown/inactive"
+                         " handle %d, %s mailbox seq no %d\n", handle,
+                         (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ?
+                         "stale" : "good", mb->request);
+               return;
        }
-       return NULL;
+
+       mdl_ack_count = mb->args[2];
+       mdl_ack = order->mdl_ack;
+       for (i = 0; i < mdl_ack_count; i++, mdl_ack++) {
+               id = mdl_ack->id;
+               /*
+                * Simple integrity check for processing a stale (and possibly
+                * inconsistent mailbox): make sure the buffer id is in the
+                * valid range for the stream.
+                *
+                * We go through the trouble of dealing with stale mailboxes
+                * because most of the time, the mailbox data is still valid and
+                * unchanged (and in practice the firmware ping-pongs the
+                * two mdl_ack buffers so mdl_acks are not stale).
+                *
+                * There are occasions when we get a half changed mailbox,
+                * which this check catches for a handle & id mismatch.  If the
+                * handle and id do correspond, the worst case is that we
+                * completely lost the old buffer, but pick up the new buffer
+                * early (but the new mdl_ack is guaranteed to be good in this
+                * case as the firmware wouldn't point us to a new mdl_ack until
+                * it's filled in).
+                *
+                * cx18_queue_get buf() will detect the lost buffers
+                * and send them back to q_free for fw rotation eventually.
+                */
+               if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
+                   !(id >= s->mdl_offset &&
+                     id < (s->mdl_offset + s->buffers))) {
+                       CX18_WARN("Fell behind! Ignoring stale mailbox with "
+                                 " inconsistent data. Lost buffer for mailbox "
+                                 "seq no %d\n", mb->request);
+                       break;
+               }
+               buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
+
+               CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
+               if (buf == NULL) {
+                       CX18_WARN("Could not find buf %d for stream %s\n",
+                                 id, s->name);
+                       /* Put as many buffers as possible back into fw use */
+                       cx18_stream_load_fw_queue(s);
+                       continue;
+               }
+
+               if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
+                       CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
+                                         buf->bytesused);
+                       dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+                                        buf->bytesused);
+               }
+               /* Put as many buffers as possible back into fw use */
+               cx18_stream_load_fw_queue(s);
+               /* Put back TS buffer, since it was removed from all queues */
+               if (s->type == CX18_ENC_STREAM_TYPE_TS)
+                       cx18_stream_put_buf_fw(s, buf);
+       }
+       wake_up(&cx->dma_waitq);
+       if (s->id != -1)
+               wake_up(&s->waitq);
 }
 
-long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
+static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
 {
-       const struct cx18_api_info *info = find_api_info(mb->cmd);
-       struct cx18_mailbox __iomem *ack_mb;
-       u32 ack_irq;
-       u8 rpu = CPU;
+       char *p;
+       char *str = order->str;
 
-       if (info == NULL && mb->cmd) {
-               CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
-               return -EINVAL;
-       }
-       if (info)
-               rpu = info->rpu;
+       CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str);
+       p = strchr(str, '.');
+       if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
+               CX18_INFO("FW version: %s\n", p - 1);
+}
 
-       switch (rpu) {
-       case HPU:
-               ack_irq = IRQ_EPU_TO_HPU_ACK;
-               ack_mb = &cx->scb->hpu2epu_mb;
+static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       switch (order->rpu) {
+       case CPU:
+       {
+               switch (order->mb.cmd) {
+               case CX18_EPU_DMA_DONE:
+                       epu_dma_done(cx, order);
+                       break;
+               case CX18_EPU_DEBUG:
+                       epu_debug(cx, order);
+                       break;
+               default:
+                       CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
+                                 order->mb.cmd);
+                       break;
+               }
                break;
+       }
+       case APU:
+               CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
+                         order->mb.cmd);
+               break;
+       default:
+               break;
+       }
+}
+
+static
+void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       atomic_set(&order->pending, 0);
+}
+
+void cx18_epu_work_handler(struct work_struct *work)
+{
+       struct cx18_epu_work_order *order =
+                       container_of(work, struct cx18_epu_work_order, work);
+       struct cx18 *cx = order->cx;
+       epu_cmd(cx, order);
+       free_epu_work_order(cx, order);
+}
+
+
+/*
+ * Functions that run in an interrupt handling context
+ */
+
+static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       struct cx18_mailbox __iomem *ack_mb;
+       u32 ack_irq, req;
+
+       switch (order->rpu) {
        case APU:
                ack_irq = IRQ_EPU_TO_APU_ACK;
                ack_mb = &cx->scb->apu2epu_mb;
@@ -170,26 +276,197 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
                ack_mb = &cx->scb->cpu2epu_mb;
                break;
        default:
-               CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
-               return -EINVAL;
+               CX18_WARN("Unhandled RPU (%d) for command %x ack\n",
+                         order->rpu, order->mb.cmd);
+               return;
        }
 
-       cx18_setup_page(cx, SCB_OFFSET);
-       cx18_write_sync(cx, mb->request, &ack_mb->ack);
+       req = order->mb.request;
+       /* Don't ack if the RPU has gotten impatient and timed us out */
+       if (req != cx18_readl(cx, &ack_mb->request) ||
+           req == cx18_readl(cx, &ack_mb->ack)) {
+               CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
+                               "incoming %s to EPU mailbox (sequence no. %u) "
+                               "while processing\n",
+                               rpu_str[order->rpu], rpu_str[order->rpu], req);
+               order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC;
+               return;
+       }
+       cx18_writel(cx, req, &ack_mb->ack);
        cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq);
-       return 0;
+       return;
+}
+
+static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       u32 handle, mdl_ack_offset, mdl_ack_count;
+       struct cx18_mailbox *mb;
+
+       mb = &order->mb;
+       handle = mb->args[0];
+       mdl_ack_offset = mb->args[1];
+       mdl_ack_count = mb->args[2];
+
+       if (handle == CX18_INVALID_TASK_HANDLE ||
+           mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) {
+               if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
+                       mb_ack_irq(cx, order);
+               return -1;
+       }
+
+       cx18_memcpy_fromio(cx, order->mdl_ack, cx->enc_mem + mdl_ack_offset,
+                          sizeof(struct cx18_mdl_ack) * mdl_ack_count);
+
+       if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
+               mb_ack_irq(cx, order);
+       return 1;
+}
+
+static
+int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       u32 str_offset;
+       char *str = order->str;
+
+       str[0] = '\0';
+       str_offset = order->mb.args[1];
+       if (str_offset) {
+               cx18_setup_page(cx, str_offset);
+               cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252);
+               str[252] = '\0';
+               cx18_setup_page(cx, SCB_OFFSET);
+       }
+
+       if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
+               mb_ack_irq(cx, order);
+
+       return str_offset ? 1 : 0;
 }
 
+static inline
+int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+{
+       int ret = -1;
+
+       switch (order->rpu) {
+       case CPU:
+       {
+               switch (order->mb.cmd) {
+               case CX18_EPU_DMA_DONE:
+                       ret = epu_dma_done_irq(cx, order);
+                       break;
+               case CX18_EPU_DEBUG:
+                       ret = epu_debug_irq(cx, order);
+                       break;
+               default:
+                       CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
+                                 order->mb.cmd);
+                       break;
+               }
+               break;
+       }
+       case APU:
+               CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
+                         order->mb.cmd);
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+static inline
+struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
+{
+       int i;
+       struct cx18_epu_work_order *order = NULL;
+
+       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
+               /*
+                * We only need "pending" atomic to inspect its contents,
+                * and need not do a check and set because:
+                * 1. Any work handler thread only clears "pending" and only
+                * on one, particular work order at a time, per handler thread.
+                * 2. "pending" is only set here, and we're serialized because
+                * we're called in an IRQ handler context.
+                */
+               if (atomic_read(&cx->epu_work_order[i].pending) == 0) {
+                       order = &cx->epu_work_order[i];
+                       atomic_set(&order->pending, 1);
+                       break;
+               }
+       }
+       return order;
+}
+
+void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
+{
+       struct cx18_mailbox __iomem *mb;
+       struct cx18_mailbox *order_mb;
+       struct cx18_epu_work_order *order;
+       int submit;
+
+       switch (rpu) {
+       case CPU:
+               mb = &cx->scb->cpu2epu_mb;
+               break;
+       case APU:
+               mb = &cx->scb->apu2epu_mb;
+               break;
+       default:
+               return;
+       }
+
+       order = alloc_epu_work_order_irq(cx);
+       if (order == NULL) {
+               CX18_WARN("Unable to find blank work order form to schedule "
+                         "incoming mailbox command processing\n");
+               return;
+       }
+
+       order->flags = 0;
+       order->rpu = rpu;
+       order_mb = &order->mb;
+
+       /* mb->cmd and mb->args[0] through mb->args[2] */
+       cx18_memcpy_fromio(cx, &order_mb->cmd, &mb->cmd, 4 * sizeof(u32));
+       /* mb->request and mb->ack.  N.B. we want to read mb->ack last */
+       cx18_memcpy_fromio(cx, &order_mb->request, &mb->request,
+                          2 * sizeof(u32));
+
+       if (order_mb->request == order_mb->ack) {
+               CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
+                               "incoming %s to EPU mailbox (sequence no. %u)"
+                               "\n",
+                               rpu_str[rpu], rpu_str[rpu], order_mb->request);
+               dump_mb(cx, order_mb, "incoming");
+               order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
+       }
+
+       /*
+        * Individual EPU command processing is responsible for ack-ing
+        * a non-stale mailbox as soon as possible
+        */
+       submit = epu_cmd_irq(cx, order);
+       if (submit > 0) {
+               queue_work(cx->work_queue, &order->work);
+       }
+}
+
+
+/*
+ * Functions called from a non-interrupt, non work_queue context
+ */
 
 static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 {
        const struct cx18_api_info *info = find_api_info(cmd);
-       u32 state = 0, irq = 0, req, oldreq, err;
+       u32 state, irq, req, ack, err;
        struct cx18_mailbox __iomem *mb;
+       u32 __iomem *xpu_state;
        wait_queue_head_t *waitq;
-       int timeout = 100;
-       int cnt = 0;
-       int sig = 0;
+       struct mutex *mb_lock;
+       long int timeout, ret;
        int i;
 
        if (info == NULL) {
@@ -201,50 +478,104 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
                CX18_DEBUG_HI_API("%s\n", info->name);
        else
                CX18_DEBUG_API("%s\n", info->name);
-       cx18_setup_page(cx, SCB_OFFSET);
-       mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
 
-       if (mb == NULL) {
-               CX18_ERR("mb %s busy\n", info->name);
-               return -EBUSY;
+       switch (info->rpu) {
+       case APU:
+               waitq = &cx->mb_apu_waitq;
+               mb_lock = &cx->epu2apu_mb_lock;
+               irq = IRQ_EPU_TO_APU;
+               mb = &cx->scb->epu2apu_mb;
+               xpu_state = &cx->scb->apu_state;
+               break;
+       case CPU:
+               waitq = &cx->mb_cpu_waitq;
+               mb_lock = &cx->epu2cpu_mb_lock;
+               irq = IRQ_EPU_TO_CPU;
+               mb = &cx->scb->epu2cpu_mb;
+               xpu_state = &cx->scb->cpu_state;
+               break;
+       default:
+               CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu);
+               return -EINVAL;
        }
 
-       oldreq = req - 1;
+       mutex_lock(mb_lock);
+       /*
+        * Wait for an in-use mailbox to complete
+        *
+        * If the XPU is responding with Ack's, the mailbox shouldn't be in
+        * a busy state, since we serialize access to it on our end.
+        *
+        * If the wait for ack after sending a previous command was interrupted
+        * by a signal, we may get here and find a busy mailbox.  After waiting,
+        * mark it "not busy" from our end, if the XPU hasn't ack'ed it still.
+        */
+       state = cx18_readl(cx, xpu_state);
+       req = cx18_readl(cx, &mb->request);
+       timeout = msecs_to_jiffies(10);
+       ret = wait_event_timeout(*waitq,
+                                (ack = cx18_readl(cx, &mb->ack)) == req,
+                                timeout);
+       if (req != ack) {
+               /* waited long enough, make the mbox "not busy" from our end */
+               cx18_writel(cx, req, &mb->ack);
+               CX18_ERR("mbox was found stuck busy when setting up for %s; "
+                        "clearing busy and trying to proceed\n", info->name);
+       } else if (ret != timeout)
+               CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n",
+                              jiffies_to_msecs(timeout-ret));
+
+       /* Build the outgoing mailbox */
+       req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1;
+
        cx18_writel(cx, cmd, &mb->cmd);
        for (i = 0; i < args; i++)
                cx18_writel(cx, data[i], &mb->args[i]);
        cx18_writel(cx, 0, &mb->error);
        cx18_writel(cx, req, &mb->request);
+       cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */
 
-       switch (info->rpu) {
-       case APU: waitq = &cx->mb_apu_waitq; break;
-       case CPU: waitq = &cx->mb_cpu_waitq; break;
-       case EPU: waitq = &cx->mb_epu_waitq; break;
-       case HPU: waitq = &cx->mb_hpu_waitq; break;
-       default: return -EINVAL;
-       }
-       if (info->flags & API_FAST)
-               timeout /= 2;
+       /*
+        * Notify the XPU and wait for it to send an Ack back
+        */
+       timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20);
+
+       CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
+                         irq, info->name);
        cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
 
-       while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request)
-              && cnt < 660) {
-               if (cnt > 200 && !in_atomic())
-                       sig = cx18_msleep_timeout(10, 1);
-               cnt++;
-       }
-       if (sig)
-               return -EINTR;
-       if (cnt == 660) {
-               cx18_writel(cx, oldreq, &mb->request);
-               CX18_ERR("mb %s failed\n", info->name);
+       ret = wait_event_timeout(
+                      *waitq,
+                      cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
+                      timeout);
+
+       if (ret == 0) {
+               /* Timed out */
+               mutex_unlock(mb_lock);
+               CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU "
+                               "acknowledgement\n",
+                               info->name, jiffies_to_msecs(timeout));
                return -EINVAL;
        }
+
+       if (ret != timeout)
+               CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
+                                 jiffies_to_msecs(timeout-ret), info->name);
+
+       /* Collect data returned by the XPU */
        for (i = 0; i < MAX_MB_ARGUMENTS; i++)
                data[i] = cx18_readl(cx, &mb->args[i]);
        err = cx18_readl(cx, &mb->error);
-       if (!in_atomic() && (info->flags & API_SLOW))
+       mutex_unlock(mb_lock);
+
+       /*
+        * Wait for XPU to perform extra actions for the caller in some cases.
+        * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers
+        * back in a burst shortly thereafter
+        */
+       if (info->flags & API_SLOW)
                cx18_msleep_timeout(300, 0);
+
        if (err)
                CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
                                info->name);
@@ -253,12 +584,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 
 int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
 {
-       int res = cx18_api_call(cx, cmd, args, data);
-
-       /* Allow a single retry, probably already too late though.
-          If there is no free mailbox then that is usually an indication
-          of a more serious problem. */
-       return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
+       return cx18_api_call(cx, cmd, args, data);
 }
 
 static int cx18_set_filter_param(struct cx18_stream *s)
@@ -281,8 +607,9 @@ static int cx18_set_filter_param(struct cx18_stream *s)
 int cx18_api_func(void *priv, u32 cmd, int in, int out,
                u32 data[CX2341X_MBOX_MAX_DATA])
 {
-       struct cx18 *cx = priv;
-       struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+       struct cx18_api_func_private *api_priv = priv;
+       struct cx18 *cx = api_priv->cx;
+       struct cx18_stream *s = api_priv->s;
 
        switch (cmd) {
        case CX2341X_ENC_SET_OUTPUT_PORT:
index d995641536b3dc3c917a1f254ada9c7cccd4bdaf..ce2b6686aa005268363be2335ea61ba0910a001f 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 mailbox functions
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #define MB_RESERVED_HANDLE_0 0
 #define MB_RESERVED_HANDLE_1 0xFFFFFFFF
 
+#define APU 0
+#define CPU 1
+#define EPU 2
+#define HPU 3
+
 struct cx18;
 
+/*
+ * This structure is used by CPU to provide completed buffers information
+ * Its structure is dictrated by the layout of the SCB, required by the
+ * firmware, but its defintion needs to be here, instead of in cx18-scb.h,
+ * for mailbox work order scheduling
+ */
+struct cx18_mdl_ack {
+    u32 id;        /* ID of a completed MDL */
+    u32 data_used; /* Total data filled in the MDL for buffer 'id' */
+};
+
 /* The cx18_mailbox struct is the mailbox structure which is used for passing
    messages between processors */
 struct cx18_mailbox {
@@ -62,12 +79,22 @@ struct cx18_mailbox {
     u32       error;
 };
 
+struct cx18_stream;
+
+struct cx18_api_func_private {
+       struct cx18 *cx;
+       struct cx18_stream *s;
+};
+
 int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
 int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
                int args, ...);
 int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
 int cx18_api_func(void *priv, u32 cmd, int in, int out,
                u32 data[CX2341X_MBOX_MAX_DATA]);
-long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb);
+
+void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu);
+
+void cx18_epu_work_handler(struct work_struct *work);
 
 #endif
index 174682c2582f4ec1d3d48900f7ae15723d9e6234..8d9441e88c4ef4f2a62b0a564576c20f78f6560d 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-queue.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -41,91 +42,126 @@ void cx18_queue_init(struct cx18_queue *q)
        q->bytesused = 0;
 }
 
-void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
-               struct cx18_queue *q)
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+                                struct cx18_queue *q, int to_front)
 {
-       unsigned long flags = 0;
-
-       /* clear the buffer if it is going to be enqueued to the free queue */
-       if (q == &s->q_free) {
+       /* clear the buffer if it is not to be enqueued to the full queue */
+       if (q != &s->q_full) {
                buf->bytesused = 0;
                buf->readpos = 0;
                buf->b_flags = 0;
+               buf->skipped = 0;
        }
-       spin_lock_irqsave(&s->qlock, flags);
-       list_add_tail(&buf->list, &q->list);
-       atomic_inc(&q->buffers);
+
+       mutex_lock(&s->qlock);
+
+       /* q_busy is restricted to a max buffer count imposed by firmware */
+       if (q == &s->q_busy &&
+           atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
+               q = &s->q_free;
+
+       if (to_front)
+               list_add(&buf->list, &q->list); /* LIFO */
+       else
+               list_add_tail(&buf->list, &q->list); /* FIFO */
        q->bytesused += buf->bytesused - buf->readpos;
-       spin_unlock_irqrestore(&s->qlock, flags);
+       atomic_inc(&q->buffers);
+
+       mutex_unlock(&s->qlock);
+       return q;
 }
 
 struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
 {
        struct cx18_buffer *buf = NULL;
-       unsigned long flags = 0;
 
-       spin_lock_irqsave(&s->qlock, flags);
+       mutex_lock(&s->qlock);
        if (!list_empty(&q->list)) {
-               buf = list_entry(q->list.next, struct cx18_buffer, list);
-               list_del_init(q->list.next);
-               atomic_dec(&q->buffers);
+               buf = list_first_entry(&q->list, struct cx18_buffer, list);
+               list_del_init(&buf->list);
                q->bytesused -= buf->bytesused - buf->readpos;
+               buf->skipped = 0;
+               atomic_dec(&q->buffers);
        }
-       spin_unlock_irqrestore(&s->qlock, flags);
+       mutex_unlock(&s->qlock);
        return buf;
 }
 
-struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
        u32 bytesused)
 {
        struct cx18 *cx = s->cx;
-       struct list_head *p;
-
-       spin_lock(&s->qlock);
-       list_for_each(p, &s->q_free.list) {
-               struct cx18_buffer *buf =
-                       list_entry(p, struct cx18_buffer, list);
-
-               if (buf->id != id)
+       struct cx18_buffer *buf;
+       struct cx18_buffer *tmp;
+       struct cx18_buffer *ret = NULL;
+
+       mutex_lock(&s->qlock);
+       list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) {
+               if (buf->id != id) {
+                       buf->skipped++;
+                       if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
+                               /* buffer must have fallen out of rotation */
+                               CX18_WARN("Skipped %s, buffer %d, %d "
+                                         "times - it must have dropped out of "
+                                         "rotation\n", s->name, buf->id,
+                                         buf->skipped);
+                               /* move it to q_free */
+                               list_move_tail(&buf->list, &s->q_free.list);
+                               buf->bytesused = buf->readpos = buf->b_flags =
+                                       buf->skipped = 0;
+                               atomic_dec(&s->q_busy.buffers);
+                               atomic_inc(&s->q_free.buffers);
+                       }
                        continue;
+               }
 
                buf->bytesused = bytesused;
-               atomic_dec(&s->q_free.buffers);
-               atomic_inc(&s->q_full.buffers);
-               s->q_full.bytesused += buf->bytesused;
-               list_move_tail(&buf->list, &s->q_full.list);
+               /* Sync the buffer before we release the qlock */
+               cx18_buf_sync_for_cpu(s, buf);
+               if (s->type == CX18_ENC_STREAM_TYPE_TS) {
+                       /*
+                        * TS doesn't use q_full.  As we pull the buffer off of
+                        * the queue here, the caller will have to put it back.
+                        */
+                       list_del_init(&buf->list);
+               } else {
+                       /* Move buffer from q_busy to q_full */
+                       list_move_tail(&buf->list, &s->q_full.list);
+                       set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+                       s->q_full.bytesused += buf->bytesused;
+                       atomic_inc(&s->q_full.buffers);
+               }
+               atomic_dec(&s->q_busy.buffers);
 
-               spin_unlock(&s->qlock);
-               return buf;
+               ret = buf;
+               break;
        }
-       spin_unlock(&s->qlock);
-       CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
-       return NULL;
+       mutex_unlock(&s->qlock);
+       return ret;
 }
 
 /* Move all buffers of a queue to q_free, while flushing the buffers */
 static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
 {
-       unsigned long flags;
        struct cx18_buffer *buf;
 
        if (q == &s->q_free)
                return;
 
-       spin_lock_irqsave(&s->qlock, flags);
+       mutex_lock(&s->qlock);
        while (!list_empty(&q->list)) {
-               buf = list_entry(q->list.next, struct cx18_buffer, list);
-               list_move_tail(q->list.next, &s->q_free.list);
-               buf->bytesused = buf->readpos = buf->b_flags = 0;
+               buf = list_first_entry(&q->list, struct cx18_buffer, list);
+               list_move_tail(&buf->list, &s->q_free.list);
+               buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0;
                atomic_inc(&s->q_free.buffers);
        }
        cx18_queue_init(q);
-       spin_unlock_irqrestore(&s->qlock, flags);
+       mutex_unlock(&s->qlock);
 }
 
 void cx18_flush_queues(struct cx18_stream *s)
 {
-       cx18_queue_flush(s, &s->q_io);
+       cx18_queue_flush(s, &s->q_busy);
        cx18_queue_flush(s, &s->q_full);
 }
 
index 7f93bb13c09f6b53de8848451475e00c5ea6b8c1..456cec3bc28f2b9a193f75fd2179209c6f8d11b6 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-queue.h
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -42,11 +43,26 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
 void cx18_buf_swap(struct cx18_buffer *buf);
 
 /* cx18_queue utility functions */
+struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+                                struct cx18_queue *q, int to_front);
+
+static inline
+struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+                               struct cx18_queue *q)
+{
+       return _cx18_enqueue(s, buf, q, 0); /* FIFO */
+}
+
+static inline
+struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf,
+                            struct cx18_queue *q)
+{
+       return _cx18_enqueue(s, buf, q, 1); /* LIFO */
+}
+
 void cx18_queue_init(struct cx18_queue *q);
-void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
-       struct cx18_queue *q);
 struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
-struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
+struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
        u32 bytesused);
 void cx18_flush_queues(struct cx18_stream *s);
 
index f56d3772aa675bdb60464fc14ff3f4052ea7cb0b..34b4d03c55cda9692668ce05a0a12aa818aa22f7 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 System Control Block initialization
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -117,6 +118,5 @@ void cx18_init_scb(struct cx18 *cx)
        cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
                        &cx->scb->ipc_offset);
 
-       cx18_writel(cx, 1, &cx->scb->hpu_state);
        cx18_writel(cx, 1, &cx->scb->epu_state);
 }
index 594713bbed6892eb214cf16e867349e60f52b3f8..1dc1c431f5a14c9a7241937a73ab61621508f0ee 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 System Control Block initialization
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -85,12 +86,6 @@ struct cx18_mdl {
     u32 length; /* Length of the buffer segment */
 };
 
-/* This structure is used by CPU to provide completed buffers information */
-struct cx18_mdl_ack {
-    u32 id;        /* ID of a completed MDL */
-    u32 data_used; /* Total data filled in the MDL for buffer 'id' */
-};
-
 struct cx18_scb {
        /* These fields form the System Control Block which is used at boot time
           for localizing the IPC data as well as the code positions for all
@@ -276,7 +271,7 @@ struct cx18_scb {
        struct cx18_mailbox  hpu2epu_mb;
        struct cx18_mailbox  ppu2epu_mb;
 
-       struct cx18_mdl_ack  cpu_mdl_ack[CX18_MAX_STREAMS][2];
+       struct cx18_mdl_ack  cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS];
        struct cx18_mdl      cpu_mdl[1];
 };
 
index e5ff7705b7a134c8495566b264c1621b65071f32..63c336c95ff5005e9220361b55c6347fdb7ec401 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-streams.c
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -110,7 +111,6 @@ static void cx18_stream_init(struct cx18 *cx, int type)
 {
        struct cx18_stream *s = &cx->streams[type];
        struct video_device *dev = s->v4l2dev;
-       u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
 
        /* we need to keep v4l2dev, so restore it afterwards */
        memset(s, 0, sizeof(*s));
@@ -123,21 +123,15 @@ static void cx18_stream_init(struct cx18 *cx, int type)
        s->handle = CX18_INVALID_TASK_HANDLE;
 
        s->dma = cx18_stream_info[type].dma;
+       s->buffers = cx->stream_buffers[type];
        s->buf_size = cx->stream_buf_size[type];
-       if (s->buf_size)
-               s->buffers = max_size / s->buf_size;
-       if (s->buffers > 63) {
-               /* Each stream has a maximum of 63 buffers,
-                  ensure we do not exceed that. */
-               s->buffers = 63;
-               s->buf_size = (max_size / s->buffers) & ~0xfff;
-       }
-       spin_lock_init(&s->qlock);
+
+       mutex_init(&s->qlock);
        init_waitqueue_head(&s->waitq);
        s->id = -1;
        cx18_queue_init(&s->q_free);
+       cx18_queue_init(&s->q_busy);
        cx18_queue_init(&s->q_full);
-       cx18_queue_init(&s->q_io);
 }
 
 static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -167,7 +161,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
        /* User explicitly selected 0 buffers for these streams, so don't
           create them. */
        if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
-           cx->options.megabytes[type] == 0) {
+           cx->stream_buffers[type] == 0) {
                CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
                return 0;
        }
@@ -267,8 +261,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
 
        switch (vfl_type) {
        case VFL_TYPE_GRABBER:
-               CX18_INFO("Registered device video%d for %s (%d MB)\n",
-                       num, s->name, cx->options.megabytes[type]);
+               CX18_INFO("Registered device video%d for %s (%d x %d kB)\n",
+                         num, s->name, cx->stream_buffers[type],
+                         cx->stream_buf_size[type]/1024);
                break;
 
        case VFL_TYPE_RADIO:
@@ -277,10 +272,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
                break;
 
        case VFL_TYPE_VBI:
-               if (cx->options.megabytes[type])
-                       CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
-                               num,
-                               s->name, cx->options.megabytes[type]);
+               if (cx->stream_buffers[type])
+                       CX18_INFO("Registered device vbi%d for %s "
+                                 "(%d x %d bytes)\n",
+                                 num, s->name, cx->stream_buffers[type],
+                                 cx->stream_buf_size[type]);
                else
                        CX18_INFO("Registered device vbi%d for %s\n",
                                num, s->name);
@@ -344,7 +340,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
 static void cx18_vbi_setup(struct cx18_stream *s)
 {
        struct cx18 *cx = s->cx;
-       int raw = cx->vbi.sliced_in->service_set == 0;
+       int raw = cx18_raw_vbi(cx);
        u32 data[CX2341X_MBOX_MAX_DATA];
        int lines;
 
@@ -362,8 +358,7 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
 
        /* determine number of lines and total number of VBI bytes.
-          A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
-          The '- 1' byte is probably an unused U or V byte. Or something...
+          A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720
           A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
           header, 42 data bytes + checksum (to be confirmed) */
        if (raw) {
@@ -381,14 +376,15 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        /* Lines per field */
        data[1] = (lines / 2) | ((lines / 2) << 16);
        /* bytes per line */
-       data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+       data[2] = (raw ? cx->vbi.raw_decoder_line_size
+                      : cx->vbi.sliced_decoder_line_size);
        /* Every X number of frames a VBI interrupt arrives
           (frames as in 25 or 30 fps) */
        data[3] = 1;
        /* Setup VBI for the cx25840 digitizer */
        if (raw) {
                data[4] = 0x20602060;
-               data[5] = 0x30703070;
+               data[5] = 0x307090d0;
        } else {
                data[4] = 0xB0F0B0F0;
                data[5] = 0xA0E0A0E0;
@@ -401,11 +397,52 @@ static void cx18_vbi_setup(struct cx18_stream *s)
                cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
 }
 
+struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+                                         struct cx18_buffer *buf)
+{
+       struct cx18 *cx = s->cx;
+       struct cx18_queue *q;
+
+       /* Don't give it to the firmware, if we're not running a capture */
+       if (s->handle == CX18_INVALID_TASK_HANDLE ||
+           !test_bit(CX18_F_S_STREAMING, &s->s_flags))
+               return cx18_enqueue(s, buf, &s->q_free);
+
+       q = cx18_enqueue(s, buf, &s->q_busy);
+       if (q != &s->q_busy)
+               return q; /* The firmware has the max buffers it can handle */
+
+       cx18_buf_sync_for_device(s, buf);
+       cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+                 (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+                 1, buf->id, s->buf_size);
+       return q;
+}
+
+void cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+       struct cx18_queue *q;
+       struct cx18_buffer *buf;
+
+       if (atomic_read(&s->q_free.buffers) == 0 ||
+           atomic_read(&s->q_busy.buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
+               return;
+
+       /* Move from q_free to q_busy notifying the firmware, until the limit */
+       do {
+               buf = cx18_dequeue(s, &s->q_free);
+               if (buf == NULL)
+                       break;
+               q = cx18_stream_put_buf_fw(s, buf);
+       } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM
+                && q == &s->q_busy);
+}
+
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 {
        u32 data[MAX_MB_ARGUMENTS];
        struct cx18 *cx = s->cx;
-       struct list_head *p;
+       struct cx18_buffer *buf;
        int ts = 0;
        int captype = 0;
 
@@ -434,8 +471,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                captype = CAPTURE_CHANNEL_TYPE_PCM;
                break;
        case CX18_ENC_STREAM_TYPE_VBI:
-               captype = cx->vbi.sliced_in->service_set ?
-                   CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+               captype = cx18_raw_vbi(cx) ?
+                    CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
                cx->vbi.frame = 0;
                cx->vbi.inserted_frame = 0;
                memset(cx->vbi.sliced_mpeg_size,
@@ -457,6 +494,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
        cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
 
        if (atomic_read(&cx->ana_capturing) == 0 && !ts) {
+               struct cx18_api_func_private priv;
+
                /* Stuff from Windows, we don't know what it is */
                cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
                cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
@@ -476,7 +515,9 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
 
                /* Setup API for Stream */
-               cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
+               priv.cx = cx;
+               priv.s = s;
+               cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
        }
 
        if (atomic_read(&cx->tot_capturing) == 0) {
@@ -488,16 +529,17 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
                (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
 
-       list_for_each(p, &s->q_free.list) {
-               struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
-
+       /* Init all the cpu_mdls for this stream */
+       cx18_flush_queues(s);
+       mutex_lock(&s->qlock);
+       list_for_each_entry(buf, &s->q_free.list, list) {
                cx18_writel(cx, buf->dma_handle,
                                        &cx->scb->cpu_mdl[buf->id].paddr);
                cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
-               cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
-                       (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
-                       1, buf->id, s->buf_size);
        }
+       mutex_unlock(&s->qlock);
+       cx18_stream_load_fw_queue(s);
+
        /* begin_capture */
        if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
                CX18_DEBUG_WARN("Error starting capture!\n");
@@ -506,9 +548,15 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                        cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
                else
                        cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+               clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+               /* FIXME - CX18_F_S_STREAMOFF as well? */
                cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
                cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
-               /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */
+               s->handle = CX18_INVALID_TASK_HANDLE;
+               if (atomic_read(&cx->tot_capturing) == 0) {
+                       set_bit(CX18_F_I_EOS, &cx->i_flags);
+                       cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
+               }
                return -EINVAL;
        }
 
@@ -560,9 +608,6 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
                CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
        }
 
-       /* Tell the CX23418 it can't use our buffers anymore */
-       cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
-
        if (s->type != CX18_ENC_STREAM_TYPE_TS)
                atomic_dec(&cx->ana_capturing);
        atomic_dec(&cx->tot_capturing);
@@ -570,6 +615,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
        /* Clear capture and no-read bits */
        clear_bit(CX18_F_S_STREAMING, &s->s_flags);
 
+       /* Tell the CX23418 it can't use our buffers anymore */
+       cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
+
        cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
        s->handle = CX18_INVALID_TASK_HANDLE;
 
@@ -595,3 +643,21 @@ u32 cx18_find_handle(struct cx18 *cx)
        }
        return CX18_INVALID_TASK_HANDLE;
 }
+
+struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle)
+{
+       int i;
+       struct cx18_stream *s;
+
+       if (handle == CX18_INVALID_TASK_HANDLE)
+               return NULL;
+
+       for (i = 0; i < CX18_MAX_STREAMS; i++) {
+               s = &cx->streams[i];
+               if (s->handle != handle)
+                       continue;
+               if (s->v4l2dev || s->dvb.enabled)
+                       return s;
+       }
+       return NULL;
+}
index f327e947b24f069a9791e6b8e47e82156a1e34de..420e0a172945e7c6d63f5e6bf9e62f50be2e63be 100644 (file)
@@ -4,6 +4,7 @@
  *  Derived from ivtv-streams.h
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 
 u32 cx18_find_handle(struct cx18 *cx);
+struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle);
 int cx18_streams_setup(struct cx18 *cx);
 int cx18_streams_register(struct cx18 *cx);
 void cx18_streams_cleanup(struct cx18 *cx, int unregister);
 
 /* Capture related */
+void cx18_stream_load_fw_queue(struct cx18_stream *s);
+struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
+                                         struct cx18_buffer *buf);
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
 int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
 
index 22e76ee3f4475341a9246b66c6659ce8478aa586..fb595bd548e898f80d29f6d98982c3dfe8b91def 100644 (file)
@@ -160,11 +160,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
                return;
 
        /* Raw VBI data */
-       if (cx->vbi.sliced_in->service_set == 0) {
+       if (cx18_raw_vbi(cx)) {
                u8 type;
 
                cx18_buf_swap(buf);
 
+               /* Skip 12 bytes of header that gets stuffed in */
+               size -= 12;
+               memcpy(p, &buf->buf[12], size);
                type = p[3];
 
                size = buf->bytesused = compress_raw_buf(cx, p, size);
index 9f6be2d457fb727cc26f8bb0720729f2f7bd2677..84c0ff13b607d6f8f27283917bbd3b9aca9d2f00 100644 (file)
@@ -25,7 +25,7 @@
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
 #define CX18_DRIVER_VERSION_MINOR 0
-#define CX18_DRIVER_VERSION_PATCHLEVEL 1
+#define CX18_DRIVER_VERSION_PATCHLEVEL 4
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
 #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
index 668f968d7761846cb17ae5d046f9154ca68be08f..601f3a2ab7425d0873fec3d9ea0eb504d8d3496e 100644 (file)
@@ -44,6 +44,7 @@
 
 /* All commands for CPU have the following mask set */
 #define CPU_CMD_MASK                           0x20000000
+#define CPU_CMD_MASK_DEBUG                     (CPU_CMD_MASK | 0x00000000)
 #define CPU_CMD_MASK_ACK                       (CPU_CMD_MASK | 0x80000000)
 #define CPU_CMD_MASK_CAPTURE                   (CPU_CMD_MASK | 0x00020000)
 #define CPU_CMD_MASK_TS                        (CPU_CMD_MASK | 0x00040000)
           0/zero/NULL means "I have nothing to say" */
 #define CX18_EPU_DEBUG                                 (EPU_CMD_MASK_DEBUG | 0x0003)
 
+/* Reads memory/registers (32-bit)
+   IN[0] - Address
+   OUT[1] - Value */
+#define CX18_CPU_DEBUG_PEEK32                  (CPU_CMD_MASK_DEBUG | 0x0003)
+
 /* Description: This command starts streaming with the set channel type
    IN[0] - Task handle. Handle of the task to start
    ReturnCode - One of the ERR_CAPTURE_... */
index 00831f3ef8f59b7f821d2281737987add37b74aa..798d240243536a2f79fcf218a2616ccd154ad629 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Support for a cx23417 mpeg encoder via cx23885 host port.
  *
- *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
  *    (c) 2008 Steven Toth <stoth@linuxtv.org>
  *      - CX23885/7/8 support
index dac5ccc9ba72a669de7a5558b722838f6ea914a3..caa098beeecf60f91f0a8482e5e2407d4d2f4fd7 100644 (file)
@@ -158,6 +158,10 @@ struct cx23885_board cx23885_boards[] = {
                .name           = "Leadtek Winfast PxDVR3200 H",
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = {
+               .name           = "Compro VideoMate E650F",
+               .portc          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -237,6 +241,10 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x107d,
                .subdevice = 0x6681,
                .card      = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H,
+       }, {
+               .subvendor = 0x185b,
+               .subdevice = 0xe800,
+               .card      = CX23885_BOARD_COMPRO_VIDEOMATE_E650F,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -390,6 +398,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
                /* Tuner Reset Command */
                bitmask = 0x04;
                break;
@@ -530,6 +539,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_set(GP0_IO, 0x000f000f);
                break;
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
                /* GPIO-2  xc3028 tuner reset */
 
                /* The following GPIO's are on the internal AVCore (cx25840) */
@@ -630,6 +640,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
        default:
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -644,6 +655,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
                request_module("cx25840");
                break;
        }
index e1aac07b3158a42bd32210f1d3d0a123b09cb940..1c454128a9df9c5fca5b2b6fd7253ed6111d5426 100644 (file)
@@ -502,6 +502,7 @@ static int dvb_register(struct cx23885_tsport *port)
                break;
        }
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
+       case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
                i2c_bus = &dev->i2c_bus[0];
 
                fe0->dvb.frontend = dvb_attach(zl10353_attach,
index 1d53f54cd943efc593f2f755328064642cc627aa..67828029fc69ed9489ce91ba5f30bdb33a4eb9d9 100644 (file)
@@ -66,6 +66,7 @@
 #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10
 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11
 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12
+#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F   13
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
index de515dadadc2e2062f3c655c2821874675d581f1..451133ad41ffa603593415bd405f0e23bb6b3501 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_CX25840
        tristate "Conexant CX2584x audio/video decoders"
-       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       depends on VIDEO_V4L2 && I2C
        ---help---
          Support for the Conexant CX2584x audio/video decoders.
 
index d6421e1e8f6a793e0cdaeddca6885e9746b188e3..d199d80ea0a3642139918b96b64deeade3c54e7a 100644 (file)
@@ -25,7 +25,7 @@
 
 static int set_audclk_freq(struct i2c_client *client, u32 freq)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
        if (freq != 32000 && freq != 44100 && freq != 48000)
                return -EINVAL;
@@ -193,7 +193,7 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
 
 void cx25840_audio_set_path(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
        /* assert soft reset */
        cx25840_and_or(client, 0x810, ~0x1, 0x01);
@@ -235,7 +235,7 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
 static int get_volume(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        int vol;
 
        if (state->unmute_volume >= 0)
@@ -252,7 +252,7 @@ static int get_volume(struct i2c_client *client)
 
 static void set_volume(struct i2c_client *client, int volume)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        int vol;
 
        if (state->unmute_volume >= 0) {
@@ -340,14 +340,14 @@ static void set_balance(struct i2c_client *client, int balance)
 
 static int get_mute(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
        return state->unmute_volume >= 0;
 }
 
 static void set_mute(struct i2c_client *client, int mute)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
 
        if (mute && state->unmute_volume == -1) {
                int vol = get_volume(client);
@@ -365,7 +365,7 @@ static void set_mute(struct i2c_client *client, int mute)
 
 int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        struct v4l2_control *ctrl = arg;
        int retval;
 
index 4da8cd74f00e6e17b6301a03d0c9a31f873a587e..2ad277189da820fd83478fb5d0369959f1de3ae6 100644 (file)
@@ -191,7 +191,7 @@ static void cx25840_work_handler(struct work_struct *work)
 static void cx25840_initialize(struct i2c_client *client)
 {
        DEFINE_WAIT(wait);
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        struct workqueue_struct *q;
 
        /* datasheet startup in numbered steps, refer to page 3-77 */
@@ -259,7 +259,7 @@ static void cx25840_initialize(struct i2c_client *client)
 static void cx23885_initialize(struct i2c_client *client)
 {
        DEFINE_WAIT(wait);
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        struct workqueue_struct *q;
 
        /* Internal Reset */
@@ -350,7 +350,7 @@ static void cx23885_initialize(struct i2c_client *client)
 
 void cx25840_std_setup(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        v4l2_std_id std = state->std;
        int hblank, hactive, burst, vblank, vactive, sc;
        int vblank656, src_decimation;
@@ -497,7 +497,7 @@ void cx25840_std_setup(struct i2c_client *client)
 
 static void input_change(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        v4l2_std_id std = state->std;
 
        /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
@@ -551,7 +551,7 @@ static void input_change(struct i2c_client *client)
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
                                                enum cx25840_audio_input aud_input)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
                           vid_input <= CX25840_COMPOSITE8);
        u8 reg;
@@ -671,7 +671,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 
 static int set_v4lstd(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 fmt = 0;     /* zero is autodetect */
        u8 pal_m = 0;
 
@@ -720,9 +720,10 @@ static int set_v4lstd(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
        case CX25840_CID_ENABLE_PVR150_WORKAROUND:
@@ -786,9 +787,10 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
        case CX25840_CID_ENABLE_PVR150_WORKAROUND:
@@ -823,21 +825,23 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
 
 /* ----------------------------------------------------------------------- */
 
-static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        switch (fmt->type) {
        case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
                return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
        default:
                return -EINVAL;
        }
-
        return 0;
 }
 
-static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct v4l2_pix_format *pix;
        int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
        int is_50Hz = !(state->std & V4L2_STD_525_60);
@@ -914,7 +918,7 @@ static void log_video_status(struct i2c_client *client)
                "0xD", "0xE", "0xF"
        };
 
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
        u8 gen_stat1 = cx25840_read(client, 0x40d);
        u8 gen_stat2 = cx25840_read(client, 0x40e);
@@ -944,7 +948,7 @@ static void log_video_status(struct i2c_client *client)
 
 static void log_audio_status(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        u8 download_ctl = cx25840_read(client, 0x803);
        u8 mod_det_stat0 = cx25840_read(client, 0x804);
        u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -1097,21 +1101,12 @@ static void log_audio_status(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static int cx25840_command(struct i2c_client *client, unsigned int cmd,
-                          void *arg)
+static int cx25840_init(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
-       struct v4l2_tuner *vt = arg;
-       struct v4l2_routing *route = arg;
-
-       /* ignore these commands */
-       switch (cmd) {
-               case TUNER_SET_TYPE_ADDR:
-                       return 0;
-       }
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        if (!state->is_initialized) {
-               v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd);
                /* initialize on first use */
                state->is_initialized = 1;
                if (state->is_cx25836)
@@ -1121,50 +1116,69 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                else
                        cx25840_initialize(client);
        }
+       return 0;
+}
 
-       switch (cmd) {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       /* ioctls to allow direct access to the
-        * cx25840 registers for testing */
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
+static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = cx25840_read(client, reg->reg & 0x0fff);
-               else
-                       cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
-               break;
-       }
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = cx25840_read(client, reg->reg & 0x0fff);
+       return 0;
+}
+
+static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+       return 0;
+}
 #endif
 
-       case VIDIOC_INT_DECODE_VBI_LINE:
-               return cx25840_vbi(client, cmd, arg);
+static int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return cx25840_audio(client, cmd, arg);
+       return cx25840_vbi(client, VIDIOC_INT_DECODE_VBI_LINE, vbi);
+}
+
+static int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return cx25840_audio(client, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freq);
+}
+
+static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_STREAMON:
-               v4l_dbg(1, cx25840_debug, client, "enable output\n");
+       v4l_dbg(1, cx25840_debug, client, "%s output\n",
+                       enable ? "enable" : "disable");
+       if (enable) {
                if (state->is_cx23885) {
                        u8 v = (cx25840_read(client, 0x421) | 0x0b);
                        cx25840_write(client, 0x421, v);
                } else {
                        cx25840_write(client, 0x115,
-                               state->is_cx25836 ? 0x0c : 0x8c);
+                                       state->is_cx25836 ? 0x0c : 0x8c);
                        cx25840_write(client, 0x116,
-                               state->is_cx25836 ? 0x04 : 0x07);
+                                       state->is_cx25836 ? 0x04 : 0x07);
                }
-               break;
-
-       case VIDIOC_STREAMOFF:
-               v4l_dbg(1, cx25840_debug, client, "disable output\n");
+       } else {
                if (state->is_cx23885) {
                        u8 v = cx25840_read(client, 0x421) & ~(0x0b);
                        cx25840_write(client, 0x421, v);
@@ -1172,133 +1186,136 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        cx25840_write(client, 0x115, 0x00);
                        cx25840_write(client, 0x116, 0x00);
                }
-               break;
+       }
+       return 0;
+}
 
-       case VIDIOC_LOG_STATUS:
-               log_video_status(client);
-               if (!state->is_cx25836)
-                       log_audio_status(client);
-               break;
+static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       struct cx25840_state *state = to_state(sd);
 
-       case VIDIOC_G_CTRL:
-               return get_v4lctrl(client, (struct v4l2_control *)arg);
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill_std(qc);
+       default:
+               break;
+       }
+       if (state->is_cx25836)
+               return -EINVAL;
 
-       case VIDIOC_S_CTRL:
-               return set_v4lctrl(client, (struct v4l2_control *)arg);
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+               return v4l2_ctrl_query_fill(qc, 0, 65535,
+                               65535 / 100, state->default_volume);
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               return v4l2_ctrl_query_fill_std(qc);
+       default:
+               return -EINVAL;
+       }
+       return -EINVAL;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
+static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               switch (qc->id) {
-                       case V4L2_CID_BRIGHTNESS:
-                       case V4L2_CID_CONTRAST:
-                       case V4L2_CID_SATURATION:
-                       case V4L2_CID_HUE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               break;
-               }
-               if (state->is_cx25836)
-                       return -EINVAL;
+       if (state->radio == 0 && state->std == std)
+               return 0;
+       state->radio = 0;
+       state->std = std;
+       return set_v4lstd(client);
+}
 
-               switch (qc->id) {
-                       case V4L2_CID_AUDIO_VOLUME:
-                               return v4l2_ctrl_query_fill(qc, 0, 65535,
-                                       65535 / 100, state->default_volume);
-                       case V4L2_CID_AUDIO_MUTE:
-                       case V4L2_CID_AUDIO_BALANCE:
-                       case V4L2_CID_AUDIO_BASS:
-                       case V4L2_CID_AUDIO_TREBLE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               return -EINVAL;
-               }
-               return -EINVAL;
-       }
+static int cx25840_s_radio(struct v4l2_subdev *sd)
+{
+       struct cx25840_state *state = to_state(sd);
 
-       case VIDIOC_G_STD:
-               *(v4l2_std_id *)arg = state->std;
-               break;
+       state->radio = 1;
+       return 0;
+}
 
-       case VIDIOC_S_STD:
-               if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
-                       return 0;
-               state->radio = 0;
-               state->std = *(v4l2_std_id *)arg;
-               return set_v4lstd(client);
+static int cx25840_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case AUDC_SET_RADIO:
-               state->radio = 1;
-               break;
+       return set_input(client, route->input, state->aud_input);
+}
 
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = state->vid_input;
-               route->output = 0;
-               break;
+static int cx25840_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-               return set_input(client, route->input, state->aud_input);
+       if (state->is_cx25836)
+               return -EINVAL;
+       return set_input(client, state->vid_input, route->input);
+}
 
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               if (state->is_cx25836)
-                       return -EINVAL;
-               route->input = state->aud_input;
-               route->output = 0;
-               break;
+static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               if (state->is_cx25836)
-                       return -EINVAL;
-               return set_input(client, state->vid_input, route->input);
+       if (!state->is_cx25836)
+               input_change(client);
+       return 0;
+}
 
-       case VIDIOC_S_FREQUENCY:
-               if (!state->is_cx25836) {
-                       input_change(client);
-               }
-               break;
+static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+       u8 mode;
+       int val = 0;
 
-       case VIDIOC_G_TUNER:
-       {
-               u8 vpres = cx25840_read(client, 0x40e) & 0x20;
-               u8 mode;
-               int val = 0;
+       if (state->radio)
+               return 0;
 
-               if (state->radio)
-                       break;
+       vt->signal = vpres ? 0xffff : 0x0;
+       if (state->is_cx25836)
+               return 0;
 
-               vt->signal = vpres ? 0xffff : 0x0;
-               if (state->is_cx25836)
-                       break;
+       vt->capability |=
+               V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+               V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
 
-               vt->capability |=
-                   V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
-                   V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+       mode = cx25840_read(client, 0x804);
 
-               mode = cx25840_read(client, 0x804);
+       /* get rxsubchans and audmode */
+       if ((mode & 0xf) == 1)
+               val |= V4L2_TUNER_SUB_STEREO;
+       else
+               val |= V4L2_TUNER_SUB_MONO;
 
-               /* get rxsubchans and audmode */
-               if ((mode & 0xf) == 1)
-                       val |= V4L2_TUNER_SUB_STEREO;
-               else
-                       val |= V4L2_TUNER_SUB_MONO;
+       if (mode == 2 || mode == 4)
+               val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 
-               if (mode == 2 || mode == 4)
-                       val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+       if (mode & 0x10)
+               val |= V4L2_TUNER_SUB_SAP;
 
-               if (mode & 0x10)
-                       val |= V4L2_TUNER_SUB_SAP;
+       vt->rxsubchans = val;
+       vt->audmode = state->audmode;
+       return 0;
+}
 
-               vt->rxsubchans = val;
-               vt->audmode = state->audmode;
-               break;
-       }
+static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_S_TUNER:
-               if (state->radio || state->is_cx25836)
-                       break;
+       if (state->radio || state->is_cx25836)
+               return 0;
 
-               switch (vt->audmode) {
+       switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
                        /* mono      -> mono
                           stereo    -> mono
@@ -1326,41 +1343,100 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
                        break;
                default:
                        return -EINVAL;
-               }
-               state->audmode = vt->audmode;
-               break;
+       }
+       state->audmode = vt->audmode;
+       return 0;
+}
 
-       case VIDIOC_G_FMT:
-               return get_v4lfmt(client, (struct v4l2_format *)arg);
+static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_S_FMT:
-               return set_v4lfmt(client, (struct v4l2_format *)arg);
+       if (state->is_cx25836)
+               cx25836_initialize(client);
+       else if (state->is_cx23885)
+               cx23885_initialize(client);
+       else
+               cx25840_initialize(client);
+       return 0;
+}
 
-       case VIDIOC_INT_RESET:
-               if (state->is_cx25836)
-                       cx25836_initialize(client);
-               else if (state->is_cx23885)
-                       cx23885_initialize(client);
-               else
-                       cx25840_initialize(client);
-               break;
+static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev);
+       return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
+}
 
-       default:
-               return -EINVAL;
-       }
+static int cx25840_log_status(struct v4l2_subdev *sd)
+{
+       struct cx25840_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
+       log_video_status(client);
+       if (!state->is_cx25836)
+               log_audio_status(client);
        return 0;
 }
 
+static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cx25840_core_ops = {
+       .log_status = cx25840_log_status,
+       .g_chip_ident = cx25840_g_chip_ident,
+       .g_ctrl = cx25840_g_ctrl,
+       .s_ctrl = cx25840_s_ctrl,
+       .queryctrl = cx25840_queryctrl,
+       .reset = cx25840_reset,
+       .init = cx25840_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = cx25840_g_register,
+       .s_register = cx25840_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
+       .s_frequency = cx25840_s_frequency,
+       .s_std = cx25840_s_std,
+       .s_radio = cx25840_s_radio,
+       .g_tuner = cx25840_g_tuner,
+       .s_tuner = cx25840_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
+       .s_clock_freq = cx25840_s_clock_freq,
+       .s_routing = cx25840_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops cx25840_video_ops = {
+       .s_routing = cx25840_s_video_routing,
+       .g_fmt = cx25840_g_fmt,
+       .s_fmt = cx25840_s_fmt,
+       .decode_vbi_line = cx25840_decode_vbi_line,
+       .s_stream = cx25840_s_stream,
+};
+
+static const struct v4l2_subdev_ops cx25840_ops = {
+       .core = &cx25840_core_ops,
+       .tuner = &cx25840_tuner_ops,
+       .audio = &cx25840_audio_ops,
+       .video = &cx25840_video_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static int cx25840_probe(struct i2c_client *client,
                         const struct i2c_device_id *did)
 {
        struct cx25840_state *state;
+       struct v4l2_subdev *sd;
        u32 id;
        u16 device_id;
 
@@ -1392,10 +1468,11 @@ static int cx25840_probe(struct i2c_client *client,
        }
 
        state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
-       if (state == NULL) {
+       if (state == NULL)
                return -ENOMEM;
-       }
 
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
        /* Note: revision '(device_id & 0x0f) == 2' was never built. The
           marking skips from 0x1 == 22 to 0x3 == 23. */
        v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
@@ -1403,7 +1480,6 @@ static int cx25840_probe(struct i2c_client *client,
                    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
                    client->addr << 1, client->adapter->name);
 
-       i2c_set_clientdata(client, state);
        state->c = client;
        state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
        state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
@@ -1430,7 +1506,10 @@ static int cx25840_probe(struct i2c_client *client,
 
 static int cx25840_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index b87337e590b43334a3b4b345ede4199ea5ae1924..be0558277ca336567c8bf66771aa7fb5711d5d57 100644 (file)
@@ -22,6 +22,7 @@
 
 
 #include <linux/videodev2.h>
+#include <media/v4l2-device.h>
 #include <linux/i2c.h>
 
 /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
@@ -34,6 +35,7 @@
 
 struct cx25840_state {
        struct i2c_client *c;
+       struct v4l2_subdev sd;
        int pvr150_workaround;
        int radio;
        v4l2_std_id std;
@@ -53,6 +55,11 @@ struct cx25840_state {
        struct work_struct fw_work;   /* work entry for fw load */
 };
 
+static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct cx25840_state, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 /* cx25850-core.c                                                         */
 int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
index 8d489a4b9570696f4633cb71d38f0ceceda513fd..0b2dceb74108696b00cde823e9f63a6446818c1c 100644 (file)
@@ -91,7 +91,7 @@ static int fw_write(struct i2c_client *client, const u8 *data, int size)
 
 int cx25840_loadfw(struct i2c_client *client)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        const struct firmware *fw = NULL;
        u8 buffer[FWSEND];
        const u8 *ptr;
index 58e6ef1c28a093d849b88f7111f5120a27b9b6aa..03f09b288eb8539ecd0438c68b989f59e9aef720 100644 (file)
@@ -84,7 +84,7 @@ static int decode_vps(u8 * dst, u8 * p)
 
 int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-       struct cx25840_state *state = i2c_get_clientdata(client);
+       struct cx25840_state *state = to_state(i2c_get_clientdata(client));
        struct v4l2_format *fmt;
        struct v4l2_sliced_vbi_format *svbi;
 
index 06f171ab61495b4180befde4da18ea8c5a5e14c1..66c755c116dcbc8190f7305257b8201e6bc88496 100644 (file)
@@ -742,7 +742,6 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        core = cx88_core_get(pci);
        if (NULL == core) {
                err = -EINVAL;
-               kfree (chip);
                return err;
        }
 
@@ -812,7 +811,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 
        err = snd_cx88_create(card, pci, &chip);
        if (err < 0)
-               return (err);
+               goto error;
 
        err = snd_cx88_pcm(chip, 0, "CX88 Digital");
        if (err < 0)
index d3ae5b4dfca72e9141658df38d17cb2f38d53b2e..e162a70748c5fa6458655daf8591f94b2d3fff63 100644 (file)
@@ -3,7 +3,7 @@
  *  Support for a cx23416 mpeg encoder via cx2388x host port.
  *  "blackbird" reference design.
  *
- *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
  *
  *    (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
@@ -39,7 +39,7 @@
 #include "cx88.h"
 
 MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
-MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
 
 static unsigned int mpegbufs = 32;
@@ -1244,8 +1244,16 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
                 * We're being given access to re-arrange the GPIOs.
                 * Take the bus off the cx22702 and put the cx23416 on it.
                 */
-               cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */
-               cx_set(MO_GP0_IO,   0x00000004); /* Disable the cx22702 */
+               /* Toggle reset on cx22702 leaving i2c active */
+               cx_set(MO_GP0_IO, 0x00000080);
+               udelay(1000);
+               cx_clear(MO_GP0_IO, 0x00000080);
+               udelay(50);
+               cx_set(MO_GP0_IO, 0x00000080);
+               udelay(1000);
+               /* tri-state the cx22702 pins */
+               cx_set(MO_GP0_IO, 0x00000004);
+               udelay(1000);
                break;
        default:
                err = -ENODEV;
index 5bcbb4cc7c2a53e0656d56be53441ad085fb0874..733ede34f93a43151db923d962e51cc225b0a0eb 100644 (file)
@@ -1237,7 +1237,6 @@ static const struct cx88_board cx88_boards[] = {
                },
        },
        [CX88_BOARD_WINFAST_DTV2000H] = {
-               /* video inputs and radio still in testing */
                .name           = "WinFast DTV2000 H",
                .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
                .radio_type     = UNSET,
@@ -1251,7 +1250,35 @@ static const struct cx88_board cx88_boards[] = {
                        .gpio1  = 0x00008203,
                        .gpio2  = 0x00017304,
                        .gpio3  = 0x02000000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0001d701,
+                       .gpio1  = 0x0000b207,
+                       .gpio2  = 0x0001d701,
+                       .gpio3  = 0x02000000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE2,
+                       .vmux   = 2,
+                       .gpio0  = 0x0001d503,
+                       .gpio1  = 0x0000b207,
+                       .gpio2  = 0x0001d503,
+                       .gpio3  = 0x02000000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 3,
+                       .gpio0  = 0x0001d701,
+                       .gpio1  = 0x0000b207,
+                       .gpio2  = 0x0001d701,
+                       .gpio3  = 0x02000000,
                }},
+               .radio = {
+                        .type  = CX88_RADIO,
+                        .gpio0 = 0x00015702,
+                        .gpio1 = 0x0000f207,
+                        .gpio2 = 0x00015702,
+                        .gpio3 = 0x02000000,
+               },
                .mpeg           = CX88_MPEG_DVB,
        },
        [CX88_BOARD_GENIATECH_DVBS] = {
@@ -1847,6 +1874,18 @@ static const struct cx88_board cx88_boards[] = {
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_TBS_8910] = {
+               .name           = "TBS 8910 DVB-S",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
        [CX88_BOARD_TBS_8920] = {
                .name           = "TBS 8920 DVB-S/S2",
                .tuner_type     = TUNER_ABSENT,
@@ -1859,6 +1898,18 @@ static const struct cx88_board cx88_boards[] = {
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_PROF_6200] = {
+               .name           = "Prof 6200 DVB-S",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
        [CX88_BOARD_PROF_7300] = {
                .name           = "PROF 7300 DVB-S/S2",
                .tuner_type     = UNSET,
@@ -1871,6 +1922,18 @@ static const struct cx88_board cx88_boards[] = {
                } },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_SATTRADE_ST4200] = {
+               .name           = "SATTRADE ST4200 DVB-S/S2",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .input          = {{
+                       .type   = CX88_VMUX_DVB,
+                       .vmux   = 0,
+               } },
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -1897,7 +1960,11 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = PCI_VENDOR_ID_ATI,
                .subdevice = 0x00f8,
                .card      = CX88_BOARD_ATI_WONDER_PRO,
-       },{
+       }, {
+               .subvendor = PCI_VENDOR_ID_ATI,
+               .subdevice = 0x00f9,
+               .card      = CX88_BOARD_ATI_WONDER_PRO,
+       }, {
                .subvendor = 0x107d,
                .subdevice = 0x6611,
                .card      = CX88_BOARD_WINFAST2000XP_EXPERT,
@@ -2256,14 +2323,26 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0xA044,
                .subdevice = 0x2011,
                .card      = CX88_BOARD_OMICOM_SS4_PCI,
+       }, {
+               .subvendor = 0x8910,
+               .subdevice = 0x8888,
+               .card      = CX88_BOARD_TBS_8910,
        }, {
                .subvendor = 0x8920,
                .subdevice = 0x8888,
                .card      = CX88_BOARD_TBS_8920,
+       }, {
+               .subvendor = 0xb022,
+               .subdevice = 0x3022,
+               .card      = CX88_BOARD_PROF_6200,
        }, {
                .subvendor = 0xB033,
                .subdevice = 0x3033,
                .card      = CX88_BOARD_PROF_7300,
+       }, {
+               .subvendor = 0xb200,
+               .subdevice = 0x4200,
+               .card      = CX88_BOARD_SATTRADE_ST4200,
        },
 };
 
@@ -2874,8 +2953,11 @@ static void cx88_card_setup(struct cx88_core *core)
        case  CX88_BOARD_TEVII_S420:
        case  CX88_BOARD_TEVII_S460:
        case  CX88_BOARD_OMICOM_SS4_PCI:
+       case  CX88_BOARD_TBS_8910:
        case  CX88_BOARD_TBS_8920:
+       case  CX88_BOARD_PROF_6200:
        case  CX88_BOARD_PROF_7300:
+       case  CX88_BOARD_SATTRADE_ST4200:
                cx_write(MO_SRST_IO, 0);
                msleep(100);
                cx_write(MO_SRST_IO, 1);
index 60705b08bfe899e5c39a17ef6dd83b8436f9ff30..b045874ad04f98c5d89048204e57277ce345e4a7 100644 (file)
@@ -844,6 +844,9 @@ static int set_tvaudio(struct cx88_core *core)
        } else if (V4L2_STD_SECAM_L & norm) {
                core->tvaudio = WW_L;
 
+       } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) {
+               core->tvaudio = WW_BG;
+
        } else if (V4L2_STD_SECAM_DK & norm) {
                core->tvaudio = WW_DK;
 
index 309ca5e68063ac7fd8b1667b8ef1486c38f5fa8a..da4dd4913d9f7cc3fbd31d64f20ee5e9bdb56ed7 100644 (file)
@@ -406,7 +406,7 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
                        cx_write(MO_GP0_IO, 0x00006060);
                        break;
                case SEC_VOLTAGE_OFF:
-                       printk("LNB Voltage SEC_VOLTAGE_off\n");
+                       printk("LNB Voltage SEC_VOLTAGE_off\n");
                        break;
        }
 
@@ -606,7 +606,7 @@ static int dvb_register(struct cx8802_dev *dev)
        /* Get the first frontend */
        fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
        if (!fe0)
-               return -EINVAL;
+               goto frontend_detach;
 
        /* multi-frontend gate control is undefined or defaults to fe0 */
        dev->frontends.gate = 0;
@@ -653,38 +653,35 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
        case CX88_BOARD_HAUPPAUGE_HVR3000:
+               /* MFE frontend 1 */
+               mfe_shared = 1;
+               dev->frontends.gate = 2;
                /* DVB-S init */
                fe0->dvb.frontend = dvb_attach(cx24123_attach,
-                              &hauppauge_novas_config,
-                              &dev->core->i2c_adap);
+                                       &hauppauge_novas_config,
+                                       &dev->core->i2c_adap);
                if (fe0->dvb.frontend) {
-                       if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
-                       &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
-                               dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __func__);
-                       }
-               } else {
-                       dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __func__);
+                       if (!dvb_attach(isl6421_attach,
+                                       fe0->dvb.frontend,
+                                       &dev->core->i2c_adap,
+                                       0x08, ISL6421_DCL, 0x00))
+                               goto frontend_detach;
                }
-               /* DVB-T init */
+               /* MFE frontend 2 */
                fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
-               if (fe1) {
-                       dev->frontends.gate = 2;
-                       mfe_shared = 1;
-                       fe1->dvb.frontend = dvb_attach(cx22702_attach,
-                               &hauppauge_hvr_config,
-                               &dev->core->i2c_adap);
-                       if (fe1->dvb.frontend) {
-                               fe1->dvb.frontend->id = 1;
-                               if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
-                                               &dev->core->i2c_adap, 0x61,
-                                               TUNER_PHILIPS_FMD1216ME_MK3)) {
-                                       dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __func__);
-                               }
-                       } else {
-                               dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __func__);
-                       }
-               } else {
-                       dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __func__);
+               if (!fe1)
+                       goto frontend_detach;
+               /* DVB-T init */
+               fe1->dvb.frontend = dvb_attach(cx22702_attach,
+                                       &hauppauge_hvr_config,
+                                       &dev->core->i2c_adap);
+               if (fe1->dvb.frontend) {
+                       fe1->dvb.frontend->id = 1;
+                       if (!dvb_attach(simple_tuner_attach,
+                                       fe1->dvb.frontend,
+                                       &dev->core->i2c_adap,
+                                       0x61, TUNER_PHILIPS_FMD1216ME_MK3))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -998,50 +995,51 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
        case CX88_BOARD_HAUPPAUGE_HVR4000:
+               /* MFE frontend 1 */
+               mfe_shared = 1;
+               dev->frontends.gate = 2;
                /* DVB-S/S2 Init */
                fe0->dvb.frontend = dvb_attach(cx24116_attach,
-                       &hauppauge_hvr4000_config,
-                       &dev->core->i2c_adap);
+                                       &hauppauge_hvr4000_config,
+                                       &dev->core->i2c_adap);
                if (fe0->dvb.frontend) {
-                       if(!dvb_attach(isl6421_attach, fe0->dvb.frontend,
-                               &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) {
-                               dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __func__);
-                       }
-               } else {
-                       dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __func__);
+                       if (!dvb_attach(isl6421_attach,
+                                       fe0->dvb.frontend,
+                                       &dev->core->i2c_adap,
+                                       0x08, ISL6421_DCL, 0x00))
+                               goto frontend_detach;
                }
-               /* DVB-T Init */
+               /* MFE frontend 2 */
                fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
-               if (fe1) {
-                       dev->frontends.gate = 2;
-                       mfe_shared = 1;
-                       fe1->dvb.frontend = dvb_attach(cx22702_attach,
-                               &hauppauge_hvr_config,
-                               &dev->core->i2c_adap);
-                       if (fe1->dvb.frontend) {
-                               fe1->dvb.frontend->id = 1;
-                               if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend,
-                                       &dev->core->i2c_adap, 0x61,
-                                       TUNER_PHILIPS_FMD1216ME_MK3)) {
-                                       dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __func__);
-                               }
-                       } else {
-                               dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __func__);
-                       }
-               } else {
-                       dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __func__);
+               if (!fe1)
+                       goto frontend_detach;
+               /* DVB-T Init */
+               fe1->dvb.frontend = dvb_attach(cx22702_attach,
+                                       &hauppauge_hvr_config,
+                                       &dev->core->i2c_adap);
+               if (fe1->dvb.frontend) {
+                       fe1->dvb.frontend->id = 1;
+                       if (!dvb_attach(simple_tuner_attach,
+                                       fe1->dvb.frontend,
+                                       &dev->core->i2c_adap,
+                                       0x61, TUNER_PHILIPS_FMD1216ME_MK3))
+                               goto frontend_detach;
                }
                break;
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
                fe0->dvb.frontend = dvb_attach(cx24116_attach,
-                       &hauppauge_hvr4000_config,
-                       &dev->core->i2c_adap);
+                                       &hauppauge_hvr4000_config,
+                                       &dev->core->i2c_adap);
                if (fe0->dvb.frontend) {
-                       dvb_attach(isl6421_attach, fe0->dvb.frontend,
-                               &dev->core->i2c_adap,
-                               0x08, ISL6421_DCL, 0x00);
+                       if (!dvb_attach(isl6421_attach,
+                                       fe0->dvb.frontend,
+                                       &dev->core->i2c_adap,
+                                       0x08, ISL6421_DCL, 0x00))
+                               goto frontend_detach;
                }
                break;
+       case CX88_BOARD_PROF_6200:
+       case CX88_BOARD_TBS_8910:
        case CX88_BOARD_TEVII_S420:
                fe0->dvb.frontend = dvb_attach(stv0299_attach,
                                                &tevii_tuner_sharp_config,
@@ -1070,21 +1068,18 @@ static int dvb_register(struct cx8802_dev *dev)
                fe0->dvb.frontend = dvb_attach(cx24116_attach,
                                               &tevii_s460_config,
                                               &core->i2c_adap);
-               if (fe0->dvb.frontend != NULL) {
-                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+               if (fe0->dvb.frontend != NULL)
                        fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
-               }
                break;
        case CX88_BOARD_OMICOM_SS4_PCI:
        case CX88_BOARD_TBS_8920:
        case CX88_BOARD_PROF_7300:
+       case CX88_BOARD_SATTRADE_ST4200:
                fe0->dvb.frontend = dvb_attach(cx24116_attach,
                                               &hauppauge_hvr4000_config,
                                               &core->i2c_adap);
-               if (fe0->dvb.frontend != NULL) {
-                       core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
+               if (fe0->dvb.frontend != NULL)
                        fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
-               }
                break;
        default:
                printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -1092,11 +1087,11 @@ static int dvb_register(struct cx8802_dev *dev)
                break;
        }
 
-        if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
+       if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) {
                printk(KERN_ERR
                       "%s/2: frontend initialization failed\n",
                       core->name);
-               return -EINVAL;
+               goto frontend_detach;
        }
        /* define general-purpose callback pointer */
        fe0->dvb.frontend->callback = cx88_tuner_callback;
@@ -1133,40 +1128,44 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
                 * on the bus. Take the bus from the cx23416 and enable the
                 * cx22702 demod
                 */
-               cx_set(MO_GP0_IO,   0x00000080); /* cx22702 out of reset and enable */
+               /* Toggle reset on cx22702 leaving i2c active */
+               cx_set(MO_GP0_IO, 0x00000080);
+               udelay(1000);
+               cx_clear(MO_GP0_IO, 0x00000080);
+               udelay(50);
+               cx_set(MO_GP0_IO, 0x00000080);
+               udelay(1000);
+               /* enable the cx22702 pins */
                cx_clear(MO_GP0_IO, 0x00000004);
                udelay(1000);
                break;
 
        case CX88_BOARD_HAUPPAUGE_HVR3000:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
-               if(core->dvbdev->frontends.active_fe_id == 1) {
-                       /* DVB-S/S2 Enabled */
-
-                       /* Toggle reset on cx22702 leaving i2c active */
-                       cx_write(MO_GP0_IO, (core->board.input[0].gpio0 & 0x0000ff00) | 0x00000080);
-                       udelay(1000);
-                       cx_clear(MO_GP0_IO, 0x00000080);
-                       udelay(50);
-                       cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset */
-                       cx_set(MO_GP0_IO, 0x00000004); /* tri-state the cx22702 pins */
-                       udelay(1000);
-
-                       cx_write(MO_SRST_IO, 1); /* Take the cx24116/cx24123 out of reset */
+               /* Toggle reset on cx22702 leaving i2c active */
+               cx_set(MO_GP0_IO, 0x00000080);
+               udelay(1000);
+               cx_clear(MO_GP0_IO, 0x00000080);
+               udelay(50);
+               cx_set(MO_GP0_IO, 0x00000080);
+               udelay(1000);
+               switch (core->dvbdev->frontends.active_fe_id) {
+               case 1: /* DVB-S/S2 Enabled */
+                       /* tri-state the cx22702 pins */
+                       cx_set(MO_GP0_IO, 0x00000004);
+                       /* Take the cx24116/cx24123 out of reset */
+                       cx_write(MO_SRST_IO, 1);
                        core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
-               } else
-               if (core->dvbdev->frontends.active_fe_id == 2) {
-                       /* DVB-T Enabled */
-
+                       break;
+               case 2: /* DVB-T Enabled */
                        /* Put the cx24116/cx24123 into reset */
                        cx_write(MO_SRST_IO, 0);
-
-                       /* cx22702 out of reset and enable it */
-                       cx_set(MO_GP0_IO,   0x00000080);
+                       /* enable the cx22702 pins */
                        cx_clear(MO_GP0_IO, 0x00000004);
                        core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
-                       udelay(1000);
+                       break;
                }
+               udelay(1000);
                break;
 
        default:
@@ -1199,8 +1198,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
 {
        struct cx88_core *core = drv->core;
        struct cx8802_dev *dev = drv->core->dvbdev;
-       int err, i;
-       struct videobuf_dvb_frontend *fe;
+       int err;
 
        dprintk( 1, "%s\n", __func__);
        dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
@@ -1216,31 +1214,47 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
        /* If vp3054 isn't enabled, a stub will just return 0 */
        err = vp3054_i2c_probe(dev);
        if (0 != err)
-               goto fail_core;
+               goto fail_probe;
 
        /* dvb stuff */
        printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
        dev->ts_gen_cntrl = 0x0c;
 
-       for (i = 1; i <= core->board.num_frontends; i++) {
-               fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
-               if (!fe) {
-                       printk(KERN_ERR "%s() failed to get frontend(%d)\n", __func__, i);
-                       continue;
+       err = -ENODEV;
+       if (core->board.num_frontends) {
+               struct videobuf_dvb_frontend *fe;
+               int i;
+
+               for (i = 1; i <= core->board.num_frontends; i++) {
+                       fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
+                       if (fe == NULL) {
+                               printk(KERN_ERR "%s() failed to get frontend(%d)\n",
+                                       __func__, i);
+                               goto fail_probe;
+                       }
+                       videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
+                                   &dev->pci->dev, &dev->slock,
+                                   V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                                   V4L2_FIELD_TOP,
+                                   sizeof(struct cx88_buffer),
+                                   dev);
+                       /* init struct videobuf_dvb */
+                       fe->dvb.name = dev->core->name;
                }
-               videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
-                           &dev->pci->dev, &dev->slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_TOP,
-                           sizeof(struct cx88_buffer),
-                           dev);
-               /* init struct videobuf_dvb */
-               fe->dvb.name = dev->core->name;
+       } else {
+               /* no frontends allocated */
+               printk(KERN_ERR "%s/2 .num_frontends should be non-zero\n",
+                       core->name);
+               goto fail_core;
        }
        err = dvb_register(dev);
-       if (err != 0)
+       if (err)
+               /* frontends/adapter de-allocated in dvb_register */
                printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
                       core->name, err);
+       return err;
+fail_probe:
+       videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends);
 fail_core:
        return err;
 }
index 3ebdcd1d83f8b21b809989688457505232133447..a04fee235db6c487c162434e75d20a05b4e9b463 100644 (file)
@@ -3,7 +3,7 @@
  *  Support for the mpeg transport stream transfers
  *  PCI function #2 of the cx2388x.
  *
- *    (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ *    (c) 2004 Jelle Foks <jelle@foks.us>
  *    (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
  *    (c) 2004 Gerd Knorr <kraxel@bytesex.org>
  *
@@ -34,7 +34,7 @@
 /* ------------------------------------------------------------------ */
 
 MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards");
-MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>");
+MODULE_AUTHOR("Jelle Foks <jelle@foks.us>");
 MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
 MODULE_LICENSE("GPL");
index f4240965be32cb24f07e013c75382e375ac407a3..20649b25f7baf522a95a659d65da13ba7369805f 100644 (file)
 /* ----------------------------------------------------------- */
 /* defines and enums                                           */
 
-/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
-#define CX88_NORMS (\
-       V4L2_STD_NTSC_M|  V4L2_STD_NTSC_M_JP|  V4L2_STD_NTSC_443 | \
-       V4L2_STD_PAL_BG|  V4L2_STD_PAL_DK   |  V4L2_STD_PAL_I    | \
-       V4L2_STD_PAL_M |  V4L2_STD_PAL_N    |  V4L2_STD_PAL_Nc   | \
-       V4L2_STD_PAL_60|  V4L2_STD_SECAM_L  |  V4L2_STD_SECAM_DK )
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */
+#define CX88_NORMS (V4L2_STD_ALL               \
+                   & ~V4L2_STD_PAL_H           \
+                   & ~V4L2_STD_NTSC_M_KR       \
+                   & ~V4L2_STD_SECAM_LC)
 
 #define FORMAT_FLAGS_PACKED       0x01
 #define FORMAT_FLAGS_PLANAR       0x02
@@ -229,6 +228,9 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_TEVII_S420              73
 #define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
 #define CX88_BOARD_PROF_7300               75
+#define CX88_BOARD_SATTRADE_ST4200         76
+#define CX88_BOARD_TBS_8910                77
+#define CX88_BOARD_PROF_6200               78
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
index 7a8d49ef646e62cb22127dd9387070dfcc1db22e..15c03f0e69ad63fe1a5c2015a8210e31698b21cd 100644 (file)
@@ -424,11 +424,12 @@ static int em28xx_audio_init(struct em28xx *dev)
        struct snd_pcm      *pcm;
        struct snd_card     *card;
        static int          devnr;
-       int                 ret, err;
+       int                 err;
 
-       if (dev->has_audio_class) {
+       if (dev->has_alsa_audio != 1) {
                /* This device does not support the extension (in this case
-                  the device is expecting the snd-usb-audio module */
+                  the device is expecting the snd-usb-audio module or
+                  doesn't have analog audio support at all) */
                return 0;
        }
 
@@ -449,7 +450,12 @@ static int em28xx_audio_init(struct em28xx *dev)
        }
 
        spin_lock_init(&adev->slock);
-       ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
+       err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
        pcm->info_flags = 0;
        pcm->private_data = dev;
@@ -461,7 +467,7 @@ static int em28xx_audio_init(struct em28xx *dev)
        err = snd_card_register(card);
        if (err < 0) {
                snd_card_free(card);
-               return -ENOMEM;
+               return err;
        }
        adev->sndcard = card;
        adev->udev = dev->udev;
@@ -475,9 +481,10 @@ static int em28xx_audio_fini(struct em28xx *dev)
        if (dev == NULL)
                return 0;
 
-       if (dev->has_audio_class) {
+       if (dev->has_alsa_audio != 1) {
                /* This device does not support the extension (in this case
-                  the device is expecting the snd-usb-audio module */
+                  the device is expecting the snd-usb-audio module or
+                  doesn't have analog audio support at all) */
                return 0;
        }
 
index d65d0572403bbd29f77675bcaf995284e0cdd466..e776699b62f958ebcc54989751f32908f22d991c 100644 (file)
@@ -37,6 +37,8 @@
 
 #include "em28xx.h"
 
+#define DRIVER_NAME         "em28xx"
+
 static int tuner = -1;
 module_param(tuner, int, 0444);
 MODULE_PARM_DESC(tuner, "tuner type");
@@ -45,122 +47,177 @@ static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
+static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,     "card type");
+
+/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
+static unsigned long em28xx_devused;
+
 struct em28xx_hash_table {
        unsigned long hash;
        unsigned int  model;
        unsigned int  tuner;
 };
 
+/*
+ *  Reset sequences for analog/digital modes
+ */
+
+/* Reset for the most [analog] boards */
+static struct em28xx_reg_seq default_analog[] = {
+       {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
+       {       -1,             -1,     -1,             -1},
+};
+
+/* Reset for the most [digital] boards */
+static struct em28xx_reg_seq default_digital[] = {
+       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {       -1,             -1,     -1,             -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+       {EM28XX_R08_GPIO,       0x2d,   ~EM_GPIO_4,     10},
+       {0x05,                  0xff,   0x10,           10},
+       {  -1,                  -1,     -1,             -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+       {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
+       {EM2880_R04_GPO,        0x04,   0x0f,           10},
+       {EM2880_R04_GPO,        0x0c,   0x0f,           10},
+       { -1,                   -1,     -1,             -1},
+};
+
+/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
+static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
+       {EM28XX_R08_GPIO,       0x69,   ~EM_GPIO_4,      10},
+       {       -1,             -1,     -1,              -1},
+};
+
+/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
+
+/* Board  - EM2870 Kworld 355u
+   Analog - No input analog */
+
+/* Callback for the most boards */
+static struct em28xx_reg_seq default_tuner_gpio[] = {
+       {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
+       {EM28XX_R08_GPIO,       0,              EM_GPIO_4,      10},
+       {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
+       {  -1,                  -1,             -1,             -1},
+};
+
+/*
+ *  Board definitions
+ */
 struct em28xx_board em28xx_boards[] = {
        [EM2750_BOARD_UNKNOWN] = {
                .name          = "Unknown EM2750/EM2751 webcam grabber",
-               .vchannels     = 1,
+               .xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
+               .tuner_type    = TUNER_ABSENT,  /* This is a webcam */
                .input         = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
        [EM2800_BOARD_UNKNOWN] = {
                .name         = "Unknown EM2800 video grabber",
                .is_em2800    = 1,
-               .vchannels    = 2,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input           = { {
+               .decoder      = EM28XX_SAA711X,
+               .tuner_type   = TUNER_ABSENT,
+               .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_UNKNOWN] = {
-               .name         = "Unknown EM2750/28xx video grabber",
-               .is_em2800    = 0,
-               .tuner_type   = TUNER_ABSENT,
+               .name          = "Unknown EM2750/28xx video grabber",
+               .tuner_type    = TUNER_ABSENT,
        },
        [EM2750_BOARD_DLCW_130] = {
                /* Beijing Huaqi Information Digital Technology Co., Ltd */
                .name          = "Huaqi DLCW-130",
                .valid         = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels     = 1,
+               .xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
+               .tuner_type    = TUNER_ABSENT,  /* This is a webcam */
                .input         = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
        [EM2820_BOARD_KWORLD_PVRTV2800RF] = {
                .name         = "Kworld PVR TV 2800 RF",
-               .is_em2800    = 0,
-               .vchannels    = 2,
                .tuner_type   = TUNER_TEMIC_PAL,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input           = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_TERRATEC_CINERGY_250] = {
                .name         = "Terratec Cinergy 250 USB",
-               .vchannels    = 3,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_PINNACLE_USB_2] = {
                .name         = "Pinnacle PCTV USB 2",
-               .vchannels    = 3,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
                .name         = "Hauppauge WinTV USB 2",
-               .vchannels    = 3,
                .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
                .tda9887_conf = TDA9887_PRESENT |
                                TDA9887_PORT1_ACTIVE|
                                TDA9887_PORT2_ACTIVE,
                .decoder      = EM28XX_TVP5150,
                .has_msp34xx  = 1,
-               /*FIXME: S-Video not tested */
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = MSP_INPUT_DEFAULT,
@@ -174,327 +231,305 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_DLINK_USB_TV] = {
                .name         = "D-Link DUB-T210 TV Tuner",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
-               .is_em2800    = 0,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_HERCULES_SMART_TV_USB2] = {
                .name         = "Hercules Smart TV USB 2.0",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
+               .decoder      = EM28XX_SAA711X,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = {
                .name         = "Pinnacle PCTV USB 2 (Philips FM1216ME)",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
-               .is_em2800    = 0,
                .tuner_type   = TUNER_PHILIPS_FM1216ME_MK3,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_GADMEI_UTV310] = {
                .name         = "Gadmei UTV310",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_TNF_5335MF,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = {
                .name         = "Leadtek Winfast USB II Deluxe",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_PHILIPS_FM1216ME_MK3,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7114,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
-                       .vmux     = 2,
-                       .amux     = 0,
-               }, {
-                       .type     = EM28XX_VMUX_COMPOSITE1,
-                       .vmux     = 0,
-                       .amux     = 1,
+                       .vmux     = SAA7115_COMPOSITE2,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
-                       .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = 9,
-                       .amux     = 1,
-               } },
-       },
-       [EM2820_BOARD_PINNACLE_DVC_100] = {
-               .name         = "Pinnacle Dazzle DVC 100",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
-                       .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
-               .name          = "Videology 20K14XUSB USB2.0",
+               .name         = "Videology 20K14XUSB USB2.0",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels     = 1,
-               .input         = { {
+               .tuner_type   = TUNER_ABSENT,   /* This is a webcam */
+               .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
        [EM2821_BOARD_PROLINK_PLAYTV_USB2] = {
                .name         = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
-               .is_em2800    = 0,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,  /* unknown? */
                .tda9887_conf = TDA9887_PRESENT,        /* unknown? */
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2821_BOARD_SUPERCOMP_USB_2] = {
                .name         = "Supercomp USB 2.0 TV",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
-               .is_em2800    = 0,
                .tuner_type   = TUNER_PHILIPS_FM1236_MK3,
                .tda9887_conf = TDA9887_PRESENT |
                                TDA9887_PORT1_ACTIVE |
                                TDA9887_PORT2_ACTIVE,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2821_BOARD_USBGEAR_VD204] = {
-               .name          = "Usbgear VD204v9",
+               .name         = "Usbgear VD204v9",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels     = 2,
-               .decoder       = EM28XX_SAA7113,
-               .input          = { {
+               .tuner_type   = TUNER_ABSENT,   /* Capture only device */
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type  = EM28XX_VMUX_COMPOSITE1,
                        .vmux  = SAA7115_COMPOSITE0,
-                       .amux  = 1,
+                       .amux  = EM28XX_AMUX_LINE_IN,
                }, {
                        .type  = EM28XX_VMUX_SVIDEO,
                        .vmux  = SAA7115_SVIDEO3,
-                       .amux  = 1,
+                       .amux  = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2860_BOARD_NETGMBH_CAM] = {
                /* Beijing Huaqi Information Digital Technology Co., Ltd */
-               .name          = "NetGMBH Cam",
-               .valid       = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels     = 1,
-               .input         = { {
+               .name         = "NetGMBH Cam",
+               .valid        = EM28XX_BOARD_NOT_VALIDATED,
+               .tuner_type   = TUNER_ABSENT,   /* This is a webcam */
+               .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
        [EM2860_BOARD_TYPHOON_DVD_MAKER] = {
-               .name          = "Typhoon DVD Maker",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels     = 2,
-               .decoder       = EM28XX_SAA7113,
-               .input          = { {
+               .name         = "Typhoon DVD Maker",
+               .decoder      = EM28XX_SAA711X,
+               .tuner_type   = TUNER_ABSENT,   /* Capture only device */
+               .input        = { {
                        .type  = EM28XX_VMUX_COMPOSITE1,
                        .vmux  = SAA7115_COMPOSITE0,
-                       .amux  = 1,
+                       .amux  = EM28XX_AMUX_LINE_IN,
                }, {
                        .type  = EM28XX_VMUX_SVIDEO,
                        .vmux  = SAA7115_SVIDEO3,
-                       .amux  = 1,
+                       .amux  = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2860_BOARD_GADMEI_UTV330] = {
                .name         = "Gadmei UTV330",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_TNF_5335MF,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2860_BOARD_TERRATEC_HYBRID_XS] = {
                .name         = "Terratec Cinergy A Hybrid XS",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2861_BOARD_KWORLD_PVRTV_300U] = {
                .name         = "KWorld PVRTV 300U",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = {
                .name          = "Yakumo MovieMixer",
-               .valid       = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels     = 1,
+               .tuner_type   = TUNER_ABSENT,   /* Capture only device */
                .decoder       = EM28XX_TVP5150,
                .input         = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2861_BOARD_PLEXTOR_PX_TV100U] = {
                .name         = "Plextor ConvertX PX-TV100U",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_TNF_5335MF,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
+
+       /* Those boards with em2870 are DVB Only*/
+
        [EM2870_BOARD_TERRATEC_XS] = {
                .name         = "Terratec Cinergy T XS",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
        },
        [EM2870_BOARD_TERRATEC_XS_MT2060] = {
                .name         = "Terratec Cinergy T XS (MT2060)",
@@ -505,6 +540,7 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Kworld 350 U DVB-T",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
        },
        [EM2870_BOARD_KWORLD_355U] = {
                .name         = "Kworld 355 U DVB-T",
@@ -514,164 +550,216 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Pinnacle PCTV DVB-T",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_ABSENT, /* MT2060 */
+               /* djh - I have serious doubts this is right... */
+               .xclk         = EM28XX_XCLK_IR_RC5_MODE |
+                               EM28XX_XCLK_FREQUENCY_10MHZ,
        },
        [EM2870_BOARD_COMPRO_VIDEOMATE] = {
                .name         = "Compro, VideoMate U3",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_ABSENT, /* MT2060 */
        },
+
        [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = {
                .name         = "Terratec Hybrid XS Secam",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .has_msp34xx  = 1,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                } },
        },
        [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
                .name         = "Hauppauge WinTV HVR 900",
-               .vchannels    = 3,
                .tda9887_conf = TDA9887_PRESENT,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
-               .has_dvb        = 1,
+               .has_dvb      = 1,
+               .dvb_gpio     = hauppauge_wintv_hvr_900_digital,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
                .name         = "Hauppauge WinTV HVR 900 (R2)",
-               .vchannels    = 3,
                .tda9887_conf = TDA9887_PRESENT,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
                .decoder      = EM28XX_TVP5150,
+               .input        = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = TVP5150_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
+               } },
+       },
+       [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = {
+               .name           = "Hauppauge WinTV HVR 850",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_gpio     = default_tuner_gpio,
+               .mts_firmware   = 1,
+               .has_dvb        = 1,
+               .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+               .ir_codes       = ir_codes_hauppauge_new,
+               .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 3,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
                .name           = "Hauppauge WinTV HVR 950",
-               .vchannels      = 3,
-               .tda9887_conf   = TDA9887_PRESENT,
                .tuner_type     = TUNER_XC2028,
+               .tuner_gpio     = default_tuner_gpio,
                .mts_firmware   = 1,
-               .has_12mhz_i2s  = 1,
                .has_dvb        = 1,
+               .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+               .ir_codes       = ir_codes_hauppauge_new,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
                .name           = "Pinnacle PCTV HD Pro Stick",
-               .vchannels      = 3,
-               .tda9887_conf   = TDA9887_PRESENT,
                .tuner_type     = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .mts_firmware   = 1,
-               .has_12mhz_i2s  = 1,
                .has_dvb        = 1,
+               .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+               .ir_codes       = ir_codes_pinnacle_pctv_hd,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = {
                .name           = "AMD ATI TV Wonder HD 600",
-               .vchannels      = 3,
-               .tda9887_conf   = TDA9887_PRESENT,
                .tuner_type     = TUNER_XC2028,
+               .tuner_gpio     = default_tuner_gpio,
                .mts_firmware   = 1,
-               .has_12mhz_i2s  = 1,
                .has_dvb        = 1,
+               .dvb_gpio       = hauppauge_wintv_hvr_900_digital,
+               .ir_codes       = ir_codes_ati_tv_wonder_hd_600,
                .decoder        = EM28XX_TVP5150,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2880_BOARD_TERRATEC_HYBRID_XS] = {
-               .name         = "Terratec Hybrid XS",
-               .vchannels    = 3,
-               .tda9887_conf = TDA9887_PRESENT,
-               .tuner_type   = TUNER_XC2028,
-               .decoder      = EM28XX_TVP5150,
+               .name           = "Terratec Hybrid XS",
+               .tuner_type     = TUNER_XC2028,
+               .tuner_gpio     = default_tuner_gpio,
+               .decoder        = EM28XX_TVP5150,
                .has_dvb        = 1,
+               .dvb_gpio       = default_analog,
                .input          = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                } },
        },
        /* maybe there's a reason behind it why Terratec sells the Hybrid XS
@@ -679,172 +767,168 @@ struct em28xx_board em28xx_boards[] = {
           maybe we'll need it lateron */
        [EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
                .name         = "Terratec Prodigy XS",
-               .vchannels    = 3,
-               .tda9887_conf = TDA9887_PRESENT,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2820_BOARD_MSI_VOX_USB_2] = {
                .name              = "MSI VOX USB 2.0",
-               .vchannels         = 3,
                .tuner_type        = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf      = TDA9887_PRESENT      |
                                     TDA9887_PORT1_ACTIVE |
                                     TDA9887_PORT2_ACTIVE,
                .max_range_640_480 = 1,
-
-               .decoder           = EM28XX_SAA7114,
+               .decoder           = EM28XX_SAA711X,
                .input             = { {
                        .type      = EM28XX_VMUX_TELEVISION,
                        .vmux      = SAA7115_COMPOSITE4,
-                       .amux      = 0,
+                       .amux      = EM28XX_AMUX_VIDEO,
                }, {
                        .type      = EM28XX_VMUX_COMPOSITE1,
                        .vmux      = SAA7115_COMPOSITE0,
-                       .amux      = 1,
+                       .amux      = EM28XX_AMUX_LINE_IN,
                }, {
                        .type      = EM28XX_VMUX_SVIDEO,
                        .vmux      = SAA7115_SVIDEO3,
-                       .amux      = 1,
+                       .amux      = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2800_BOARD_TERRATEC_CINERGY_200] = {
                .name         = "Terratec Cinergy 200 USB",
                .is_em2800    = 1,
-               .vchannels    = 3,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2800_BOARD_GRABBEEX_USB2800] = {
                .name         = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder",
                .is_em2800    = 1,
-               .vchannels    = 2,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .tuner_type   = TUNER_ABSENT, /* capture only board */
+               .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
                .name         = "Leadtek Winfast USB II",
                .is_em2800    = 1,
-               .vchannels    = 3,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2800_BOARD_KWORLD_USB2800] = {
                .name         = "Kworld USB2800",
                .is_em2800    = 1,
-               .vchannels    = 3,
                .tuner_type   = TUNER_PHILIPS_FCV1236D,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2820_BOARD_PINNACLE_DVC_90] = {
                .name         = "Pinnacle Dazzle DVC 90/DVC 100",
-               .vchannels    = 3,
-               .tuner_type   = TUNER_ABSENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .tuner_type   = TUNER_ABSENT, /* capture only board */
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2800_BOARD_VGEAR_POCKETTV] = {
                .name         = "V-Gear PocketTV",
                .is_em2800    = 1,
-               .vchannels    = 3,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
-       [EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
-               .name         = "Pixelview Prolink PlayTV USB 2.0",
-               .vchannels    = 3,
+       [EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2] = {
+               .name         = "Pixelview PlayTV Box 4 USB 2.0",
                .tda9887_conf = TDA9887_PRESENT,
                .tuner_type   = TUNER_YMEC_TVF_5533MF,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = SAA7115_COMPOSITE2,
-                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .aout     = EM28XX_AOUT_MONO |  /* I2S */
+                                   EM28XX_AOUT_MASTER, /* Line out pin */
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = SAA7115_COMPOSITE0,
@@ -855,229 +939,275 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
-       [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
-               .name         = "PointNix Intra-Oral Camera",
+       [EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
+               .name         = "Pixelview Prolink PlayTV USB 2.0",
                .has_snapshot_button = 1,
-               .vchannels    = 1,
                .tda9887_conf = TDA9887_PRESENT,
-               .tuner_type   = TUNER_ABSENT,
-               .decoder      = EM28XX_SAA7113,
-               .input          = { {
+               .tuner_type   = TUNER_YMEC_TVF_5533MF,
+               .decoder      = EM28XX_SAA711X,
+               .input        = { {
+                       .type     = EM28XX_VMUX_TELEVISION,
+                       .vmux     = SAA7115_COMPOSITE2,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .aout     = EM28XX_AOUT_MONO |  /* I2S */
+                                   EM28XX_AOUT_MASTER, /* Line out pin */
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
+       },
+       [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
+               .name                = "PointNix Intra-Oral Camera",
+               .has_snapshot_button = 1,
+               .tda9887_conf        = TDA9887_PRESENT,
+               .tuner_type          = TUNER_ABSENT,
+               .decoder             = EM28XX_SAA711X,
+               .input               = { {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
        [EM2880_BOARD_MSI_DIGIVOX_AD] = {
                .name         = "MSI DigiVox A/D",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = em2880_msi_digivox_ad_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = em2880_msi_digivox_ad_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = em2880_msi_digivox_ad_analog,
                } },
        },
        [EM2880_BOARD_MSI_DIGIVOX_AD_II] = {
                .name         = "MSI DigiVox A/D II",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = em2880_msi_digivox_ad_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = em2880_msi_digivox_ad_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = em2880_msi_digivox_ad_analog,
                } },
        },
        [EM2880_BOARD_KWORLD_DVB_305U] = {
                .name         = "KWorld DVB-T 305U",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2880_BOARD_KWORLD_DVB_310U] = {
                .name         = "KWorld DVB-T 310U",
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .has_dvb      = 1,
+               .dvb_gpio     = default_digital,
                .mts_firmware = 1,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = EM28XX_AMUX_AC97_LINE_IN,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                }, {    /* S-video has not been tested yet */
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = EM28XX_AMUX_AC97_LINE_IN,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                } },
        },
        [EM2881_BOARD_DNT_DA2_HYBRID] = {
                .name         = "DNT DA2 Hybrid",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                } },
        },
        [EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
                .name         = "Pinnacle Hybrid Pro",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = default_analog,
                } },
        },
        [EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
                .name         = "Pinnacle Hybrid Pro (2)",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .mts_firmware = 1,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2882_BOARD_KWORLD_VS_DVBT] = {
                .name         = "Kworld VS-DVB-T 323UR",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
        [EM2882_BOARD_TERRATEC_HYBRID_XS] = {
                .name         = "Terratec Hybrid XS (em2882)",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2883_BOARD_KWORLD_HYBRID_A316] = {
                .name         = "Kworld PlusTV HD Hybrid 330",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .vchannels    = 3,
-               .is_em2800    = 0,
                .tuner_type   = TUNER_XC2028,
+               .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .mts_firmware = 1,
+               .has_dvb      = 1,
+               .dvb_gpio     = default_digital,
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
-                       .amux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = default_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
-                       .amux     = 1,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+                       .gpio     = hauppauge_wintv_hvr_900_analog,
                } },
        },
        [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = {
                .name         = "Compro VideoMate ForYou/Stereo",
-               .vchannels    = 2,
                .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_TVP5150,
-               .input          = { {
+               .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = EM28XX_AMUX_LINE_IN,
@@ -1101,7 +1231,7 @@ struct usb_device_id em28xx_id_table [] = {
        { USB_DEVICE(0xeb1a, 0x2820),
                        .driver_info = EM2820_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0x2821),
-                       .driver_info = EM2820_BOARD_PROLINK_PLAYTV_USB2 },
+                       .driver_info = EM2820_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0x2860),
                        .driver_info = EM2820_BOARD_UNKNOWN },
        { USB_DEVICE(0xeb1a, 0x2861),
@@ -1164,8 +1294,8 @@ struct usb_device_id em28xx_id_table [] = {
                        .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
        { USB_DEVICE(0x2040, 0x651b), /* RP  HVR-950 */
                        .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
-       { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */
-                       .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+       { USB_DEVICE(0x2040, 0x651f),
+                       .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
        { USB_DEVICE(0x0438, 0xb002),
                        .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
        { USB_DEVICE(0x2001, 0xf112),
@@ -1188,79 +1318,13 @@ struct usb_device_id em28xx_id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
 
-/*
- *  Reset sequences for analog/digital modes
- */
-
-/* Reset for the most [analog] boards */
-static struct em28xx_reg_seq default_analog[] = {
-       {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
-       {       -1,             -1,     -1,             -1},
-};
-
-/* Reset for the most [digital] boards */
-static struct em28xx_reg_seq default_digital[] = {
-       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
-       {       -1,             -1,     -1,             -1},
-};
-
-/* Board Hauppauge WinTV HVR 900 analog */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
-       {EM28XX_R08_GPIO,       0x2d,   ~EM_GPIO_4,     10},
-       {0x05,                  0xff,   0x10,           10},
-       {  -1,                  -1,     -1,             -1},
-};
-
-/* Board Hauppauge WinTV HVR 900 digital */
-static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
-       {EM28XX_R08_GPIO,       0x2e,   ~EM_GPIO_4,     10},
-       {EM2880_R04_GPO,        0x04,   0x0f,           10},
-       {EM2880_R04_GPO,        0x0c,   0x0f,           10},
-       { -1,                   -1,     -1,             -1},
-};
-
-/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
-       {EM28XX_R08_GPIO,       0x69,   ~EM_GPIO_4,      10},
-       {       -1,             -1,     -1,              -1},
-};
-
-/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
-static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = {
-       {EM28XX_R08_GPIO,       0x6a,   ~EM_GPIO_4,     10},
-       {       -1,             -1,     -1,             -1},
-};
-
-/* Board  - EM2870 Kworld 355u
-   Analog - No input analog */
-static struct em28xx_reg_seq em2870_kworld_355u_digital[] = {
-       {EM2880_R04_GPO,        0x01,   0xff,           10},
-       {  -1,                  -1,     -1,             -1},
-};
-
-/* Callback for the most boards */
-static struct em28xx_reg_seq default_callback[] = {
-       {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
-       {EM28XX_R08_GPIO,       0,              EM_GPIO_4,      10},
-       {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
-       {  -1,                  -1,             -1,             -1},
-};
-
-/* Callback for EM2882 TERRATEC HYBRID XS */
-static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = {
-       {EM28XX_R08_GPIO,       0x2e,   0xff,              6},
-       {EM28XX_R08_GPIO,       0x3e,   ~EM_GPIO_4,        6},
-       {EM2880_R04_GPO,        0x04,   0xff,             10},
-       {EM2880_R04_GPO,        0x0c,   0xff,             10},
-       {  -1,                  -1,     -1,               -1},
-};
-
 /*
  * EEPROM hash table for devices with generic USB IDs
  */
 static struct em28xx_hash_table em28xx_eeprom_hash [] = {
        /* P/N: SA 60002070465 Tuner: TVF7533-MF */
        {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+       {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
 };
 
@@ -1282,27 +1346,26 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
        if (command != XC2028_TUNER_RESET)
                return 0;
 
-       if (dev->mode == EM28XX_ANALOG_MODE)
-               rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
-       else
-               rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);
+       rc = em28xx_gpio_set(dev, dev->board.tuner_gpio);
 
        return rc;
 }
 EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
 
-static void em28xx_set_model(struct em28xx *dev)
+static void inline em28xx_set_model(struct em28xx *dev)
 {
-       dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
-       dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
-       dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
-       dev->decoder = em28xx_boards[dev->model].decoder;
-       dev->video_inputs = em28xx_boards[dev->model].vchannels;
-       dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
-       dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
-       dev->has_dvb = em28xx_boards[dev->model].has_dvb;
-       dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button;
-       dev->valid = em28xx_boards[dev->model].valid;
+       memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board));
+
+       /* Those are the default values for the majority of boards
+          Use those values if not specified otherwise at boards entry
+        */
+       if (!dev->board.xclk)
+               dev->board.xclk = EM28XX_XCLK_IR_RC5_MODE |
+                                 EM28XX_XCLK_FREQUENCY_12MHZ;
+
+       if (!dev->board.i2c_speed)
+               dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+                                      EM28XX_I2C_FREQ_100_KHZ;
 }
 
 /* Since em28xx_pre_card_setup() requires a proper dev->model,
@@ -1312,205 +1375,126 @@ void em28xx_pre_card_setup(struct em28xx *dev)
 {
        int rc;
 
-       rc = em28xx_read_reg(dev, EM2880_R04_GPO);
-       if (rc >= 0)
-               dev->reg_gpo = rc;
+       em28xx_set_model(dev);
+
+       em28xx_info("Identified as %s (card=%d)\n",
+                   dev->board.name, dev->model);
+
+       /* Set the default GPO/GPIO for legacy devices */
+       dev->reg_gpo_num = EM2880_R04_GPO;
+       dev->reg_gpio_num = EM28XX_R08_GPIO;
 
        dev->wait_after_write = 5;
+
+       /* Based on the Chip ID, set the device configuration */
        rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
        if (rc > 0) {
-               switch (rc) {
+               dev->chip_id = rc;
+
+               switch (dev->chip_id) {
+               case CHIP_ID_EM2750:
+                       em28xx_info("chip ID is em2750\n");
+                       break;
+               case CHIP_ID_EM2820:
+                       em28xx_info("chip ID is em2820\n");
+                       break;
+               case CHIP_ID_EM2840:
+                       em28xx_info("chip ID is em2840\n");
+                       break;
                case CHIP_ID_EM2860:
                        em28xx_info("chip ID is em2860\n");
                        break;
+               case CHIP_ID_EM2870:
+                       em28xx_info("chip ID is em2870\n");
+                       dev->wait_after_write = 0;
+                       break;
+               case CHIP_ID_EM2874:
+                       em28xx_info("chip ID is em2874\n");
+                       dev->reg_gpio_num = EM2874_R80_GPIO;
+                       dev->wait_after_write = 0;
+                       break;
                case CHIP_ID_EM2883:
                        em28xx_info("chip ID is em2882/em2883\n");
                        dev->wait_after_write = 0;
                        break;
                default:
-                       em28xx_info("em28xx chip ID = %d\n", rc);
+                       em28xx_info("em28xx chip ID = %d\n", dev->chip_id);
                }
        }
-       em28xx_set_model(dev);
 
-       /* request some modules */
-       switch (dev->model) {
-       case EM2880_BOARD_TERRATEC_PRODIGY_XS:
-       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-       case EM2860_BOARD_TERRATEC_HYBRID_XS:
-       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
-       case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
-       case EM2882_BOARD_PINNACLE_HYBRID_PRO:
-       case EM2883_BOARD_KWORLD_HYBRID_A316:
-       case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               msleep(50);
-
-               /* Sets GPO/GPIO sequences for this device */
-               dev->analog_gpio      = hauppauge_wintv_hvr_900_analog;
-               dev->digital_gpio     = hauppauge_wintv_hvr_900_digital;
-               dev->tun_analog_gpio  = default_callback;
-               dev->tun_digital_gpio = default_callback;
-               break;
-
-       case EM2882_BOARD_TERRATEC_HYBRID_XS:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               msleep(50);
-
-               /* should be added ir_codes here */
-
-               /* Sets GPO/GPIO sequences for this device */
-               dev->analog_gpio      = hauppauge_wintv_hvr_900_analog;
-               dev->digital_gpio     = hauppauge_wintv_hvr_900_digital;
-               dev->tun_analog_gpio  = default_callback;
-               dev->tun_digital_gpio = em2882_terratec_hybrid_xs_digital;
-               break;
-
-       case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
-       case EM2880_BOARD_TERRATEC_HYBRID_XS:
-       case EM2870_BOARD_TERRATEC_XS:
-       case EM2881_BOARD_PINNACLE_HYBRID_PRO:
-       case EM2880_BOARD_KWORLD_DVB_310U:
-       case EM2870_BOARD_KWORLD_350U:
-       case EM2881_BOARD_DNT_DA2_HYBRID:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               msleep(50);
-
-               /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital
-                        and analog commands. If this commands doesn't work,
-                        add this timer. */
-
-               /* Sets GPO/GPIO sequences for this device */
-               dev->analog_gpio      = default_analog;
-               dev->digital_gpio     = default_digital;
-               dev->tun_analog_gpio  = default_callback;
-               dev->tun_digital_gpio = default_callback;
-               break;
-
-       case EM2880_BOARD_MSI_DIGIVOX_AD:
-       case EM2880_BOARD_MSI_DIGIVOX_AD_II:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK,    "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               msleep(50);
-
-               /* Sets GPO/GPIO sequences for this device */
-               dev->analog_gpio      = em2880_msi_digivox_ad_analog;
-               dev->digital_gpio     = em2880_msi_digivox_ad_digital;
-               dev->tun_analog_gpio  = default_callback;
-               dev->tun_digital_gpio = default_callback;
-               break;
+       /* Prepopulate cached GPO register content */
+       rc = em28xx_read_reg(dev, dev->reg_gpo_num);
+       if (rc >= 0)
+               dev->reg_gpo = rc;
 
-       case EM2750_BOARD_UNKNOWN:
-       case EM2750_BOARD_DLCW_130:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x0a", 1);
-               break;
+       /* Set the initial XCLK and I2C clock values based on the board
+          definition */
+       em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
+       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+       msleep(50);
 
+       /* request some modules */
+       switch (dev->model) {
        case EM2861_BOARD_PLEXTOR_PX_TV100U:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
                /* FIXME guess */
                /* Turn on analog audio output */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
                break;
-
        case EM2861_BOARD_KWORLD_PVRTV_300U:
        case EM2880_BOARD_KWORLD_DVB_305U:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1);
-               msleep(10);
-               em28xx_write_regs(dev, 0x08, "\x6d", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x6d);
                msleep(10);
-               em28xx_write_regs(dev, 0x08, "\x7d", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0x7d);
                msleep(10);
                break;
-
-       case EM2870_BOARD_KWORLD_355U:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               msleep(50);
-
-               /* Sets GPO/GPIO sequences for this device */
-               dev->digital_gpio     = em2870_kworld_355u_digital;
-               break;
-
        case EM2870_BOARD_COMPRO_VIDEOMATE:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
                /* TODO: someone can do some cleanup here...
                         not everything's needed */
-               em28xx_write_regs(dev, 0x04, "\x00", 1);
+               em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
                msleep(10);
-               em28xx_write_regs(dev, 0x04, "\x01", 1);
+               em28xx_write_reg(dev, EM2880_R04_GPO, 0x01);
                msleep(10);
-               em28xx_write_regs(dev, 0x08, "\xfd", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
                mdelay(70);
-               em28xx_write_regs(dev, 0x08, "\xfc", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
                mdelay(70);
-               em28xx_write_regs(dev, 0x08, "\xdc", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xdc);
                mdelay(70);
-               em28xx_write_regs(dev, 0x08, "\xfc", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfc);
                mdelay(70);
                break;
-
        case EM2870_BOARD_TERRATEC_XS_MT2060:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
                /* this device needs some gpio writes to get the DVB-T
                   demod work */
-               em28xx_write_regs(dev, 0x08, "\xfe", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
                mdelay(70);
-               em28xx_write_regs(dev, 0x08, "\xde", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
                mdelay(70);
-               dev->em28xx_write_regs(dev, 0x08, "\xfe", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
                mdelay(70);
                break;
-
        case EM2870_BOARD_PINNACLE_PCTV_DVB:
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
                /* this device needs some gpio writes to get the
                   DVB-T demod work */
-               em28xx_write_regs(dev, 0x08, "\xfe", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
                mdelay(70);
-               em28xx_write_regs(dev, 0x08, "\xde", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xde);
                mdelay(70);
-               em28xx_write_regs(dev, 0x08, "\xfe", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
                mdelay(70);
-               /* switch em2880 rc protocol */
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x22", 1);
-               /* should be added ir_codes here */
                break;
-
        case EM2820_BOARD_GADMEI_UTV310:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               /* Turn on analog audio output */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
-               break;
-
-       case EM2860_BOARD_GADMEI_UTV330:
-               /* Turn on IR */
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               /* should be added ir_codes here */
-               break;
-
        case EM2820_BOARD_MSI_VOX_USB_2:
-               em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
-               em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
-               /* enables audio for that device */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
+               /* enables audio for that devices */
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
                break;
        }
 
-       em28xx_gpio_set(dev, dev->tun_analog_gpio);
+       em28xx_gpio_set(dev, dev->board.tuner_gpio);
        em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
 
        /* Unlock device */
-       em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+       em28xx_set_mode(dev, EM28XX_SUSPEND);
 }
 
 static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
@@ -1536,6 +1520,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
                ctl->demod = XC3028_FE_DEFAULT;
                ctl->fname = XC3028L_DEFAULT_FIRMWARE;
                break;
+       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
                /* FIXME: Better to specify the needed IF */
@@ -1712,12 +1697,15 @@ void em28xx_card_setup(struct em28xx *dev)
        em28xx_set_model(dev);
 
        dev->tuner_type = em28xx_boards[dev->model].tuner_type;
+       if (em28xx_boards[dev->model].tuner_addr)
+               dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
 
        /* request some modules */
        switch (dev->model) {
        case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        {
                struct tveeprom tv;
@@ -1733,7 +1721,7 @@ void em28xx_card_setup(struct em28xx *dev)
 
                if (tv.audio_processor == V4L2_IDENT_MSPX4XX) {
                        dev->i2s_speed = 2048000;
-                       dev->has_msp34xx = 1;
+                       dev->board.has_msp34xx = 1;
                }
 #ifdef CONFIG_MODULES
                if (tv.has_ir)
@@ -1743,7 +1731,7 @@ void em28xx_card_setup(struct em28xx *dev)
        }
        case EM2820_BOARD_KWORLD_PVRTV2800RF:
                /* GPIO enables sound on KWORLD PVR TV 2800RF */
-               em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
                break;
        case EM2820_BOARD_UNKNOWN:
        case EM2800_BOARD_UNKNOWN:
@@ -1766,10 +1754,10 @@ void em28xx_card_setup(struct em28xx *dev)
                break;
        }
 
-       if (dev->has_snapshot_button)
+       if (dev->board.has_snapshot_button)
                em28xx_register_snapshot_button(dev);
 
-       if (dev->valid == EM28XX_BOARD_NOT_VALIDATED) {
+       if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) {
                em28xx_errdev("\n\n");
                em28xx_errdev("The support for this board weren't "
                              "valid yet.\n");
@@ -1784,15 +1772,433 @@ void em28xx_card_setup(struct em28xx *dev)
 
 #ifdef CONFIG_MODULES
        /* request some modules */
-       if (dev->has_msp34xx)
+       if (dev->board.has_msp34xx)
                request_module("msp3400");
-       if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+       if (dev->board.decoder == EM28XX_SAA711X)
                request_module("saa7115");
-       if (dev->decoder == EM28XX_TVP5150)
+       if (dev->board.decoder == EM28XX_TVP5150)
                request_module("tvp5150");
-       if (dev->tuner_type != TUNER_ABSENT)
+       if (dev->board.tuner_type != TUNER_ABSENT)
                request_module("tuner");
 #endif
 
        em28xx_config_tuner(dev);
+
+       em28xx_ir_init(dev);
+}
+
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+       struct em28xx *dev = container_of(work,
+                            struct em28xx, request_module_wk);
+
+       if (dev->has_audio_class)
+               request_module("snd-usb-audio");
+       else if (dev->has_alsa_audio)
+               request_module("em28xx-alsa");
+
+       if (dev->board.has_dvb)
+               request_module("em28xx-dvb");
+}
+
+static void request_modules(struct em28xx *dev)
+{
+       INIT_WORK(&dev->request_module_wk, request_module_async);
+       schedule_work(&dev->request_module_wk);
+}
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_release_resources(struct em28xx *dev)
+{
+       if (dev->sbutton_input_dev)
+               em28xx_deregister_snapshot_button(dev);
+
+       if (dev->ir)
+               em28xx_ir_fini(dev);
+
+       /*FIXME: I2C IR should be disconnected */
+
+       em28xx_release_analog_resources(dev);
+
+       em28xx_remove_from_devlist(dev);
+
+       em28xx_i2c_unregister(dev);
+       usb_put_dev(dev->udev);
+
+       /* Mark device as unused */
+       em28xx_devused &= ~(1 << dev->devno);
+};
+
+/*
+ * em28xx_init_dev()
+ * allocates and inits the device structs, registers i2c bus and v4l device
+ */
+int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+                          int minor)
+{
+       struct em28xx *dev = *devhandle;
+       int retval = -ENOMEM;
+       int errCode;
+
+       dev->udev = udev;
+       mutex_init(&dev->ctrl_urb_lock);
+       spin_lock_init(&dev->slock);
+       init_waitqueue_head(&dev->open);
+       init_waitqueue_head(&dev->wait_frame);
+       init_waitqueue_head(&dev->wait_stream);
+
+       dev->em28xx_write_regs = em28xx_write_regs;
+       dev->em28xx_read_reg = em28xx_read_reg;
+       dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
+       dev->em28xx_write_regs_req = em28xx_write_regs_req;
+       dev->em28xx_read_reg_req = em28xx_read_reg_req;
+       dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
+
+       em28xx_pre_card_setup(dev);
+
+       if (!dev->board.is_em2800) {
+               /* Sets I2C speed to 100 KHz */
+               retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
+               if (retval < 0) {
+                       em28xx_errdev("%s: em28xx_write_regs_req failed!"
+                                     " retval [%d]\n",
+                                     __func__, retval);
+                       return retval;
+               }
+       }
+
+       /* register i2c bus */
+       errCode = em28xx_i2c_register(dev);
+       if (errCode < 0) {
+               em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
+                       __func__, errCode);
+               return errCode;
+       }
+
+       /* Do board specific init and eeprom reading */
+       em28xx_card_setup(dev);
+
+       /* Configure audio */
+       errCode = em28xx_audio_setup(dev);
+       if (errCode < 0) {
+               em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
+                       __func__, errCode);
+       }
+
+       /* wake i2c devices */
+       em28xx_wake_i2c(dev);
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       INIT_LIST_HEAD(&dev->vidq.queued);
+
+
+       if (dev->board.has_msp34xx) {
+               /* Send a reset to other chips via gpio */
+               errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7);
+               if (errCode < 0) {
+                       em28xx_errdev("%s: em28xx_write_regs_req - "
+                                     "msp34xx(1) failed! errCode [%d]\n",
+                                     __func__, errCode);
+                       return errCode;
+               }
+               msleep(3);
+
+               errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               if (errCode < 0) {
+                       em28xx_errdev("%s: em28xx_write_regs_req - "
+                                     "msp34xx(2) failed! errCode [%d]\n",
+                                     __func__, errCode);
+                       return errCode;
+               }
+               msleep(3);
+       }
+
+       em28xx_add_into_devlist(dev);
+
+       retval = em28xx_register_analog_devices(dev);
+       if (retval < 0) {
+               em28xx_release_resources(dev);
+               goto fail_reg_devices;
+       }
+
+       em28xx_init_extension(dev);
+
+       /* Save some power by putting tuner to sleep */
+       em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
+       return 0;
+
+fail_reg_devices:
+       return retval;
 }
+
+/*
+ * em28xx_usb_probe()
+ * checks for supported devices
+ */
+static int em28xx_usb_probe(struct usb_interface *interface,
+                           const struct usb_device_id *id)
+{
+       const struct usb_endpoint_descriptor *endpoint;
+       struct usb_device *udev;
+       struct usb_interface *uif;
+       struct em28xx *dev = NULL;
+       int retval = -ENODEV;
+       int i, nr, ifnum, isoc_pipe;
+       char *speed;
+       char descr[255] = "";
+
+       udev = usb_get_dev(interface_to_usbdev(interface));
+       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+
+       /* Check to see next free device and mark as used */
+       nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+       em28xx_devused |= 1<<nr;
+
+       /* Don't register audio interfaces */
+       if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+               em28xx_err(DRIVER_NAME " audio device (%04x:%04x): "
+                       "interface %i, class %i\n",
+                       le16_to_cpu(udev->descriptor.idVendor),
+                       le16_to_cpu(udev->descriptor.idProduct),
+                       ifnum,
+                       interface->altsetting[0].desc.bInterfaceClass);
+
+               em28xx_devused &= ~(1<<nr);
+               return -ENODEV;
+       }
+
+       endpoint = &interface->cur_altsetting->endpoint[0].desc;
+
+       /* check if the device has the iso in endpoint at the correct place */
+       if (usb_endpoint_xfer_isoc(endpoint)
+           &&
+           (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) {
+               /* It's a newer em2874/em2875 device */
+               isoc_pipe = 0;
+       } else {
+               int check_interface = 1;
+               isoc_pipe = 1;
+               endpoint = &interface->cur_altsetting->endpoint[1].desc;
+               if (usb_endpoint_type(endpoint) !=
+                   USB_ENDPOINT_XFER_ISOC)
+                       check_interface = 0;
+
+               if (usb_endpoint_dir_out(endpoint))
+                       check_interface = 0;
+
+               if (!check_interface) {
+                       em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
+                               "interface %i, class %i found.\n",
+                               le16_to_cpu(udev->descriptor.idVendor),
+                               le16_to_cpu(udev->descriptor.idProduct),
+                               ifnum,
+                               interface->altsetting[0].desc.bInterfaceClass);
+
+                       em28xx_err(DRIVER_NAME " This is an anciliary "
+                               "interface not used by the driver\n");
+
+                       em28xx_devused &= ~(1<<nr);
+                       return -ENODEV;
+               }
+       }
+
+       switch (udev->speed) {
+       case USB_SPEED_LOW:
+               speed = "1.5";
+               break;
+       case USB_SPEED_UNKNOWN:
+       case USB_SPEED_FULL:
+               speed = "12";
+               break;
+       case USB_SPEED_HIGH:
+               speed = "480";
+               break;
+       default:
+               speed = "unknown";
+       }
+
+       if (udev->manufacturer)
+               strlcpy(descr, udev->manufacturer, sizeof(descr));
+
+       if (udev->product) {
+               if (*descr)
+                       strlcat(descr, " ", sizeof(descr));
+               strlcat(descr, udev->product, sizeof(descr));
+       }
+       if (*descr)
+               strlcat(descr, " ", sizeof(descr));
+
+       printk(DRIVER_NAME ": New device %s@ %s Mbps "
+               "(%04x:%04x, interface %d, class %d)\n",
+               descr,
+               speed,
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct),
+               ifnum,
+               interface->altsetting->desc.bInterfaceNumber);
+
+       if (nr >= EM28XX_MAXBOARDS) {
+               printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+                               EM28XX_MAXBOARDS);
+               em28xx_devused &= ~(1<<nr);
+               return -ENOMEM;
+       }
+
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               em28xx_err(DRIVER_NAME ": out of memory!\n");
+               em28xx_devused &= ~(1<<nr);
+               return -ENOMEM;
+       }
+
+       snprintf(dev->name, 29, "em28xx #%d", nr);
+       dev->devno = nr;
+       dev->model = id->driver_info;
+       dev->alt   = -1;
+
+       /* Checks if audio is provided by some interface */
+       for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+               uif = udev->config->interface[i];
+               if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+                       dev->has_audio_class = 1;
+                       break;
+               }
+       }
+
+       /* compute alternate max packet sizes */
+       uif = udev->actconfig->interface[0];
+
+       dev->num_alt = uif->num_altsetting;
+       dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
+
+       if (dev->alt_max_pkt_size == NULL) {
+               em28xx_errdev("out of memory!\n");
+               em28xx_devused &= ~(1<<nr);
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < dev->num_alt ; i++) {
+               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+               dev->alt_max_pkt_size[i] =
+                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+       }
+
+       if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
+               dev->model = card[nr];
+
+       /* allocate device struct */
+       mutex_init(&dev->lock);
+       mutex_lock(&dev->lock);
+       retval = em28xx_init_dev(&dev, udev, nr);
+       if (retval) {
+               em28xx_devused &= ~(1<<dev->devno);
+               kfree(dev);
+
+               return retval;
+       }
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       request_modules(dev);
+
+       /* Should be the last thing to do, to avoid newer udev's to
+          open the device before fully initializing it
+        */
+       mutex_unlock(&dev->lock);
+
+       return 0;
+}
+
+/*
+ * em28xx_usb_disconnect()
+ * called when the device gets diconencted
+ * video device will be unregistered on v4l2_close in case it is still open
+ */
+static void em28xx_usb_disconnect(struct usb_interface *interface)
+{
+       struct em28xx *dev;
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       if (!dev)
+               return;
+
+       em28xx_info("disconnecting %s\n", dev->vdev->name);
+
+       /* wait until all current v4l2 io is finished then deallocate
+          resources */
+       mutex_lock(&dev->lock);
+
+       wake_up_interruptible_all(&dev->open);
+
+       if (dev->users) {
+               em28xx_warn
+                   ("device /dev/video%d is open! Deregistration and memory "
+                    "deallocation are deferred on close.\n",
+                               dev->vdev->num);
+
+               dev->state |= DEV_MISCONFIGURED;
+               em28xx_uninit_isoc(dev);
+               dev->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&dev->wait_frame);
+               wake_up_interruptible(&dev->wait_stream);
+       } else {
+               dev->state |= DEV_DISCONNECTED;
+               em28xx_release_resources(dev);
+       }
+
+       em28xx_close_extension(dev);
+
+       mutex_unlock(&dev->lock);
+
+       if (!dev->users) {
+               kfree(dev->alt_max_pkt_size);
+               kfree(dev);
+       }
+}
+
+static struct usb_driver em28xx_usb_driver = {
+       .name = "em28xx",
+       .probe = em28xx_usb_probe,
+       .disconnect = em28xx_usb_disconnect,
+       .id_table = em28xx_id_table,
+};
+
+static int __init em28xx_module_init(void)
+{
+       int result;
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&em28xx_usb_driver);
+       if (result)
+               em28xx_err(DRIVER_NAME
+                          " usb_register failed. Error number %d.\n", result);
+
+       printk(KERN_INFO DRIVER_NAME " driver loaded\n");
+
+       return result;
+}
+
+static void __exit em28xx_module_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&em28xx_usb_driver);
+}
+
+module_init(em28xx_module_init);
+module_exit(em28xx_module_exit);
index 15e2b525310db9af34bf6377f573691ed04c1314..f8504518586abadc2fb27208b331c2010327596b 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
 
 #include "em28xx.h"
 
@@ -66,7 +67,8 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
                                   char *buf, int len)
 {
-       int ret, byte;
+       int ret;
+       int pipe = usb_rcvctrlpipe(dev->udev, 0);
 
        if (dev->state & DEV_DISCONNECTED)
                return -ENODEV;
@@ -74,10 +76,18 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
        if (len > URB_MAX_CTRL_SIZE)
                return -EINVAL;
 
-       em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+       if (reg_debug) {
+               printk( KERN_DEBUG "(pipe 0x%08x): "
+                       "IN:  %02x %02x %02x %02x %02x %02x %02x %02x ",
+                       pipe,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       req, 0, 0,
+                       reg & 0xff, reg >> 8,
+                       len & 0xff, len >> 8);
+       }
 
        mutex_lock(&dev->ctrl_urb_lock);
-       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
+       ret = usb_control_msg(dev->udev, pipe, req,
                              USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x0000, reg, dev->urb_buf, len, HZ);
        if (ret < 0) {
@@ -93,7 +103,9 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
        mutex_unlock(&dev->ctrl_urb_lock);
 
        if (reg_debug) {
-               printk("%02x values: ", ret);
+               int byte;
+
+               printk("<<<");
                for (byte = 0; byte < len; byte++)
                        printk(" %02x", (unsigned char)buf[byte]);
                printk("\n");
@@ -108,28 +120,12 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
  */
 int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
 {
-       u8 val;
        int ret;
+       u8 val;
 
-       if (dev->state & DEV_DISCONNECTED)
-               return(-ENODEV);
-
-       em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
-
-       mutex_lock(&dev->ctrl_urb_lock);
-       ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
-                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             0x0000, reg, dev->urb_buf, 1, HZ);
-       val = dev->urb_buf[0];
-       mutex_unlock(&dev->ctrl_urb_lock);
-
-       if (ret < 0) {
-               printk(" failed!\n");
+       ret = em28xx_read_reg_req_len(dev, req, reg, &val, 1);
+       if (ret < 0)
                return ret;
-       }
-
-       if (reg_debug)
-               printk("%02x\n", (unsigned char) val);
 
        return val;
 }
@@ -147,6 +143,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
                                 int len)
 {
        int ret;
+       int pipe = usb_sndctrlpipe(dev->udev, 0);
 
        if (dev->state & DEV_DISCONNECTED)
                return -ENODEV;
@@ -154,17 +151,25 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
        if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
                return -EINVAL;
 
-       em28xx_regdbg("req=%02x reg=%02x:", req, reg);
        if (reg_debug) {
-               int i;
-               for (i = 0; i < len; ++i)
-                       printk(" %02x", (unsigned char)buf[i]);
+               int byte;
+
+               printk( KERN_DEBUG "(pipe 0x%08x): "
+                       "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
+                       pipe,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       req, 0, 0,
+                       reg & 0xff, reg >> 8,
+                       len & 0xff, len >> 8);
+
+               for (byte = 0; byte < len; byte++)
+                       printk(" %02x", (unsigned char)buf[byte]);
                printk("\n");
        }
 
        mutex_lock(&dev->ctrl_urb_lock);
        memcpy(dev->urb_buf, buf, len);
-       ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
+       ret = usb_control_msg(dev->udev, pipe, req,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                              0x0000, reg, dev->urb_buf, len, HZ);
        mutex_unlock(&dev->ctrl_urb_lock);
@@ -187,15 +192,21 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
           Not sure what happens on reading GPO register.
         */
        if (rc >= 0) {
-               if (reg == EM2880_R04_GPO)
+               if (reg == dev->reg_gpo_num)
                        dev->reg_gpo = buf[0];
-               else if (reg == EM28XX_R08_GPIO)
+               else if (reg == dev->reg_gpio_num)
                        dev->reg_gpio = buf[0];
        }
 
        return rc;
 }
 
+/* Write a single register */
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
+{
+       return em28xx_write_regs(dev, reg, &val, 1);
+}
+
 /*
  * em28xx_write_reg_bits()
  * sets only some bits (specified by bitmask) of a register, by first reading
@@ -208,9 +219,9 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
        u8 newval;
 
        /* Uses cache for gpo/gpio registers */
-       if (reg == EM2880_R04_GPO)
+       if (reg == dev->reg_gpo_num)
                oldval = dev->reg_gpo;
-       else if (reg == EM28XX_R08_GPIO)
+       else if (reg == dev->reg_gpio_num)
                oldval = dev->reg_gpio;
        else
                oldval = em28xx_read_reg(dev, reg);
@@ -223,16 +234,71 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
        return em28xx_write_regs(dev, reg, &newval, 1);
 }
 
+/*
+ * em28xx_is_ac97_ready()
+ * Checks if ac97 is ready
+ */
+static int em28xx_is_ac97_ready(struct em28xx *dev)
+{
+       int ret, i;
+
+       /* Wait up to 50 ms for AC97 command to complete */
+       for (i = 0; i < 10; i++, msleep(5)) {
+               ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+               if (ret < 0)
+                       return ret;
+
+               if (!(ret & 0x01))
+                       return 0;
+       }
+
+       em28xx_warn("AC97 command still being executed: not handled properly!\n");
+       return -EBUSY;
+}
+
+/*
+ * em28xx_read_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+int em28xx_read_ac97(struct em28xx *dev, u8 reg)
+{
+       int ret;
+       u8 addr = (reg & 0x7f) | 0x80;
+       u16 val;
+
+       ret = em28xx_is_ac97_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
+                                          (u8 *)&val, sizeof(val));
+
+       if (ret < 0)
+               return ret;
+       return le16_to_cpu(val);
+}
+
 /*
  * em28xx_write_ac97()
  * write a 16 bit value to the specified AC97 address (LSB first!)
  */
-static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
 {
-       int ret, i;
+       int ret;
        u8 addr = reg & 0x7f;
+       __le16 value;
 
-       ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);
+       value = cpu_to_le16(val);
+
+       ret = em28xx_is_ac97_ready(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
        if (ret < 0)
                return ret;
 
@@ -240,58 +306,74 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
        if (ret < 0)
                return ret;
 
-       /* Wait up to 50 ms for AC97 command to complete */
-       for (i = 0; i < 10; i++) {
-               ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
-               if (ret < 0)
-                       return ret;
+       return 0;
+}
 
-               if (!(ret & 0x01))
-                       return 0;
-               msleep(5);
+struct em28xx_vol_table {
+       enum em28xx_amux mux;
+       u8               reg;
+};
+
+static struct em28xx_vol_table inputs[] = {
+       { EM28XX_AMUX_VIDEO,    AC97_VIDEO_VOL   },
+       { EM28XX_AMUX_LINE_IN,  AC97_LINEIN_VOL  },
+       { EM28XX_AMUX_PHONE,    AC97_PHONE_VOL   },
+       { EM28XX_AMUX_MIC,      AC97_MIC_VOL     },
+       { EM28XX_AMUX_CD,       AC97_CD_VOL      },
+       { EM28XX_AMUX_AUX,      AC97_AUX_VOL     },
+       { EM28XX_AMUX_PCM_OUT,  AC97_PCM_OUT_VOL },
+};
+
+static int set_ac97_input(struct em28xx *dev)
+{
+       int ret, i;
+       enum em28xx_amux amux = dev->ctl_ainput;
+
+       /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+          em28xx should point to LINE IN, while AC97 should use VIDEO
+        */
+       if (amux == EM28XX_AMUX_VIDEO2)
+               amux = EM28XX_AMUX_VIDEO;
+
+       /* Mute all entres but the one that were selected */
+       for (i = 0; i < ARRAY_SIZE(inputs); i++) {
+               if (amux == inputs[i].mux)
+                       ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
+               else
+                       ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
+
+               if (ret < 0)
+                       em28xx_warn("couldn't setup AC97 register %d\n",
+                                    inputs[i].reg);
        }
-       em28xx_warn("AC97 command still being executed: not handled properly!\n");
        return 0;
 }
 
 static int em28xx_set_audio_source(struct em28xx *dev)
 {
-       static char *enable  = "\x08\x08";
-       static char *disable = "\x08\x88";
-       char *video = enable, *line = disable;
        int ret;
        u8 input;
 
-       if (dev->is_em2800) {
-               if (dev->ctl_ainput)
-                       input = EM2800_AUDIO_SRC_LINE;
-               else
+       if (dev->board.is_em2800) {
+               if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
                        input = EM2800_AUDIO_SRC_TUNER;
+               else
+                       input = EM2800_AUDIO_SRC_LINE;
 
                ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
                if (ret < 0)
                        return ret;
        }
 
-       if (dev->has_msp34xx)
+       if (dev->board.has_msp34xx)
                input = EM28XX_AUDIO_SRC_TUNER;
        else {
                switch (dev->ctl_ainput) {
                case EM28XX_AMUX_VIDEO:
                        input = EM28XX_AUDIO_SRC_TUNER;
                        break;
-               case EM28XX_AMUX_LINE_IN:
+               default:
                        input = EM28XX_AUDIO_SRC_LINE;
-                       video = disable;
-                       line  = enable;
-                       break;
-               case EM28XX_AMUX_AC97_VIDEO:
-                       input = EM28XX_AUDIO_SRC_LINE;
-                       break;
-               case EM28XX_AMUX_AC97_LINE_IN:
-                       input = EM28XX_AUDIO_SRC_LINE;
-                       video = disable;
-                       line  = enable;
                        break;
                }
        }
@@ -301,41 +383,50 @@ static int em28xx_set_audio_source(struct em28xx *dev)
                return ret;
        msleep(5);
 
-       /* Sets AC97 mixer registers
-          This is seems to be needed, even for non-ac97 configs
-        */
-       ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);
-       if (ret < 0)
-               return ret;
-
-       ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);
+       switch (dev->audio_mode.ac97) {
+       case EM28XX_NO_AC97:
+               break;
+       default:
+               ret = set_ac97_input(dev);
+       }
 
        return ret;
 }
 
+struct em28xx_vol_table outputs[] = {
+       { EM28XX_AOUT_MASTER, AC97_MASTER_VOL      },
+       { EM28XX_AOUT_LINE,   AC97_LINE_LEVEL_VOL  },
+       { EM28XX_AOUT_MONO,   AC97_MASTER_MONO_VOL },
+       { EM28XX_AOUT_LFE,    AC97_LFE_MASTER_VOL  },
+       { EM28XX_AOUT_SURR,   AC97_SURR_MASTER_VOL },
+};
+
 int em28xx_audio_analog_set(struct em28xx *dev)
 {
-       int ret;
-       char s[2] = { 0x00, 0x00 };
-       u8 xclk = 0x07;
-
-       s[0] |= 0x1f - dev->volume;
-       s[1] |= 0x1f - dev->volume;
-
-       /* Mute */
-       s[1] |= 0x80;
-       ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
+       int ret, i;
+       u8 xclk;
 
-       if (ret < 0)
-               return ret;
+       if (!dev->audio_mode.has_audio)
+               return 0;
 
-       if (dev->has_12mhz_i2s)
-               xclk |= 0x20;
+       /* It is assumed that all devices use master volume for output.
+          It would be possible to use also line output.
+        */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               /* Mute all outputs */
+               for (i = 0; i < ARRAY_SIZE(outputs); i++) {
+                       ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000);
+                       if (ret < 0)
+                               em28xx_warn("couldn't setup AC97 register %d\n",
+                                    outputs[i].reg);
+               }
+       }
 
+       xclk = dev->board.xclk & 0x7f;
        if (!dev->mute)
                xclk |= 0x80;
 
-       ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
+       ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
        if (ret < 0)
                return ret;
        msleep(10);
@@ -343,36 +434,169 @@ int em28xx_audio_analog_set(struct em28xx *dev)
        /* Selects the proper audio input */
        ret = em28xx_set_audio_source(dev);
 
-       /* Unmute device */
-       if (!dev->mute)
-               s[1] &= ~0x80;
-       ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
+       /* Sets volume */
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               int vol;
+
+               /* LSB: left channel - both channels with the same level */
+               vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
+
+               /* Mute device, if needed */
+               if (dev->mute)
+                       vol |= 0x8000;
+
+               /* Sets volume */
+               for (i = 0; i < ARRAY_SIZE(outputs); i++) {
+                       if (dev->ctl_aoutput & outputs[i].mux)
+                               ret = em28xx_write_ac97(dev, outputs[i].reg,
+                                                       vol);
+                       if (ret < 0)
+                               em28xx_warn("couldn't setup AC97 register %d\n",
+                                    outputs[i].reg);
+               }
+       }
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
 
-int em28xx_colorlevels_set_default(struct em28xx *dev)
+int em28xx_audio_setup(struct em28xx *dev)
 {
-       em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1);    /* contrast */
-       em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1);  /* brightness */
-       em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1);   /* saturation */
-       em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);
-       em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);
-       em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);
+       int vid1, vid2, feat, cfg;
+       u32 vid;
+
+       if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) {
+               /* Digital only device - don't load any alsa module */
+               dev->audio_mode.has_audio = 0;
+               dev->has_audio_class = 0;
+               dev->has_alsa_audio = 0;
+               return 0;
+       }
+
+       /* If device doesn't support Usb Audio Class, use vendor class */
+       if (!dev->has_audio_class)
+               dev->has_alsa_audio = 1;
+
+       dev->audio_mode.has_audio = 1;
 
-       em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);
-       em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);
-       em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);
-       em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);
-       em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);
-       em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);
-       return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);
+       /* See how this device is configured */
+       cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
+       if (cfg < 0)
+               cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+       else
+               em28xx_info("Config register raw data: 0x%02x\n", cfg);
+
+       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                   EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+               em28xx_info("I2S Audio (3 sample rates)\n");
+               dev->audio_mode.i2s_3rates = 1;
+       }
+       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                   EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+               em28xx_info("I2S Audio (5 sample rates)\n");
+               dev->audio_mode.i2s_5rates = 1;
+       }
+
+       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+               /* Skip the code that does AC97 vendor detection */
+               dev->audio_mode.ac97 = EM28XX_NO_AC97;
+               goto init_audio;
+       }
+
+       dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
+
+       vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
+       if (vid1 < 0) {
+               /* Device likely doesn't support AC97 */
+               em28xx_warn("AC97 chip type couldn't be determined\n");
+               goto init_audio;
+       }
+
+       vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2);
+       if (vid2 < 0)
+               goto init_audio;
+
+       vid = vid1 << 16 | vid2;
+
+       dev->audio_mode.ac97_vendor_id = vid;
+       em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
+
+       feat = em28xx_read_ac97(dev, AC97_RESET);
+       if (feat < 0)
+               goto init_audio;
+
+       dev->audio_mode.ac97_feat = feat;
+       em28xx_warn("AC97 features = 0x%04x\n", feat);
+
+       /* Try to identify what audio processor we have */
+       if ((vid == 0xffffffff) && (feat == 0x6a90))
+               dev->audio_mode.ac97 = EM28XX_AC97_EM202;
+       else if ((vid >> 8) == 0x838476)
+               dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL;
+
+init_audio:
+       /* Reports detected AC97 processor */
+       switch (dev->audio_mode.ac97) {
+       case EM28XX_NO_AC97:
+               em28xx_info("No AC97 audio processor\n");
+               break;
+       case EM28XX_AC97_EM202:
+               em28xx_info("Empia 202 AC97 audio processor detected\n");
+               break;
+       case EM28XX_AC97_SIGMATEL:
+               em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
+                           dev->audio_mode.ac97_vendor_id & 0xff);
+               break;
+       case EM28XX_AC97_OTHER:
+               em28xx_warn("Unknown AC97 audio processor detected!\n");
+               break;
+       default:
+               break;
+       }
+
+       return em28xx_audio_analog_set(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_setup);
+
+int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+       em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10);  /* contrast */
+       em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00);        /* brightness */
+       em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */
+       em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
+       em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
+       em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
+
+       em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+       em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+       em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+       em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+       em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+       em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+       return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
 }
 
 int em28xx_capture_start(struct em28xx *dev, int start)
 {
        int rc;
+
+       if (dev->chip_id == CHIP_ID_EM2874) {
+               /* The Transport Stream Enable Register moved in em2874 */
+               if (!start) {
+                       rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+                                                  0x00,
+                                                  EM2874_TS1_CAPTURE_ENABLE);
+                       return rc;
+               }
+
+               /* Enable Transport Stream */
+               rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+                                          EM2874_TS1_CAPTURE_ENABLE,
+                                          EM2874_TS1_CAPTURE_ENABLE);
+               return rc;
+       }
+
+
        /* FIXME: which is the best order? */
        /* video registers are sampled by VREF */
        rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
@@ -382,28 +606,37 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 
        if (!start) {
                /* disable video capture */
-               rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1);
+               rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
                return rc;
        }
 
        /* enable video capture */
-       rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+       rc = em28xx_write_reg(dev, 0x48, 0x00);
 
        if (dev->mode == EM28XX_ANALOG_MODE)
-               rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1);
+               rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
        else
-               rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1);
+               rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
 
        msleep(6);
 
        return rc;
 }
 
-int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+int em28xx_set_outfmt(struct em28xx *dev)
 {
-       em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1);
-       em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1);
-       return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1);
+       int ret;
+
+       ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
+                                   dev->format->reg | 0x20, 0x3f);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+       if (ret < 0)
+               return ret;
+
+       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11);
 }
 
 static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -440,7 +673,7 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
 {
        u8 mode;
        /* the em2800 scaler only supports scaling down to 50% */
-       if (dev->is_em2800)
+       if (dev->board.is_em2800)
                mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
        else {
                u8 buf[2];
@@ -464,7 +697,7 @@ int em28xx_resolution_set(struct em28xx *dev)
        width = norm_maxw(dev);
        height = norm_maxh(dev) >> 1;
 
-       em28xx_outfmt_set_yuv422(dev);
+       em28xx_set_outfmt(dev);
        em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
        em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
        return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
@@ -519,12 +752,14 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
        if (!gpio)
                return rc;
 
-       dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
-       if (dev->mode == EM28XX_ANALOG_MODE)
-               dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
-       else
-               dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
-       msleep(6);
+       if (dev->mode != EM28XX_SUSPEND) {
+               em28xx_write_reg(dev, 0x48, 0x00);
+               if (dev->mode == EM28XX_ANALOG_MODE)
+                       em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
+               else
+                       em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+               msleep(6);
+       }
 
        /* Send GPIO reset sequences specified at board entry */
        while (gpio->sleep >= 0) {
@@ -549,17 +784,20 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
        if (dev->mode == set_mode)
                return 0;
 
-       if (set_mode == EM28XX_MODE_UNDEFINED) {
+       if (set_mode == EM28XX_SUSPEND) {
                dev->mode = set_mode;
-               return 0;
+
+               /* FIXME: add suspend support for ac97 */
+
+               return em28xx_gpio_set(dev, dev->board.suspend_gpio);
        }
 
        dev->mode = set_mode;
 
        if (dev->mode == EM28XX_DIGITAL_MODE)
-               return em28xx_gpio_set(dev, dev->digital_gpio);
+               return em28xx_gpio_set(dev, dev->board.dvb_gpio);
        else
-               return em28xx_gpio_set(dev, dev->analog_gpio);
+               return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
 }
 EXPORT_SYMBOL_GPL(em28xx_set_mode);
 
@@ -738,3 +976,145 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
        return 0;
 }
 EXPORT_SYMBOL_GPL(em28xx_init_isoc);
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+void em28xx_wake_i2c(struct em28xx *dev)
+{
+       struct v4l2_routing route;
+       int zero = 0;
+
+       route.input = INPUT(dev->ctl_input)->vmux;
+       route.output = 0;
+       em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
+       em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
+}
+
+/*
+ * Device control list
+ */
+
+static LIST_HEAD(em28xx_devlist);
+static DEFINE_MUTEX(em28xx_devlist_mutex);
+
+struct em28xx *em28xx_get_device(struct inode *inode,
+                                enum v4l2_buf_type *fh_type,
+                                int *has_radio)
+{
+       struct em28xx *h, *dev = NULL;
+       int minor = iminor(inode);
+
+       *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       *has_radio = 0;
+
+       mutex_lock(&em28xx_devlist_mutex);
+       list_for_each_entry(h, &em28xx_devlist, devlist) {
+               if (h->vdev->minor == minor)
+                       dev = h;
+               if (h->vbi_dev->minor == minor) {
+                       dev = h;
+                       *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+               }
+               if (h->radio_dev &&
+                   h->radio_dev->minor == minor) {
+                       dev = h;
+                       *has_radio = 1;
+               }
+       }
+       mutex_unlock(&em28xx_devlist_mutex);
+
+       return dev;
+}
+
+/*
+ * em28xx_realease_resources()
+ * unregisters the v4l2,i2c and usb devices
+ * called when the device gets disconected or at module unload
+*/
+void em28xx_remove_from_devlist(struct em28xx *dev)
+{
+       mutex_lock(&em28xx_devlist_mutex);
+       list_del(&dev->devlist);
+       mutex_unlock(&em28xx_devlist_mutex);
+};
+
+void em28xx_add_into_devlist(struct em28xx *dev)
+{
+       mutex_lock(&em28xx_devlist_mutex);
+       list_add_tail(&dev->devlist, &em28xx_devlist);
+       mutex_unlock(&em28xx_devlist_mutex);
+};
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(em28xx_extension_devlist);
+static DEFINE_MUTEX(em28xx_extension_devlist_lock);
+
+int em28xx_register_extension(struct em28xx_ops *ops)
+{
+       struct em28xx *dev = NULL;
+
+       mutex_lock(&em28xx_devlist_mutex);
+       mutex_lock(&em28xx_extension_devlist_lock);
+       list_add_tail(&ops->next, &em28xx_extension_devlist);
+       list_for_each_entry(dev, &em28xx_devlist, devlist) {
+               if (dev)
+                       ops->init(dev);
+       }
+       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+       mutex_unlock(&em28xx_extension_devlist_lock);
+       mutex_unlock(&em28xx_devlist_mutex);
+       return 0;
+}
+EXPORT_SYMBOL(em28xx_register_extension);
+
+void em28xx_unregister_extension(struct em28xx_ops *ops)
+{
+       struct em28xx *dev = NULL;
+
+       mutex_lock(&em28xx_devlist_mutex);
+       list_for_each_entry(dev, &em28xx_devlist, devlist) {
+               if (dev)
+                       ops->fini(dev);
+       }
+
+       mutex_lock(&em28xx_extension_devlist_lock);
+       printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+       list_del(&ops->next);
+       mutex_unlock(&em28xx_extension_devlist_lock);
+       mutex_unlock(&em28xx_devlist_mutex);
+}
+EXPORT_SYMBOL(em28xx_unregister_extension);
+
+void em28xx_init_extension(struct em28xx *dev)
+{
+       struct em28xx_ops *ops = NULL;
+
+       mutex_lock(&em28xx_extension_devlist_lock);
+       if (!list_empty(&em28xx_extension_devlist)) {
+               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+                       if (ops->init)
+                               ops->init(dev);
+               }
+       }
+       mutex_unlock(&em28xx_extension_devlist_lock);
+}
+
+void em28xx_close_extension(struct em28xx *dev)
+{
+       struct em28xx_ops *ops = NULL;
+
+       mutex_lock(&em28xx_extension_devlist_lock);
+       if (!list_empty(&em28xx_extension_devlist)) {
+               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+                       if (ops->fini)
+                               ops->fini(dev);
+               }
+       }
+       mutex_unlock(&em28xx_extension_devlist_lock);
+}
index c99e2383b7ec994cf92532bd2135812ecdda822d..d38cb21834d9dd790d36bfb7c48e3b691fd5154b 100644 (file)
@@ -161,7 +161,7 @@ static int stop_streaming(struct em28xx_dvb *dvb)
 
        em28xx_uninit_isoc(dev);
 
-       em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+       em28xx_set_mode(dev, EM28XX_SUSPEND);
 
        return 0;
 }
@@ -215,7 +215,7 @@ static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
        if (acquire)
                return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        else
-               return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+               return em28xx_set_mode(dev, EM28XX_SUSPEND);
 }
 
 /* ------------------------------------------------------------------ */
@@ -393,7 +393,7 @@ static int dvb_init(struct em28xx *dev)
        int result = 0;
        struct em28xx_dvb *dvb;
 
-       if (!dev->has_dvb) {
+       if (!dev->board.has_dvb) {
                /* This device does not support the extension */
                return 0;
        }
@@ -409,8 +409,10 @@ static int dvb_init(struct em28xx *dev)
        em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        /* init frontend */
        switch (dev->model) {
+       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
        case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
        case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+       case EM2883_BOARD_KWORLD_HYBRID_A316:
        case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
                dvb->frontend = dvb_attach(lgdt330x_attach,
                                           &em2880_lgdt3303_dev,
@@ -466,12 +468,12 @@ static int dvb_init(struct em28xx *dev)
        if (result < 0)
                goto out_free;
 
-       em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+       em28xx_set_mode(dev, EM28XX_SUSPEND);
        printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
        return 0;
 
 out_free:
-       em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+       em28xx_set_mode(dev, EM28XX_SUSPEND);
        kfree(dvb);
        dev->dvb = NULL;
        return result;
@@ -479,7 +481,7 @@ out_free:
 
 static int dvb_fini(struct em28xx *dev)
 {
-       if (!dev->has_dvb) {
+       if (!dev->board.has_dvb) {
                /* This device does not support the extension */
                return 0;
        }
index 2360c61ddca97e2930a69ab646648da96337d86a..d69f0efcc9aad821101d431b8c5a3afc1177da07 100644 (file)
@@ -250,7 +250,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
                         (msgs[i].flags & I2C_M_RD) ? "read" : "write",
                         i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
                if (!msgs[i].len) { /* no len: check only for device presence */
-                       if (dev->is_em2800)
+                       if (dev->board.is_em2800)
                                rc = em2800_i2c_check_for_device(dev, addr);
                        else
                                rc = em28xx_i2c_check_for_device(dev, addr);
@@ -261,7 +261,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
 
                } else if (msgs[i].flags & I2C_M_RD) {
                        /* read bytes */
-                       if (dev->is_em2800)
+                       if (dev->board.is_em2800)
                                rc = em2800_i2c_recv_bytes(dev, addr,
                                                           msgs[i].buf,
                                                           msgs[i].len);
@@ -279,7 +279,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
                                for (byte = 0; byte < msgs[i].len; byte++)
                                        printk(" %02x", msgs[i].buf[byte]);
                        }
-                       if (dev->is_em2800)
+                       if (dev->board.is_em2800)
                                rc = em2800_i2c_send_bytes(dev, addr,
                                                           msgs[i].buf,
                                                           msgs[i].len);
@@ -332,6 +332,17 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
        struct em28xx_eeprom *em_eeprom = (void *)eedata;
        int i, err, size = len, block;
 
+       if (dev->chip_id == CHIP_ID_EM2874) {
+               /* Empia switched to a 16-bit addressable eeprom in newer
+                  devices.  While we could certainly write a routine to read
+                  the eeprom, there is nothing of use in there that cannot be
+                  accessed through registers, and there is the risk that we
+                  could corrupt the eeprom (since a 16-bit read call is
+                  interpreted as a write call by 8-bit eeproms).
+               */
+               return 0;
+       }
+
        dev->i2c_client.addr = 0xa0 >> 1;
 
        /* Check if board has eeprom */
@@ -377,47 +388,49 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
        if (em_eeprom->id == 0x9567eb1a)
                dev->hash = em28xx_hash_mem(eedata, len, 32);
 
-       printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
-              em_eeprom->id, dev->hash);
-       printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
-              em_eeprom->product_ID);
+       printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
+              dev->name, em_eeprom->id, dev->hash);
+
+       printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
 
        switch (em_eeprom->chip_conf >> 4 & 0x3) {
        case 0:
-               printk(KERN_INFO "No audio on board.\n");
+               printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
                break;
        case 1:
-               printk(KERN_INFO "AC97 audio (5 sample rates)\n");
+               printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
+                                dev->name);
                break;
        case 2:
-               printk(KERN_INFO "I2S audio, sample rate=32k\n");
+               printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", dev->name);
                break;
        case 3:
-               printk(KERN_INFO "I2S audio, 3 sample rates\n");
+               printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", dev->name);
                break;
        }
 
        if (em_eeprom->chip_conf & 1 << 3)
-               printk(KERN_INFO "USB Remote wakeup capable\n");
+               printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
 
        if (em_eeprom->chip_conf & 1 << 2)
-               printk(KERN_INFO "USB Self power capable\n");
+               printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
 
        switch (em_eeprom->chip_conf & 0x3) {
        case 0:
-               printk(KERN_INFO "500mA max power\n");
+               printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
                break;
        case 1:
-               printk(KERN_INFO "400mA max power\n");
+               printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
                break;
        case 2:
-               printk(KERN_INFO "300mA max power\n");
+               printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
                break;
        case 3:
-               printk(KERN_INFO "200mA max power\n");
+               printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
                break;
        }
-       printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+       printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+                               dev->name,
                                em_eeprom->string_idx_table,
                                em_eeprom->string1,
                                em_eeprom->string2,
index eab3d9511af3397c8aaa42be2cd116264d1ca892..42bbaf64aceb568a90edbda272eb4abe6e8ece79 100644 (file)
@@ -38,12 +38,48 @@ static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
-#define dprintk(fmt, arg...) \
+#define i2cdprintk(fmt, arg...) \
        if (ir_debug) { \
                printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
        }
 
-/* ----------------------------------------------------------------------- */
+#define dprintk(fmt, arg...) \
+       if (ir_debug) { \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+       }
+
+/**********************************************************
+ Polling structure used by em28xx IR's
+ **********************************************************/
+
+struct em28xx_ir_poll_result {
+       unsigned int toggle_bit:1;
+       unsigned int read_count:7;
+       u8 rc_address;
+       u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */
+};
+
+struct em28xx_IR {
+       struct em28xx *dev;
+       struct input_dev *input;
+       struct ir_input_state ir;
+       char name[32];
+       char phys[32];
+
+       /* poll external decoder */
+       int polling;
+       struct work_struct work;
+       struct timer_list timer;
+       unsigned int last_toggle:1;
+       unsigned int last_readcount;
+       unsigned int repeat_interval;
+
+       int  (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
+};
+
+/**********************************************************
+ I2C IR based get keycodes - should be used with ir-kbd-i2c
+ **********************************************************/
 
 int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
@@ -51,7 +87,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 
        /* poll IR chip */
        if (1 != i2c_master_recv(&ir->c, &b, 1)) {
-               dprintk("read error\n");
+               i2cdprintk("read error\n");
                return -EIO;
        }
 
@@ -59,7 +95,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
           down, while 0xff indicates that no button is hold
           down. 0xfe sequences are sometimes interrupted by 0xFF */
 
-       dprintk("key %02x\n", b);
+       i2cdprintk("key %02x\n", b);
 
        if (b == 0xff)
                return 0;
@@ -73,7 +109,6 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        return 1;
 }
 
-
 int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
        unsigned char buf[2];
@@ -97,7 +132,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
                 ((buf[0]&0x10)>>3) | /* 0000 0010 */
                 ((buf[0]&0x20)>>5);  /* 0000 0001 */
 
-       dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
+       i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
                        code, buf[0]);
 
        /* return key */
@@ -114,11 +149,11 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
        /* poll IR chip */
 
        if (3 != i2c_master_recv(&ir->c, buf, 3)) {
-               dprintk("read error\n");
+               i2cdprintk("read error\n");
                return -EIO;
        }
 
-       dprintk("key %02x\n", buf[2]&0x3f);
+       i2cdprintk("key %02x\n", buf[2]&0x3f);
        if (buf[0] != 0x00)
                return 0;
 
@@ -128,6 +163,260 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
        return 1;
 }
 
+/**********************************************************
+ Poll based get keycode functions
+ **********************************************************/
+
+/* This is for the em2860/em2880 */
+static int default_polling_getkey(struct em28xx_IR *ir,
+                                 struct em28xx_ir_poll_result *poll_result)
+{
+       struct em28xx *dev = ir->dev;
+       int rc;
+       u8 msg[3] = { 0, 0, 0 };
+
+       /* Read key toggle, brand, and key code
+          on registers 0x45, 0x46 and 0x47
+        */
+       rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
+                                         msg, sizeof(msg));
+       if (rc < 0)
+               return rc;
+
+       /* Infrared toggle (Reg 0x45[7]) */
+       poll_result->toggle_bit = (msg[0] >> 7);
+
+       /* Infrared read count (Reg 0x45[6:0] */
+       poll_result->read_count = (msg[0] & 0x7f);
+
+       /* Remote Control Address (Reg 0x46) */
+       poll_result->rc_address = msg[1];
+
+       /* Remote Control Data (Reg 0x47) */
+       poll_result->rc_data[0] = msg[2];
+
+       return 0;
+}
+
+static int em2874_polling_getkey(struct em28xx_IR *ir,
+                                struct em28xx_ir_poll_result *poll_result)
+{
+       struct em28xx *dev = ir->dev;
+       int rc;
+       u8 msg[5] = { 0, 0, 0, 0, 0 };
+
+       /* Read key toggle, brand, and key code
+          on registers 0x51-55
+        */
+       rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
+                                         msg, sizeof(msg));
+       if (rc < 0)
+               return rc;
+
+       /* Infrared toggle (Reg 0x51[7]) */
+       poll_result->toggle_bit = (msg[0] >> 7);
+
+       /* Infrared read count (Reg 0x51[6:0] */
+       poll_result->read_count = (msg[0] & 0x7f);
+
+       /* Remote Control Address (Reg 0x52) */
+       poll_result->rc_address = msg[1];
+
+       /* Remote Control Data (Reg 0x53-55) */
+       poll_result->rc_data[0] = msg[2];
+       poll_result->rc_data[1] = msg[3];
+       poll_result->rc_data[2] = msg[4];
+
+       return 0;
+}
+
+/**********************************************************
+ Polling code for em28xx
+ **********************************************************/
+
+static void em28xx_ir_handle_key(struct em28xx_IR *ir)
+{
+       int result;
+       int do_sendkey = 0;
+       struct em28xx_ir_poll_result poll_result;
+
+       /* read the registers containing the IR status */
+       result = ir->get_key(ir, &poll_result);
+       if (result < 0) {
+               dprintk("ir->get_key() failed %d\n", result);
+               return;
+       }
+
+       dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
+               poll_result.toggle_bit, poll_result.read_count,
+               ir->last_readcount, poll_result.rc_data[0]);
+
+       if (ir->dev->chip_id == CHIP_ID_EM2874) {
+               /* The em2874 clears the readcount field every time the
+                  register is read.  The em2860/2880 datasheet says that it
+                  is supposed to clear the readcount, but it doesn't.  So with
+                  the em2874, we are looking for a non-zero read count as
+                  opposed to a readcount that is incrementing */
+               ir->last_readcount = 0;
+       }
+
+       if (poll_result.read_count == 0) {
+               /* The button has not been pressed since the last read */
+       } else if (ir->last_toggle != poll_result.toggle_bit) {
+               /* A button has been pressed */
+               dprintk("button has been pressed\n");
+               ir->last_toggle = poll_result.toggle_bit;
+               ir->repeat_interval = 0;
+               do_sendkey = 1;
+       } else if (poll_result.toggle_bit == ir->last_toggle &&
+                  poll_result.read_count > 0 &&
+                  poll_result.read_count != ir->last_readcount) {
+               /* The button is still being held down */
+               dprintk("button being held down\n");
+
+               /* Debouncer for first keypress */
+               if (ir->repeat_interval++ > 9) {
+                       /* Start repeating after 1 second */
+                       do_sendkey = 1;
+               }
+       }
+
+       if (do_sendkey) {
+               dprintk("sending keypress\n");
+               ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0],
+                                poll_result.rc_data[0]);
+               ir_input_nokey(ir->input, &ir->ir);
+       }
+
+       ir->last_readcount = poll_result.read_count;
+       return;
+}
+
+static void ir_timer(unsigned long data)
+{
+       struct em28xx_IR *ir = (struct em28xx_IR *)data;
+
+       schedule_work(&ir->work);
+}
+
+static void em28xx_ir_work(struct work_struct *work)
+{
+       struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work);
+
+       em28xx_ir_handle_key(ir);
+       mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+void em28xx_ir_start(struct em28xx_IR *ir)
+{
+       setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
+       INIT_WORK(&ir->work, em28xx_ir_work);
+       schedule_work(&ir->work);
+}
+
+static void em28xx_ir_stop(struct em28xx_IR *ir)
+{
+       del_timer_sync(&ir->timer);
+       flush_scheduled_work();
+}
+
+int em28xx_ir_init(struct em28xx *dev)
+{
+       struct em28xx_IR *ir;
+       struct input_dev *input_dev;
+       u8 ir_config;
+       int err = -ENOMEM;
+
+       if (dev->board.ir_codes == NULL) {
+               /* No remote control support */
+               return 0;
+       }
+
+       ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ir || !input_dev)
+               goto err_out_free;
+
+       ir->input = input_dev;
+
+       /* Setup the proper handler based on the chip */
+       switch (dev->chip_id) {
+       case CHIP_ID_EM2860:
+       case CHIP_ID_EM2883:
+               ir->get_key = default_polling_getkey;
+               break;
+       case CHIP_ID_EM2874:
+               ir->get_key = em2874_polling_getkey;
+               /* For now we only support RC5, so enable it */
+               ir_config = EM2874_IR_RC5;
+               em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
+               break;
+       default:
+               printk("Unrecognized em28xx chip id: IR not supported\n");
+               goto err_out_free;
+       }
+
+       /* This is how often we ask the chip for IR information */
+       ir->polling = 100; /* ms */
+
+       /* init input device */
+       snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)",
+                                               dev->name);
+
+       usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+       strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+       ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->board.ir_codes);
+       input_dev->name = ir->name;
+       input_dev->phys = ir->phys;
+       input_dev->id.bustype = BUS_USB;
+       input_dev->id.version = 1;
+       input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+       input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+       input_dev->dev.parent = &dev->udev->dev;
+       /* record handles to ourself */
+       ir->dev = dev;
+       dev->ir = ir;
+
+       em28xx_ir_start(ir);
+
+       /* all done */
+       err = input_register_device(ir->input);
+       if (err)
+               goto err_out_stop;
+
+       return 0;
+ err_out_stop:
+       em28xx_ir_stop(ir);
+       dev->ir = NULL;
+ err_out_free:
+       input_free_device(input_dev);
+       kfree(ir);
+       return err;
+}
+
+int em28xx_ir_fini(struct em28xx *dev)
+{
+       struct em28xx_IR *ir = dev->ir;
+
+       /* skip detach on non attached boards */
+       if (!ir)
+               return 0;
+
+       em28xx_ir_stop(ir);
+       input_unregister_device(ir->input);
+       kfree(ir);
+
+       /* done */
+       dev->ir = NULL;
+       return 0;
+}
+
+/**********************************************************
+ Handle Webcam snapshot button
+ **********************************************************/
+
 static void em28xx_query_sbutton(struct work_struct *work)
 {
        /* Poll the register and see if the button is depressed */
@@ -210,9 +499,3 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)
        }
        return;
 }
-
-/* ----------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index fac1ab23f6216dd74d4fcbc0a65fd26868d0fcd6..65dcb91bdcc2046baa7d3070224e5c71245a5f04 100644 (file)
 
 /* em28xx registers */
 
+#define EM28XX_R00_CHIPCFG     0x00
+
+/* em28xx Chip Configuration 0x00 */
+#define EM28XX_CHIPCFG_VENDOR_AUDIO            0x80
+#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE      0x40
+#define EM28XX_CHIPCFG_I2S_5_SAMPRATES         0x30
+#define EM28XX_CHIPCFG_I2S_3_SAMPRATES         0x20
+#define EM28XX_CHIPCFG_AC97                    0x10
+#define EM28XX_CHIPCFG_AUDIOMASK               0x30
+
        /* GPIO/GPO registers */
 #define EM2880_R04_GPO 0x04    /* em2880-em2883 only */
 #define EM28XX_R08_GPIO        0x08    /* em2820 or upper */
 
 #define EM28XX_R06_I2C_CLK     0x06
+
+/* em28xx I2C Clock Register (0x06) */
+#define EM28XX_I2C_CLK_ACK_LAST_READ   0x80
+#define EM28XX_I2C_CLK_WAIT_ENABLE     0x40
+#define EM28XX_I2C_EEPROM_ON_BOARD     0x08
+#define EM28XX_I2C_EEPROM_KEY_VALID    0x04
+#define EM2874_I2C_SECONDARY_BUS_SELECT        0x04 /* em2874 has two i2c busses */
+#define EM28XX_I2C_FREQ_1_5_MHZ                0x03 /* bus frequency (bits [1-0]) */
+#define EM28XX_I2C_FREQ_25_KHZ         0x02
+#define EM28XX_I2C_FREQ_400_KHZ                0x01
+#define EM28XX_I2C_FREQ_100_KHZ                0x00
+
+
 #define EM28XX_R0A_CHIPID      0x0a
 #define EM28XX_R0C_USBSUSP     0x0c    /* */
 
 #define EM28XX_R0E_AUDIOSRC    0x0e
 #define EM28XX_R0F_XCLK        0x0f
 
+/* em28xx XCLK Register (0x0f) */
+#define EM28XX_XCLK_AUDIO_UNMUTE       0x80 /* otherwise audio muted */
+#define EM28XX_XCLK_I2S_MSB_TIMING     0x40 /* otherwise standard timing */
+#define EM28XX_XCLK_IR_RC5_MODE                0x20 /* otherwise NEC mode */
+#define EM28XX_XCLK_IR_NEC_CHK_PARITY  0x10
+#define EM28XX_XCLK_FREQUENCY_30MHZ    0x00 /* Freq. select (bits [3-0]) */
+#define EM28XX_XCLK_FREQUENCY_15MHZ    0x01
+#define EM28XX_XCLK_FREQUENCY_10MHZ    0x02
+#define EM28XX_XCLK_FREQUENCY_7_5MHZ   0x03
+#define EM28XX_XCLK_FREQUENCY_6MHZ     0x04
+#define EM28XX_XCLK_FREQUENCY_5MHZ     0x05
+#define EM28XX_XCLK_FREQUENCY_4_3MHZ   0x06
+#define EM28XX_XCLK_FREQUENCY_12MHZ    0x07
+#define EM28XX_XCLK_FREQUENCY_20MHZ    0x08
+#define EM28XX_XCLK_FREQUENCY_20MHZ_2  0x09
+#define EM28XX_XCLK_FREQUENCY_48MHZ    0x0a
+#define EM28XX_XCLK_FREQUENCY_24MHZ    0x0b
+
 #define EM28XX_R10_VINMODE     0x10
 #define EM28XX_R11_VINCTRL     0x11
 #define EM28XX_R12_VINENABLE   0x12    /* */
 #define EM28XX_R26_COMPR       0x26
 #define EM28XX_R27_OUTFMT      0x27
 
+/* em28xx Output Format Register (0x27) */
+#define EM28XX_OUTFMT_RGB_8_RGRG       0x00
+#define EM28XX_OUTFMT_RGB_8_GRGR       0x01
+#define EM28XX_OUTFMT_RGB_8_GBGB       0x02
+#define EM28XX_OUTFMT_RGB_8_BGBG       0x03
+#define EM28XX_OUTFMT_RGB_16_656       0x04
+#define EM28XX_OUTFMT_RGB_8_BAYER      0x08 /* Pattern in Reg 0x10[1-0] */
+#define EM28XX_OUTFMT_YUV211           0x10
+#define EM28XX_OUTFMT_YUV422_Y0UY1V    0x14
+#define EM28XX_OUTFMT_YUV422_Y1UY0V    0x15
+#define EM28XX_OUTFMT_YUV411           0x18
+
+
 #define EM28XX_R28_XMIN        0x28
 #define EM28XX_R29_XMAX        0x29
 #define EM28XX_R2A_YMIN        0x2a
 #define EM28XX_R42_AC97ADDR    0x42
 #define EM28XX_R43_AC97BUSY    0x43
 
-/* em202 registers */
-#define EM28XX_R02_MASTER_AC97 0x02
-#define EM28XX_R10_LINE_IN_AC97    0x10
-#define EM28XX_R14_VIDEO_AC97  0x14
+#define EM28XX_R45_IR          0x45
+       /* 0x45  bit 7    - parity bit
+                bits 6-0 - count
+          0x46  IR brand
+          0x47  IR data
+        */
+
+/* em2874 registers */
+#define EM2874_R50_IR_CONFIG    0x50
+#define EM2874_R51_IR           0x51
+#define EM2874_R5F_TS_ENABLE    0x5f
+#define EM2874_R80_GPIO         0x80
+
+/* em2874 IR config register (0x50) */
+#define EM2874_IR_NEC           0x00
+#define EM2874_IR_RC5           0x04
+#define EM2874_IR_RC5_MODE_0    0x08
+#define EM2874_IR_RC5_MODE_6A   0x0b
+
+/* em2874 Transport Stream Enable Register (0x5f) */
+#define EM2874_TS1_CAPTURE_ENABLE (1 << 0)
+#define EM2874_TS1_FILTER_ENABLE  (1 << 1)
+#define EM2874_TS1_NULL_DISCARD   (1 << 2)
+#define EM2874_TS2_CAPTURE_ENABLE (1 << 4)
+#define EM2874_TS2_FILTER_ENABLE  (1 << 5)
+#define EM2874_TS2_NULL_DISCARD   (1 << 6)
 
 /* register settings */
 #define EM2800_AUDIO_SRC_TUNER  0x0d
 
 /* FIXME: Need to be populated with the other chip ID's */
 enum em28xx_chip_id {
+       CHIP_ID_EM2820 = 18,
+       CHIP_ID_EM2840 = 20,
+       CHIP_ID_EM2750 = 33,
        CHIP_ID_EM2860 = 34,
+       CHIP_ID_EM2870 = 35,
        CHIP_ID_EM2883 = 36,
+       CHIP_ID_EM2874 = 65,
 };
+
+/*
+ * Registers used by em202 and other AC97 chips
+ */
+
+/* Standard AC97 registers */
+#define AC97_RESET               0x00
+
+       /* Output volumes */
+#define AC97_MASTER_VOL          0x02
+#define AC97_LINE_LEVEL_VOL      0x04  /* Some devices use for headphones */
+#define AC97_MASTER_MONO_VOL     0x06
+
+       /* Input volumes */
+#define AC97_PC_BEEP_VOL         0x0a
+#define AC97_PHONE_VOL           0x0c
+#define AC97_MIC_VOL             0x0e
+#define AC97_LINEIN_VOL          0x10
+#define AC97_CD_VOL              0x12
+#define AC97_VIDEO_VOL           0x14
+#define AC97_AUX_VOL             0x16
+#define AC97_PCM_OUT_VOL         0x18
+
+       /* capture registers */
+#define AC97_RECORD_SELECT       0x1a
+#define AC97_RECORD_GAIN         0x1c
+
+       /* control registers */
+#define AC97_GENERAL_PURPOSE     0x20
+#define AC97_3D_CTRL             0x22
+#define AC97_AUD_INT_AND_PAG     0x24
+#define AC97_POWER_DOWN_CTRL     0x26
+#define AC97_EXT_AUD_ID          0x28
+#define AC97_EXT_AUD_CTRL        0x2a
+
+/* Supported rate varies for each AC97 device
+   if write an unsupported value, it will return the closest one
+ */
+#define AC97_PCM_OUT_FRONT_SRATE 0x2c
+#define AC97_PCM_OUT_SURR_SRATE  0x2e
+#define AC97_PCM_OUT_LFE_SRATE   0x30
+#define AC97_PCM_IN_SRATE        0x32
+
+       /* For devices with more than 2 channels, extra output volumes */
+#define AC97_LFE_MASTER_VOL      0x36
+#define AC97_SURR_MASTER_VOL     0x38
+
+       /* Digital SPDIF output control */
+#define AC97_SPDIF_OUT_CTRL      0x3a
+
+       /* Vendor ID identifier */
+#define AC97_VENDOR_ID1          0x7c
+#define AC97_VENDOR_ID2          0x7e
+
+/* EMP202 vendor registers */
+#define EM202_EXT_MODEM_CTRL     0x3e
+#define EM202_GPIO_CONF          0x4c
+#define EM202_GPIO_POLARITY      0x4e
+#define EM202_GPIO_STICKY        0x50
+#define EM202_GPIO_MASK          0x52
+#define EM202_GPIO_STATUS        0x54
+#define EM202_SPDIF_OUT_SEL      0x6a
+#define EM202_ANTIPOP            0x72
+#define EM202_EAPD_GPIO_ACCESS   0x74
index 4ea1f1e048979e51859652d93e24846a7f39fd3e..53527536481e6946b1432b2b08b4590ac0620596 100644 (file)
@@ -39,6 +39,7 @@
 #include "em28xx.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
 
@@ -47,9 +48,8 @@
                      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
                      "Sascha Sommer <saschasommer@freenet.de>"
 
-#define DRIVER_NAME         "em28xx"
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 1)
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
@@ -72,19 +72,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-static LIST_HEAD(em28xx_devlist);
-static DEFINE_MUTEX(em28xx_devlist_mutex);
-
-static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 
-module_param_array(card,  int, NULL, 0444);
 module_param_array(video_nr, int, NULL, 0444);
 module_param_array(vbi_nr, int, NULL, 0444);
 module_param_array(radio_nr, int, NULL, 0444);
-MODULE_PARM_DESC(card,     "card type");
 MODULE_PARM_DESC(video_nr, "video device numbers");
 MODULE_PARM_DESC(vbi_nr,   "vbi device numbers");
 MODULE_PARM_DESC(radio_nr, "radio device numbers");
@@ -93,8 +87,15 @@ static unsigned int video_debug;
 module_param(video_debug, int, 0644);
 MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
 
-/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
-static unsigned long em28xx_devused;
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+       {
+               .name     = "16bpp YUY2, 4:2:2, packed",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .reg      = EM28XX_OUTFMT_YUV422_Y0UY1V,
+       },
+};
 
 /* supported controls */
 /* Common to all boards */
@@ -120,8 +121,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
        }
 };
 
-static struct usb_driver em28xx_usb_driver;
-
 /* ------------------------------------------------------------------
        DMA and thread functions
    ------------------------------------------------------------------*/
@@ -386,16 +385,18 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        struct em28xx        *dev = fh->dev;
        struct v4l2_frequency f;
 
-       *size = 16 * fh->dev->width * fh->dev->height >> 3;
+       *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+
        if (0 == *count)
                *count = EM28XX_DEF_BUF;
 
        if (*count < EM28XX_MIN_BUF)
                *count = EM28XX_MIN_BUF;
 
-       /* Ask tuner to go to analog mode */
+       /* Ask tuner to go to analog or radio mode */
        memset(&f, 0, sizeof(f));
        f.frequency = dev->ctl_freq;
+       f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
 
        em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
 
@@ -438,9 +439,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        struct em28xx        *dev = fh->dev;
        int                  rc = 0, urb_init = 0;
 
-       /* FIXME: It assumes depth = 16 */
-       /* The only currently supported format is 16 bits/pixel */
-       buf->vb.size = 16 * dev->width * dev->height >> 3;
+       buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
 
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
                return -EINVAL;
@@ -508,56 +507,6 @@ static struct videobuf_queue_ops em28xx_video_qops = {
 
 /*********************  v4l2 interface  **************************************/
 
-/*
- * em28xx_config()
- * inits registers with sane defaults
- */
-static int em28xx_config(struct em28xx *dev)
-{
-       int retval;
-
-       /* Sets I2C speed to 100 KHz */
-       if (!dev->is_em2800) {
-               retval = em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1);
-               if (retval < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req failed! retval [%d]\n",
-                               __func__, retval);
-                       return retval;
-               }
-       }
-
-       /* enable vbi capturing */
-
-/*     em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
-/*     em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
-       em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
-
-       dev->mute = 1;          /* maybe not the right place... */
-       dev->volume = 0x1f;
-
-       em28xx_outfmt_set_yuv422(dev);
-       em28xx_colorlevels_set_default(dev);
-       em28xx_compression_disable(dev);
-
-       return 0;
-}
-
-/*
- * em28xx_config_i2c()
- * configure i2c attached devices
- */
-static void em28xx_config_i2c(struct em28xx *dev)
-{
-       struct v4l2_routing route;
-       int zero = 0;
-
-       route.input = INPUT(dev->ctl_input)->vmux;
-       route.output = 0;
-       em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, &zero);
-       em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-       em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-}
-
 static void video_mux(struct em28xx *dev, int index)
 {
        struct v4l2_routing route;
@@ -566,10 +515,14 @@ static void video_mux(struct em28xx *dev, int index)
        route.output = 0;
        dev->ctl_input = index;
        dev->ctl_ainput = INPUT(index)->amux;
+       dev->ctl_aoutput = INPUT(index)->aout;
+
+       if (!dev->ctl_aoutput)
+               dev->ctl_aoutput = EM28XX_AOUT_MASTER;
 
        em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
-       if (dev->has_msp34xx) {
+       if (dev->board.has_msp34xx) {
                if (dev->i2s_speed) {
                        em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
                                &dev->i2s_speed);
@@ -595,12 +548,10 @@ static int res_get(struct em28xx_fh *fh)
                return rc;
 
        if (dev->stream_on)
-               return -EINVAL;
+               return -EBUSY;
 
-       mutex_lock(&dev->lock);
        dev->stream_on = 1;
        fh->stream_on  = 1;
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -613,10 +564,8 @@ static void res_free(struct em28xx_fh *fh)
 {
        struct em28xx    *dev = fh->dev;
 
-       mutex_lock(&dev->lock);
        fh->stream_on = 0;
        dev->stream_on = 0;
-       mutex_unlock(&dev->lock);
 }
 
 /*
@@ -703,8 +652,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = dev->width;
        f->fmt.pix.height = dev->height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       f->fmt.pix.bytesperline = dev->width * 2;
+       f->fmt.pix.pixelformat = dev->format->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
        f->fmt.pix.sizeimage = f->fmt.pix.bytesperline  * dev->height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
@@ -716,6 +665,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(format); i++)
+               if (format[i].fourcc == fourcc)
+                       return &format[i];
+
+       return NULL;
+}
+
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
@@ -726,24 +686,30 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        unsigned int          maxw   = norm_maxw(dev);
        unsigned int          maxh   = norm_maxh(dev);
        unsigned int          hscale, vscale;
+       struct em28xx_fmt     *fmt;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!fmt) {
+               em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+                               f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
 
        /* width must even because of the YUYV format
           height must be even because of interlacing */
        height &= 0xfffe;
-       width &= 0xfffe;
+       width  &= 0xfffe;
 
-       if (height < 32)
+       if (unlikely(height < 32))
                height = 32;
-       if (height > maxh)
+       if (unlikely(height > maxh))
                height = maxh;
-       if (width < 48)
+       if (unlikely(width < 48))
                width = 48;
-       if (width > maxw)
+       if (unlikely(width > maxw))
                width = maxw;
 
-       mutex_lock(&dev->lock);
-
-       if (dev->is_em2800) {
+       if (dev->board.is_em2800) {
                /* the em2800 can only scale down to 50% */
                if (height % (maxh / 2))
                        height = maxh;
@@ -766,13 +732,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = width;
        f->fmt.pix.height = height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       f->fmt.pix.bytesperline = width * 2;
-       f->fmt.pix.sizeimage = width * 2 * height;
+       f->fmt.pix.pixelformat = fmt->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+       f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
        f->fmt.pix.field = V4L2_FIELD_INTERLACED;
 
-       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -782,14 +747,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        int                   rc;
+       struct em28xx_fmt     *fmt;
 
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
+       mutex_lock(&dev->lock);
+
        vidioc_try_fmt_vid_cap(file, priv, f);
 
-       mutex_lock(&dev->lock);
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!fmt) {
+               rc = -EINVAL;
+               goto out;
+       }
 
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                em28xx_errdev("%s queue busy\n", __func__);
@@ -806,6 +778,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        /* set new image size */
        dev->width = f->fmt.pix.width;
        dev->height = f->fmt.pix.height;
+       dev->format = fmt;
        get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
        em28xx_set_alternate(dev);
@@ -831,15 +804,12 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
 
        mutex_lock(&dev->lock);
        dev->norm = *norm;
-       mutex_unlock(&dev->lock);
 
        /* Adjusts width/height, if needed */
        f.fmt.pix.width = dev->width;
        f.fmt.pix.height = dev->height;
        vidioc_try_fmt_vid_cap(file, priv, &f);
 
-       mutex_lock(&dev->lock);
-
        /* set new image size */
        dev->width = f.fmt.pix.width;
        dev->height = f.fmt.pix.height;
@@ -928,20 +898,38 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
        struct em28xx_fh   *fh    = priv;
        struct em28xx      *dev   = fh->dev;
-       unsigned int        index = a->index;
-
-       if (a->index > 1)
-               return -EINVAL;
-
-       index = dev->ctl_ainput;
 
-       if (index == 0)
+       switch (a->index) {
+       case EM28XX_AMUX_VIDEO:
                strcpy(a->name, "Television");
-       else
+               break;
+       case EM28XX_AMUX_LINE_IN:
                strcpy(a->name, "Line In");
+               break;
+       case EM28XX_AMUX_VIDEO2:
+               strcpy(a->name, "Television alt");
+               break;
+       case EM28XX_AMUX_PHONE:
+               strcpy(a->name, "Phone");
+               break;
+       case EM28XX_AMUX_MIC:
+               strcpy(a->name, "Mic");
+               break;
+       case EM28XX_AMUX_CD:
+               strcpy(a->name, "CD");
+               break;
+       case EM28XX_AMUX_AUX:
+               strcpy(a->name, "Aux");
+               break;
+       case EM28XX_AMUX_PCM_OUT:
+               strcpy(a->name, "PCM");
+               break;
+       default:
+               return -EINVAL;
+       }
 
+       a->index = dev->ctl_ainput;
        a->capability = V4L2_AUDCAP_STEREO;
-       a->index = index;
 
        return 0;
 }
@@ -951,9 +939,15 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
        struct em28xx_fh   *fh  = priv;
        struct em28xx      *dev = fh->dev;
 
-       if (a->index != dev->ctl_ainput)
-               return -EINVAL;
+       mutex_lock(&dev->lock);
+
+       dev->ctl_ainput = INPUT(a->index)->amux;
+       dev->ctl_aoutput = INPUT(a->index)->aout;
 
+       if (!dev->ctl_aoutput)
+               dev->ctl_aoutput = EM28XX_AOUT_MASTER;
+
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -974,7 +968,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 
        qc->id = id;
 
-       if (!dev->has_msp34xx) {
+       if (!dev->board.has_msp34xx) {
                for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
                        if (qc->id && qc->id == em28xx_qctrl[i].id) {
                                memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc));
@@ -1002,17 +996,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
-       mutex_lock(&dev->lock);
+       rc = 0;
 
-       if (!dev->has_msp34xx)
-               rc = em28xx_get_ctrl(dev, ctrl);
-       else
-               rc = -EINVAL;
+       mutex_lock(&dev->lock);
 
-       if (rc == -EINVAL) {
+       if (dev->board.has_msp34xx)
                em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
-               rc = 0;
-       }
+       else
+               rc = em28xx_get_ctrl(dev, ctrl);
 
        mutex_unlock(&dev->lock);
        return rc;
@@ -1032,7 +1023,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
        mutex_lock(&dev->lock);
 
-       if (dev->has_msp34xx)
+       if (dev->board.has_msp34xx)
                em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
        else {
                rc = 1;
@@ -1112,8 +1103,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
 
+       mutex_lock(&dev->lock);
        f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
        f->frequency = dev->ctl_freq;
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1143,6 +1136,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
 
        mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1159,6 +1153,21 @@ static int em28xx_reg_len(int reg)
        }
 }
 
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+              struct v4l2_chip_ident *chip)
+{
+       struct em28xx_fh      *fh  = priv;
+       struct em28xx         *dev = fh->dev;
+
+       chip->ident = V4L2_IDENT_NONE;
+       chip->revision = 0;
+
+       em28xx_i2c_call_clients(dev, VIDIOC_G_CHIP_IDENT, chip);
+
+       return 0;
+}
+
+
 static int vidioc_g_register(struct file *file, void *priv,
                             struct v4l2_register *reg)
 {
@@ -1166,19 +1175,43 @@ static int vidioc_g_register(struct file *file, void *priv,
        struct em28xx         *dev = fh->dev;
        int ret;
 
-       if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+       switch (reg->match_type) {
+       case V4L2_CHIP_MATCH_AC97:
+               mutex_lock(&dev->lock);
+               ret = em28xx_read_ac97(dev, reg->reg);
+               mutex_unlock(&dev->lock);
+               if (ret < 0)
+                       return ret;
+
+               reg->val = ret;
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               em28xx_i2c_call_clients(dev, VIDIOC_DBG_G_REGISTER, reg);
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /* Not supported yet */
                return -EINVAL;
+       default:
+               if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+                       return -EINVAL;
+       }
 
+       /* Match host */
        if (em28xx_reg_len(reg->reg) == 1) {
+               mutex_lock(&dev->lock);
                ret = em28xx_read_reg(dev, reg->reg);
+               mutex_unlock(&dev->lock);
+
                if (ret < 0)
                        return ret;
 
                reg->val = ret;
        } else {
                __le64 val = 0;
+               mutex_lock(&dev->lock);
                ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
                                                   reg->reg, (char *)&val, 2);
+               mutex_unlock(&dev->lock);
                if (ret < 0)
                        return ret;
 
@@ -1194,11 +1227,35 @@ static int vidioc_s_register(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        __le64 buf;
+       int    rc;
 
+       switch (reg->match_type) {
+       case V4L2_CHIP_MATCH_AC97:
+               mutex_lock(&dev->lock);
+               rc = em28xx_write_ac97(dev, reg->reg, reg->val);
+               mutex_unlock(&dev->lock);
+
+               return rc;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               em28xx_i2c_call_clients(dev, VIDIOC_DBG_S_REGISTER, reg);
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /* Not supported yet */
+               return -EINVAL;
+       default:
+               if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+                       return -EINVAL;
+       }
+
+       /* Match host */
        buf = cpu_to_le64(reg->val);
 
-       return em28xx_write_regs(dev, reg->reg, (char *)&buf,
-                                em28xx_reg_len(reg->reg));
+       mutex_lock(&dev->lock);
+       rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
+                              em28xx_reg_len(reg->reg));
+       mutex_unlock(&dev->lock);
+
+       return rc;
 }
 #endif
 
@@ -1235,10 +1292,15 @@ static int vidioc_streamon(struct file *file, void *priv,
                return rc;
 
 
-       if (unlikely(res_get(fh) < 0))
-               return -EBUSY;
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+
+       if (likely(rc >= 0))
+               rc = videobuf_streamon(&fh->vb_vidq);
 
-       return (videobuf_streamon(&fh->vb_vidq));
+       mutex_unlock(&dev->lock);
+
+       return rc;
 }
 
 static int vidioc_streamoff(struct file *file, void *priv,
@@ -1257,9 +1319,13 @@ static int vidioc_streamoff(struct file *file, void *priv,
        if (type != fh->type)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
+
        videobuf_streamoff(&fh->vb_vidq);
        res_free(fh);
 
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1271,7 +1337,7 @@ static int vidioc_querycap(struct file *file, void  *priv,
 
        strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
 
@@ -1288,15 +1354,13 @@ static int vidioc_querycap(struct file *file, void  *priv,
 }
 
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *fmtd)
+                                       struct v4l2_fmtdesc *f)
 {
-       if (fmtd->index != 0)
+       if (unlikely(f->index >= ARRAY_SIZE(format)))
                return -EINVAL;
 
-       fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       strcpy(fmtd->description, "Packed YUY2");
-       fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-       memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+       strlcpy(f->description, format[f->index].name, sizeof(f->description));
+       f->pixelformat = format[f->index].fourcc;
 
        return 0;
 }
@@ -1424,7 +1488,7 @@ static int radio_querycap(struct file *file, void  *priv,
 
        strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
        strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
-       strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));
+       strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
 
        cap->version = EM28XX_VERSION_CODE;
        cap->capabilities = V4L2_CAP_TUNER;
@@ -1442,7 +1506,10 @@ static int radio_g_tuner(struct file *file, void *priv,
        strcpy(t->name, "Radio");
        t->type = V4L2_TUNER_RADIO;
 
+       mutex_lock(&dev->lock);
        em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
@@ -1474,7 +1541,9 @@ static int radio_s_tuner(struct file *file, void *priv,
        if (0 != t->index)
                return -EINVAL;
 
+       mutex_lock(&dev->lock);
        em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1516,28 +1585,13 @@ static int radio_queryctrl(struct file *file, void *priv,
 static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 {
        int minor = iminor(inode);
-       int errCode = 0, radio = 0;
-       struct em28xx *h, *dev = NULL;
+       int errCode = 0, radio;
+       struct em28xx *dev;
+       enum v4l2_buf_type fh_type;
        struct em28xx_fh *fh;
-       enum v4l2_buf_type fh_type = 0;
 
-       mutex_lock(&em28xx_devlist_mutex);
-       list_for_each_entry(h, &em28xx_devlist, devlist) {
-               if (h->vdev->minor == minor) {
-                       dev  = h;
-                       fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               }
-               if (h->vbi_dev->minor == minor) {
-                       dev  = h;
-                       fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
-               }
-               if (h->radio_dev &&
-                   h->radio_dev->minor == minor) {
-                       radio = 1;
-                       dev   = h;
-               }
-       }
-       mutex_unlock(&em28xx_devlist_mutex);
+       dev = em28xx_get_device(inode, &fh_type, &radio);
+
        if (NULL == dev)
                return -ENODEV;
 
@@ -1571,7 +1625,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
                /* Needed, since GPIO might have disabled power of
                   some i2c device
                 */
-               em28xx_config_i2c(dev);
+               em28xx_wake_i2c(dev);
 
        }
        if (fh->radio) {
@@ -1595,16 +1649,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconected or at module unload
 */
-static void em28xx_release_resources(struct em28xx *dev)
+void em28xx_release_analog_resources(struct em28xx *dev)
 {
 
        /*FIXME: I2C IR should be disconnected */
 
-       em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
-                               dev->vdev->num, dev->vbi_dev->num);
-       list_del(&dev->devlist);
-       if (dev->sbutton_input_dev)
-               em28xx_deregister_snapshot_button(dev);
        if (dev->radio_dev) {
                if (-1 != dev->radio_dev->minor)
                        video_unregister_device(dev->radio_dev);
@@ -1613,6 +1662,8 @@ static void em28xx_release_resources(struct em28xx *dev)
                dev->radio_dev = NULL;
        }
        if (dev->vbi_dev) {
+               em28xx_info("V4L2 device /dev/vbi%d deregistered\n",
+                           dev->vbi_dev->num);
                if (-1 != dev->vbi_dev->minor)
                        video_unregister_device(dev->vbi_dev);
                else
@@ -1620,17 +1671,14 @@ static void em28xx_release_resources(struct em28xx *dev)
                dev->vbi_dev = NULL;
        }
        if (dev->vdev) {
+               em28xx_info("V4L2 device /dev/video%d deregistered\n",
+                           dev->vdev->num);
                if (-1 != dev->vdev->minor)
                        video_unregister_device(dev->vdev);
                else
                        video_device_release(dev->vdev);
                dev->vdev = NULL;
        }
-       em28xx_i2c_unregister(dev);
-       usb_put_dev(dev->udev);
-
-       /* Mark device as unused */
-       em28xx_devused &= ~(1<<dev->devno);
 }
 
 /*
@@ -1647,11 +1695,10 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
        em28xx_videodbg("users=%d\n", dev->users);
 
 
+       mutex_lock(&dev->lock);
        if (res_check(fh))
                res_free(fh);
 
-       mutex_lock(&dev->lock);
-
        if (dev->users == 1) {
                videobuf_stop(&fh->vb_vidq);
                videobuf_mmap_free(&fh->vb_vidq);
@@ -1665,9 +1712,12 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
                        return 0;
                }
 
+               /* Save some power by putting tuner to sleep */
+               em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+
                /* do this before setting alternate! */
                em28xx_uninit_isoc(dev);
-               em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+               em28xx_set_mode(dev, EM28XX_SUSPEND);
 
                /* set alternate 0 */
                dev->alt = 0;
@@ -1706,8 +1756,12 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
         */
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               if (unlikely(res_get(fh)))
-                       return -EBUSY;
+               mutex_lock(&dev->lock);
+               rc = res_get(fh);
+               mutex_unlock(&dev->lock);
+
+               if (unlikely(rc < 0))
+                       return rc;
 
                return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
                                        filp->f_flags & O_NONBLOCK);
@@ -1729,7 +1783,11 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
        if (rc < 0)
                return rc;
 
-       if (unlikely(res_get(fh) < 0))
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+       mutex_unlock(&dev->lock);
+
+       if (unlikely(rc < 0))
                return POLLERR;
 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
@@ -1747,13 +1805,17 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        struct em28xx    *dev   = fh->dev;
        int              rc;
 
-       if (unlikely(res_get(fh) < 0))
-               return -EBUSY;
-
        rc = check_dev(dev);
        if (rc < 0)
                return rc;
 
+       mutex_lock(&dev->lock);
+       rc = res_get(fh);
+       mutex_unlock(&dev->lock);
+
+       if (unlikely(rc < 0))
+               return rc;
+
        rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
        em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
@@ -1810,6 +1872,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        .vidioc_g_register          = vidioc_g_register,
        .vidioc_s_register          = vidioc_s_register,
+       .vidioc_g_chip_ident        = vidioc_g_chip_ident,
 #endif
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf                = vidiocgmbuf,
@@ -1865,44 +1928,6 @@ static struct video_device em28xx_radio_template = {
 /******************************** usb interface ******************************/
 
 
-static LIST_HEAD(em28xx_extension_devlist);
-static DEFINE_MUTEX(em28xx_extension_devlist_lock);
-
-int em28xx_register_extension(struct em28xx_ops *ops)
-{
-       struct em28xx *dev = NULL;
-
-       mutex_lock(&em28xx_devlist_mutex);
-       mutex_lock(&em28xx_extension_devlist_lock);
-       list_add_tail(&ops->next, &em28xx_extension_devlist);
-       list_for_each_entry(dev, &em28xx_devlist, devlist) {
-               if (dev)
-                       ops->init(dev);
-       }
-       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
-       mutex_unlock(&em28xx_extension_devlist_lock);
-       mutex_unlock(&em28xx_devlist_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(em28xx_register_extension);
-
-void em28xx_unregister_extension(struct em28xx_ops *ops)
-{
-       struct em28xx *dev = NULL;
-
-       mutex_lock(&em28xx_devlist_mutex);
-       list_for_each_entry(dev, &em28xx_devlist, devlist) {
-               if (dev)
-                       ops->fini(dev);
-       }
-
-       mutex_lock(&em28xx_extension_devlist_lock);
-       printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
-       list_del(&ops->next);
-       mutex_unlock(&em28xx_extension_devlist_lock);
-       mutex_unlock(&em28xx_devlist_mutex);
-}
-EXPORT_SYMBOL(em28xx_unregister_extension);
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
                                             const struct video_device *template,
@@ -1925,11 +1950,43 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
        return vfd;
 }
 
-
-static int register_analog_devices(struct em28xx *dev)
+int em28xx_register_analog_devices(struct em28xx *dev)
 {
        int ret;
 
+       printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n",
+               dev->name,
+               (EM28XX_VERSION_CODE >> 16) & 0xff,
+               (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
+
+       /* Analog specific initialization */
+       dev->format = &format[0];
+       video_mux(dev, 0);
+
+       /* enable vbi capturing */
+
+/*     em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
+/*     em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */
+       em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
+
+       dev->mute = 1;          /* maybe not the right place... */
+       dev->volume = 0x1f;
+
+       em28xx_set_outfmt(dev);
+       em28xx_colorlevels_set_default(dev);
+       em28xx_compression_disable(dev);
+
+       /* set default norm */
+       dev->norm = em28xx_video_template.current_norm;
+       dev->width = norm_maxw(dev);
+       dev->height = norm_maxh(dev);
+       dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+       dev->hscale = 0;
+       dev->vscale = 0;
+
+       /* FIXME: This is a very bad hack! Not all devices have TV on input 2 */
+       dev->ctl_input = 2;
+
        /* allocate and fill video video_device struct */
        dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
        if (!dev->vdev) {
@@ -1978,383 +2035,3 @@ static int register_analog_devices(struct em28xx *dev)
 
        return 0;
 }
-
-
-/*
- * em28xx_init_dev()
- * allocates and inits the device structs, registers i2c bus and v4l device
- */
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
-                          int minor)
-{
-       struct em28xx_ops *ops = NULL;
-       struct em28xx *dev = *devhandle;
-       int retval = -ENOMEM;
-       int errCode;
-       unsigned int maxh, maxw;
-
-       dev->udev = udev;
-       mutex_init(&dev->lock);
-       mutex_init(&dev->ctrl_urb_lock);
-       spin_lock_init(&dev->slock);
-       init_waitqueue_head(&dev->open);
-       init_waitqueue_head(&dev->wait_frame);
-       init_waitqueue_head(&dev->wait_stream);
-
-       dev->em28xx_write_regs = em28xx_write_regs;
-       dev->em28xx_read_reg = em28xx_read_reg;
-       dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
-       dev->em28xx_write_regs_req = em28xx_write_regs_req;
-       dev->em28xx_read_reg_req = em28xx_read_reg_req;
-       dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
-
-       em28xx_pre_card_setup(dev);
-
-       errCode = em28xx_config(dev);
-       if (errCode) {
-               em28xx_errdev("error configuring device\n");
-               return -ENOMEM;
-       }
-
-       /* register i2c bus */
-       errCode = em28xx_i2c_register(dev);
-       if (errCode < 0) {
-               em28xx_errdev("%s: em28xx_i2c_register - errCode [%d]!\n",
-                       __func__, errCode);
-               return errCode;
-       }
-
-       /* Do board specific init and eeprom reading */
-       em28xx_card_setup(dev);
-
-       /* Configure audio */
-       errCode = em28xx_audio_analog_set(dev);
-       if (errCode < 0) {
-               em28xx_errdev("%s: em28xx_audio_analog_set - errCode [%d]!\n",
-                       __func__, errCode);
-               return errCode;
-       }
-
-       /* configure the device */
-       em28xx_config_i2c(dev);
-
-       /* set default norm */
-       dev->norm = em28xx_video_template.current_norm;
-
-       maxw = norm_maxw(dev);
-       maxh = norm_maxh(dev);
-
-       /* set default image size */
-       dev->width = maxw;
-       dev->height = maxh;
-       dev->interlaced = EM28XX_INTERLACED_DEFAULT;
-       dev->hscale = 0;
-       dev->vscale = 0;
-       dev->ctl_input = 2;
-
-       errCode = em28xx_config(dev);
-       if (errCode < 0) {
-               em28xx_errdev("%s: em28xx_config - errCode [%d]!\n",
-                       __func__, errCode);
-               return errCode;
-       }
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vidq.queued);
-
-
-       if (dev->has_msp34xx) {
-               /* Send a reset to other chips via gpio */
-               errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
-               if (errCode < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(1) failed! errCode [%d]\n",
-                               __func__, errCode);
-                       return errCode;
-               }
-               msleep(3);
-
-               errCode = em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
-               if (errCode < 0) {
-                       em28xx_errdev("%s: em28xx_write_regs_req - msp34xx(2) failed! errCode [%d]\n",
-                               __func__, errCode);
-                       return errCode;
-               }
-               msleep(3);
-       }
-
-       video_mux(dev, 0);
-
-       mutex_lock(&em28xx_devlist_mutex);
-       list_add_tail(&dev->devlist, &em28xx_devlist);
-       retval = register_analog_devices(dev);
-       if (retval < 0) {
-               em28xx_release_resources(dev);
-               mutex_unlock(&em28xx_devlist_mutex);
-               goto fail_reg_devices;
-       }
-
-       mutex_lock(&em28xx_extension_devlist_lock);
-       if (!list_empty(&em28xx_extension_devlist)) {
-               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-                       if (ops->id)
-                               ops->init(dev);
-               }
-       }
-       mutex_unlock(&em28xx_extension_devlist_lock);
-       mutex_unlock(&em28xx_devlist_mutex);
-
-       return 0;
-
-fail_reg_devices:
-       mutex_unlock(&dev->lock);
-       return retval;
-}
-
-#if defined(CONFIG_MODULES) && defined(MODULE)
-static void request_module_async(struct work_struct *work)
-{
-       struct em28xx *dev = container_of(work,
-                            struct em28xx, request_module_wk);
-
-       if (dev->has_audio_class)
-               request_module("snd-usb-audio");
-       else
-               request_module("em28xx-alsa");
-
-       if (dev->has_dvb)
-               request_module("em28xx-dvb");
-}
-
-static void request_modules(struct em28xx *dev)
-{
-       INIT_WORK(&dev->request_module_wk, request_module_async);
-       schedule_work(&dev->request_module_wk);
-}
-#else
-#define request_modules(dev)
-#endif /* CONFIG_MODULES */
-
-/*
- * em28xx_usb_probe()
- * checks for supported devices
- */
-static int em28xx_usb_probe(struct usb_interface *interface,
-                           const struct usb_device_id *id)
-{
-       const struct usb_endpoint_descriptor *endpoint;
-       struct usb_device *udev;
-       struct usb_interface *uif;
-       struct em28xx *dev = NULL;
-       int retval = -ENODEV;
-       int i, nr, ifnum;
-
-       udev = usb_get_dev(interface_to_usbdev(interface));
-       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
-
-       /* Check to see next free device and mark as used */
-       nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
-       em28xx_devused |= 1<<nr;
-
-       /* Don't register audio interfaces */
-       if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-               em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
-                               udev->descriptor.idVendor,
-                               udev->descriptor.idProduct,
-                               ifnum,
-                               interface->altsetting[0].desc.bInterfaceClass);
-
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-
-       em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
-                       udev->descriptor.idVendor,
-                       udev->descriptor.idProduct,
-                       ifnum,
-                       interface->altsetting[0].desc.bInterfaceClass);
-
-       endpoint = &interface->cur_altsetting->endpoint[1].desc;
-
-       /* check if the device has the iso in endpoint at the correct place */
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
-           USB_ENDPOINT_XFER_ISOC) {
-               em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-               em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
-               em28xx_devused &= ~(1<<nr);
-               return -ENODEV;
-       }
-
-       if (nr >= EM28XX_MAXBOARDS) {
-               printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
-                               EM28XX_MAXBOARDS);
-               em28xx_devused &= ~(1<<nr);
-               return -ENOMEM;
-       }
-
-       /* allocate memory for our device state and initialize it */
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               em28xx_err(DRIVER_NAME ": out of memory!\n");
-               em28xx_devused &= ~(1<<nr);
-               return -ENOMEM;
-       }
-
-       snprintf(dev->name, 29, "em28xx #%d", nr);
-       dev->devno = nr;
-       dev->model = id->driver_info;
-       dev->alt   = -1;
-
-       /* Checks if audio is provided by some interface */
-       for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
-               uif = udev->config->interface[i];
-               if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
-                       dev->has_audio_class = 1;
-                       break;
-               }
-       }
-
-       printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
-                  dev->has_audio_class ? "Has" : "Doesn't have");
-
-       /* compute alternate max packet sizes */
-       uif = udev->actconfig->interface[0];
-
-       dev->num_alt = uif->num_altsetting;
-       em28xx_info("Alternate settings: %i\n", dev->num_alt);
-/*     dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
-       dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
-
-       if (dev->alt_max_pkt_size == NULL) {
-               em28xx_errdev("out of memory!\n");
-               em28xx_devused &= ~(1<<nr);
-               kfree(dev);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < dev->num_alt ; i++) {
-               u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
-                                                       wMaxPacketSize);
-               dev->alt_max_pkt_size[i] =
-                   (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
-               em28xx_info("Alternate setting %i, max size= %i\n", i,
-                                               dev->alt_max_pkt_size[i]);
-       }
-
-       if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
-               dev->model = card[nr];
-
-       /* allocate device struct */
-       retval = em28xx_init_dev(&dev, udev, nr);
-       if (retval) {
-               em28xx_devused &= ~(1<<dev->devno);
-               kfree(dev);
-
-               return retval;
-       }
-
-       em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
-
-       /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
-
-       request_modules(dev);
-
-       return 0;
-}
-
-/*
- * em28xx_usb_disconnect()
- * called when the device gets diconencted
- * video device will be unregistered on v4l2_close in case it is still open
- */
-static void em28xx_usb_disconnect(struct usb_interface *interface)
-{
-       struct em28xx *dev;
-       struct em28xx_ops *ops = NULL;
-
-       dev = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-
-       if (!dev)
-               return;
-
-       em28xx_info("disconnecting %s\n", dev->vdev->name);
-
-       /* wait until all current v4l2 io is finished then deallocate
-          resources */
-       mutex_lock(&dev->lock);
-
-       wake_up_interruptible_all(&dev->open);
-
-       if (dev->users) {
-               em28xx_warn
-                   ("device /dev/video%d is open! Deregistration and memory "
-                    "deallocation are deferred on close.\n",
-                               dev->vdev->num);
-
-               dev->state |= DEV_MISCONFIGURED;
-               em28xx_uninit_isoc(dev);
-               dev->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&dev->wait_frame);
-               wake_up_interruptible(&dev->wait_stream);
-       } else {
-               dev->state |= DEV_DISCONNECTED;
-               em28xx_release_resources(dev);
-       }
-       mutex_unlock(&dev->lock);
-
-       mutex_lock(&em28xx_extension_devlist_lock);
-       if (!list_empty(&em28xx_extension_devlist)) {
-               list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-                       ops->fini(dev);
-               }
-       }
-       mutex_unlock(&em28xx_extension_devlist_lock);
-
-       if (!dev->users) {
-               kfree(dev->alt_max_pkt_size);
-               kfree(dev);
-       }
-}
-
-static struct usb_driver em28xx_usb_driver = {
-       .name = "em28xx",
-       .probe = em28xx_usb_probe,
-       .disconnect = em28xx_usb_disconnect,
-       .id_table = em28xx_id_table,
-};
-
-static int __init em28xx_module_init(void)
-{
-       int result;
-
-       printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n",
-              (EM28XX_VERSION_CODE >> 16) & 0xff,
-              (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff);
-#ifdef SNAPSHOT
-       printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n",
-              SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100);
-#endif
-
-       /* register this driver with the USB subsystem */
-       result = usb_register(&em28xx_usb_driver);
-       if (result)
-               em28xx_err(DRIVER_NAME
-                          " usb_register failed. Error number %d.\n", result);
-
-       return result;
-}
-
-static void __exit em28xx_module_exit(void)
-{
-       /* deregister this driver with the USB subsystem */
-       usb_deregister(&em28xx_usb_driver);
-}
-
-module_init(em28xx_module_init);
-module_exit(em28xx_module_exit);
index 5956e9b3062f5147ad34bb354412910a45f2fafe..b5eddc26388e476d4174149b824185482f1c7281 100644 (file)
@@ -67,7 +67,6 @@
 #define EM2820_BOARD_HERCULES_SMART_TV_USB2      26
 #define EM2820_BOARD_PINNACLE_USB_2_FM1216ME     27
 #define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28
-#define EM2820_BOARD_PINNACLE_DVC_100            29
 #define EM2820_BOARD_VIDEOLOGY_20K14XUSB         30
 #define EM2821_BOARD_USBGEAR_VD204               31
 #define EM2821_BOARD_SUPERCOMP_USB_2             32
@@ -97,6 +96,8 @@
 #define EM2882_BOARD_PINNACLE_HYBRID_PRO         56
 #define EM2883_BOARD_KWORLD_HYBRID_A316                  57
 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU     58
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850     60
+#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2    61
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
 #define EM2800_I2C_WRITE_TIMEOUT 20
 
 enum em28xx_mode {
-       EM28XX_MODE_UNDEFINED,
+       EM28XX_SUSPEND,
        EM28XX_ANALOG_MODE,
        EM28XX_DIGITAL_MODE,
 };
@@ -207,9 +208,12 @@ struct em28xx_usb_isoc_ctl {
 
 };
 
+/* Struct to enumberate video formats */
 struct em28xx_fmt {
        char  *name;
        u32   fourcc;          /* v4l2 format id */
+       int   depth;
+       int   reg;
 };
 
 /* buffer for one video frame */
@@ -255,54 +259,105 @@ enum enum28xx_itype {
        EM28XX_RADIO,
 };
 
+enum em28xx_ac97_mode {
+       EM28XX_NO_AC97 = 0,
+       EM28XX_AC97_EM202,
+       EM28XX_AC97_SIGMATEL,
+       EM28XX_AC97_OTHER,
+};
+
+struct em28xx_audio_mode {
+       enum em28xx_ac97_mode ac97;
+
+       u16 ac97_feat;
+       u32 ac97_vendor_id;
+
+       unsigned int has_audio:1;
+
+       unsigned int i2s_3rates:1;
+       unsigned int i2s_5rates:1;
+};
+
+/* em28xx has two audio inputs: tuner and line in.
+   However, on most devices, an auxiliary AC97 codec device is used.
+   The AC97 device may have several different inputs and outputs,
+   depending on their model. So, it is possible to use AC97 mixer to
+   address more than two different entries.
+ */
 enum em28xx_amux {
-       EM28XX_AMUX_VIDEO,
-       EM28XX_AMUX_LINE_IN,
-       EM28XX_AMUX_AC97_VIDEO,
-       EM28XX_AMUX_AC97_LINE_IN,
+       /* This is the only entry for em28xx tuner input */
+       EM28XX_AMUX_VIDEO,      /* em28xx tuner, AC97 mixer Video */
+
+       EM28XX_AMUX_LINE_IN,    /* AC97 mixer Line In */
+
+       /* Some less-common mixer setups */
+       EM28XX_AMUX_VIDEO2,     /* em28xx Line in, AC97 mixer Video */
+       EM28XX_AMUX_PHONE,
+       EM28XX_AMUX_MIC,
+       EM28XX_AMUX_CD,
+       EM28XX_AMUX_AUX,
+       EM28XX_AMUX_PCM_OUT,
+};
+
+enum em28xx_aout {
+       EM28XX_AOUT_MASTER = 1 << 0,
+       EM28XX_AOUT_LINE   = 1 << 1,
+       EM28XX_AOUT_MONO   = 1 << 2,
+       EM28XX_AOUT_LFE    = 1 << 3,
+       EM28XX_AOUT_SURR   = 1 << 4,
+};
+
+struct em28xx_reg_seq {
+       int reg;
+       unsigned char val, mask;
+       int sleep;
 };
 
 struct em28xx_input {
        enum enum28xx_itype type;
        unsigned int vmux;
        enum em28xx_amux amux;
+       enum em28xx_aout aout;
+       struct em28xx_reg_seq *gpio;
 };
 
 #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
 
 enum em28xx_decoder {
+       EM28XX_NODECODER,
        EM28XX_TVP5150,
-       EM28XX_SAA7113,
-       EM28XX_SAA7114
-};
-
-struct em28xx_reg_seq {
-       int reg;
-       unsigned char val, mask;
-       int sleep;
+       EM28XX_SAA711X,
 };
 
 struct em28xx_board {
        char *name;
        int vchannels;
        int tuner_type;
+       int tuner_addr;
 
        /* i2c flags */
        unsigned int tda9887_conf;
 
+       /* GPIO sequences */
+       struct em28xx_reg_seq *dvb_gpio;
+       struct em28xx_reg_seq *suspend_gpio;
+       struct em28xx_reg_seq *tuner_gpio;
+
        unsigned int is_em2800:1;
        unsigned int has_msp34xx:1;
        unsigned int mts_firmware:1;
-       unsigned int has_12mhz_i2s:1;
        unsigned int max_range_640_480:1;
        unsigned int has_dvb:1;
        unsigned int has_snapshot_button:1;
        unsigned int valid:1;
 
+       unsigned char xclk, i2c_speed;
+
        enum em28xx_decoder decoder;
 
        struct em28xx_input       input[MAX_EM28XX_INPUT];
        struct em28xx_input       radio;
+       IR_KEYTAB_TYPE            *ir_codes;
 };
 
 struct em28xx_eeprom {
@@ -369,32 +424,26 @@ struct em28xx {
        char name[30];          /* name (including minor) of the device */
        int model;              /* index in the device_data struct */
        int devno;              /* marks the number of this device */
-       unsigned int is_em2800:1;
-       unsigned int has_msp34xx:1;
-       unsigned int has_tda9887:1;
+       enum em28xx_chip_id chip_id;
+
+       struct em28xx_board board;
+
        unsigned int stream_on:1;       /* Locks streams */
        unsigned int has_audio_class:1;
-       unsigned int has_12mhz_i2s:1;
-       unsigned int max_range_640_480:1;
-       unsigned int has_dvb:1;
-       unsigned int has_snapshot_button:1;
-       unsigned int valid:1;           /* report for validated boards */
+       unsigned int has_alsa_audio:1;
 
-       /* Some older em28xx chips needs a waiting time after writing */
-       unsigned int wait_after_write;
+       struct em28xx_fmt *format;
 
-       /* GPIO sequences for analog and digital mode */
-       struct em28xx_reg_seq *analog_gpio, *digital_gpio;
+       struct em28xx_IR *ir;
 
-       /* GPIO sequences for tuner callbacks */
-       struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;
+       /* Some older em28xx chips needs a waiting time after writing */
+       unsigned int wait_after_write;
 
-       int video_inputs;       /* number of video inputs */
        struct list_head        devlist;
 
        u32 i2s_speed;          /* I2S speed for audio digital stream */
 
-       enum em28xx_decoder decoder;
+       struct em28xx_audio_mode audio_mode;
 
        int tuner_type;         /* type of the tuner */
        int tuner_addr;         /* tuner address */
@@ -409,6 +458,7 @@ struct em28xx {
        int ctl_freq;           /* selected frequency */
        unsigned int ctl_input; /* selected input */
        unsigned int ctl_ainput;/* selected audio input */
+       unsigned int ctl_aoutput;/* selected audio output */
        int mute;
        int volume;
        /* frame properties */
@@ -469,6 +519,9 @@ struct em28xx {
 
        enum em28xx_mode mode;
 
+       /* register numbers for GPO/GPIO registers */
+       u16 reg_gpo_num, reg_gpio_num;
+
        /* Caches GPO and GPIO registers */
        unsigned char   reg_gpo, reg_gpio;
 
@@ -508,11 +561,17 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg);
 int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
                          int len);
 int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
+
+int em28xx_read_ac97(struct em28xx *dev, u8 reg);
+int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
+
 int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_audio_setup(struct em28xx *dev);
 
 int em28xx_colorlevels_set_default(struct em28xx *dev);
 int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_set_outfmt(struct em28xx *dev);
 int em28xx_resolution_set(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
 int em28xx_init_isoc(struct em28xx *dev, int max_packets,
@@ -521,10 +580,20 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
 void em28xx_uninit_isoc(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
-
-/* Provided by em28xx-video.c */
+void em28xx_wake_i2c(struct em28xx *dev);
+void em28xx_remove_from_devlist(struct em28xx *dev);
+void em28xx_add_into_devlist(struct em28xx *dev);
+struct em28xx *em28xx_get_device(struct inode *inode,
+                                enum v4l2_buf_type *fh_type,
+                                int *has_radio);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
+void em28xx_init_extension(struct em28xx *dev);
+void em28xx_close_extension(struct em28xx *dev);
+
+/* Provided by em28xx-video.c */
+int em28xx_register_analog_devices(struct em28xx *dev);
+void em28xx_release_analog_resources(struct em28xx *dev);
 
 /* Provided by em28xx-cards.c */
 extern int em2800_variant_detect(struct usb_device *udev, int model);
@@ -535,9 +604,9 @@ extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
 void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
+void em28xx_release_resources(struct em28xx *dev);
 
 /* Provided by em28xx-input.c */
-/* TODO: Check if the standard get_key handlers on ir-common can be used */
 int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
 int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
@@ -545,6 +614,9 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
 void em28xx_register_snapshot_button(struct em28xx *dev);
 void em28xx_deregister_snapshot_button(struct em28xx *dev);
 
+int em28xx_ir_init(struct em28xx *dev);
+int em28xx_ir_fini(struct em28xx *dev);
+
 /* printk macros */
 
 #define em28xx_err(fmt, arg...) do {\
@@ -564,7 +636,7 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev);
 static inline int em28xx_compression_disable(struct em28xx *dev)
 {
        /* side effect of disabling scaler and mixer */
-       return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1);
+       return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
 }
 
 static inline int em28xx_contrast_get(struct em28xx *dev)
@@ -636,7 +708,7 @@ static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
 /*FIXME: maxw should be dependent of alt mode */
 static inline unsigned int norm_maxw(struct em28xx *dev)
 {
-       if (dev->max_range_640_480)
+       if (dev->board.max_range_640_480)
                return 640;
        else
                return 720;
@@ -644,7 +716,7 @@ static inline unsigned int norm_maxw(struct em28xx *dev)
 
 static inline unsigned int norm_maxh(struct em28xx *dev)
 {
-       if (dev->max_range_640_480)
+       if (dev->board.max_range_640_480)
                return 480;
        else
                return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
index 9d0ef96c23ff47c6147059ee9b3a2b28b5986067..83c07112c59d64c4fb6832b01a5d1cedc174c07c 100644 (file)
@@ -1581,7 +1581,7 @@ et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
 
        strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
        if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+               strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
                        sizeof(cap.bus_info));
 
        if (copy_to_user(arg, &cap, sizeof(cap)))
index 6b557c057facf79419ffadf393240b485259c070..ee6a691dff229d9d597b5ac9cd1b101294872ab3 100644 (file)
@@ -12,12 +12,13 @@ menuconfig USB_GSPCA
          "Video For Linux" to use this driver.
 
          To compile this driver as modules, choose M here: the
-         modules will be called gspca_main.
+         module will be called gspca_main.
 
 
 if USB_GSPCA && VIDEO_V4L2
 
 source "drivers/media/video/gspca/m5602/Kconfig"
+source "drivers/media/video/gspca/stv06xx/Kconfig"
 
 config USB_GSPCA_CONEX
        tristate "Conexant Camera Driver"
@@ -64,6 +65,16 @@ config USB_GSPCA_OV519
          To compile this driver as a module, choose M here: the
          module will be called gspca_ov519.
 
+config USB_GSPCA_OV534
+       tristate "OV534 USB Camera Driver"
+       depends on VIDEO_V4L2 && USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on the OV534 chip.
+         (e.g. Sony Playstation EYE)
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_ov534.
+
 config USB_GSPCA_PAC207
        tristate "Pixart PAC207 USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
@@ -83,10 +94,11 @@ config USB_GSPCA_PAC7311
          module will be called gspca_pac7311.
 
 config USB_GSPCA_SONIXB
-       tristate "SN9C102 USB Camera Driver"
+       tristate "SONIX Bayer USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
        help
-         Say Y here if you want support for cameras based on the SONIXB chip.
+         Say Y here if you want support for cameras based on the Sonix
+         chips with Bayer format (SN9C101, SN9C102 and SN9C103).
 
          To compile this driver as a module, choose M here: the
          module will be called gspca_sonixb.
@@ -95,7 +107,8 @@ config USB_GSPCA_SONIXJ
        tristate "SONIX JPEG USB Camera Driver"
        depends on VIDEO_V4L2 && USB_GSPCA
        help
-         Say Y here if you want support for cameras based on the SONIXJ chip.
+         Say Y here if you want support for cameras based on the Sonix
+         chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110).
 
          To compile this driver as a module, choose M here: the
          module will be called gspca_sonixj
@@ -171,7 +184,7 @@ config USB_GSPCA_SUNPLUS
          SPCA504(abc) SPCA533 SPCA536 chips.
 
          To compile this driver as a module, choose M here: the
-         module will be called gspca_spca5xx.
+         module will be called gspca_sunplus.
 
 config USB_GSPCA_T613
        tristate "T613 (JPEG Compliance) USB Camera Driver"
index 22734f5a6c3216b52cd0fb867832da939ced7bf6..bd8d9ee405049624f4f417de1c99318ae95197c0 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_USB_GSPCA_ETOMS)   += gspca_etoms.o
 obj-$(CONFIG_USB_GSPCA_FINEPIX)        += gspca_finepix.o
 obj-$(CONFIG_USB_GSPCA_MARS)   += gspca_mars.o
 obj-$(CONFIG_USB_GSPCA_OV519)  += gspca_ov519.o
+obj-$(CONFIG_USB_GSPCA_OV534)  += gspca_ov534.o
 obj-$(CONFIG_USB_GSPCA_PAC207) += gspca_pac207.o
 obj-$(CONFIG_USB_GSPCA_PAC7311) += gspca_pac7311.o
 obj-$(CONFIG_USB_GSPCA_SONIXB) += gspca_sonixb.o
@@ -27,6 +28,7 @@ gspca_etoms-objs              := etoms.o
 gspca_finepix-objs             := finepix.o
 gspca_mars-objs                        := mars.o
 gspca_ov519-objs               := ov519.o
+gspca_ov534-objs               := ov534.o
 gspca_pac207-objs              := pac207.o
 gspca_pac7311-objs             := pac7311.o
 gspca_sonixb-objs              := sonixb.o
@@ -45,4 +47,4 @@ gspca_vc032x-objs             := vc032x.o
 gspca_zc3xx-objs               := zc3xx.o
 
 obj-$(CONFIG_USB_M5602)                += m5602/
-
+obj-$(CONFIG_USB_STV06XX)      += stv06xx/
index de28354ea5bac3e0a6a9650ac2266aba2a026ee3..1753f5bb35444c7db2fba72d05016e2b06e36a2d 100644 (file)
@@ -93,7 +93,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
index 3be30b420a26fea30eb09674c82798152f0519b2..f3cd8ff5cc923b07a4b97367bd5ee99b750127ba 100644 (file)
@@ -112,7 +112,7 @@ static struct ctrl sd_ctrls[] = {
         },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240,
@@ -125,7 +125,7 @@ static struct v4l2_pix_format vga_mode[] = {
                .priv = 0}, */
 };
 
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144,
index 607942fd797004cb0737cac2af973e5e21623f9b..afc8b2dd307bb36df8b40886def1cdef96cb1dd8 100644 (file)
@@ -72,7 +72,7 @@ struct usb_fpix {
 }
 
 /* These cameras only support 320x200. */
-static struct v4l2_pix_format fpix_mode[1] = {
+static const struct v4l2_pix_format fpix_mode[1] = {
        { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -314,9 +314,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        int ret;
        int size_ret;
 
-       /* Reset bulk in endpoint */
-       usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr);
-
        /* Init the device */
        memset(gspca_dev->usb_buf, 0, 12);
        gspca_dev->usb_buf[0] = 0xc6;
index 02a6e9ef033740d7401b6bd1ccd5966552add823..8b9f3bde5740dd7edcf60270b7c5b5be3a0230fc 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/string.h>
 #include <linux/pagemap.h>
 #include <linux/io.h>
-#include <linux/kref.h>
 #include <asm/page.h>
 #include <linux/uaccess.h>
 #include <linux/jiffies.h>
@@ -45,7 +44,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 3, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 4, 0)
 
 static int video_nr = -1;
 
@@ -150,8 +149,11 @@ static void fill_frame(struct gspca_dev *gspca_dev,
 
                /* check the packet status and length */
                len = urb->iso_frame_desc[i].actual_length;
-               if (len == 0)
+               if (len == 0) {
+                       if (gspca_dev->empty_packet == 0)
+                               gspca_dev->empty_packet = 1;
                        continue;
+               }
                st = urb->iso_frame_desc[i].status;
                if (st) {
                        PDEBUG(D_ERR,
@@ -170,7 +172,6 @@ static void fill_frame(struct gspca_dev *gspca_dev,
        }
 
        /* resubmit the URB */
-       urb->status = 0;
        st = usb_submit_urb(urb, GFP_ATOMIC);
        if (st < 0)
                PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
@@ -200,11 +201,18 @@ static void bulk_irq(struct urb *urb
 {
        struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
        struct gspca_frame *frame;
+       int st;
 
        PDEBUG(D_PACK, "bulk irq");
        if (!gspca_dev->streaming)
                return;
-       if (urb->status != 0 && urb->status != -ECONNRESET) {
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ECONNRESET:
+               urb->status = 0;
+               break;
+       default:
 #ifdef CONFIG_PM
                if (!gspca_dev->frozen)
 #endif
@@ -223,6 +231,13 @@ static void bulk_irq(struct urb *urb
                                        urb->transfer_buffer,
                                        urb->actual_length);
        }
+
+       /* resubmit the URB */
+       if (gspca_dev->cam.bulk_nurbs != 0) {
+               st = usb_submit_urb(urb, GFP_ATOMIC);
+               if (st < 0)
+                       PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+       }
 }
 
 /*
@@ -285,7 +300,6 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
                frame->v4l2_buf.bytesused = frame->data_end - frame->data;
                frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
                frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
-               atomic_inc(&gspca_dev->nevent);
                wake_up_interruptible(&gspca_dev->wq);  /* event = new frame */
                i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
                gspca_dev->fr_i = i;
@@ -379,7 +393,6 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
        gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
        gspca_dev->last_packet_type = DISCARD_PACKET;
        gspca_dev->sequence = 0;
-       atomic_set(&gspca_dev->nevent, 0);
        return 0;
 }
 
@@ -520,11 +533,14 @@ static int create_urbs(struct gspca_dev *gspca_dev,
                nurbs = DEF_NURBS;
        } else {                                /* bulk */
                npkt = 0;
-               bsize = gspca_dev->cam. bulk_size;
+               bsize = gspca_dev->cam.bulk_size;
                if (bsize == 0)
                        bsize = psize;
                PDEBUG(D_STREAM, "bulk bsize:%d", bsize);
-               nurbs = 1;
+               if (gspca_dev->cam.bulk_nurbs != 0)
+                       nurbs = gspca_dev->cam.bulk_nurbs;
+               else
+                       nurbs = 1;
        }
 
        gspca_dev->nurbs = nurbs;
@@ -597,6 +613,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                if (ret < 0)
                        goto out;
 
+               /* clear the bulk endpoint */
+               if (gspca_dev->alt == 0)        /* if bulk transfer */
+                       usb_clear_halt(gspca_dev->dev,
+                                       usb_rcvintpipe(gspca_dev->dev,
+                                                gspca_dev->cam.epaddr));
+
                /* start the cam */
                ret = gspca_dev->sd_desc->start(gspca_dev);
                if (ret < 0) {
@@ -604,10 +626,9 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                        goto out;
                }
                gspca_dev->streaming = 1;
-               atomic_set(&gspca_dev->nevent, 0);
 
-               /* bulk transfers are started by the subdriver */
-               if (gspca_dev->alt == 0)
+               /* some bulk transfers are started by the subdriver */
+               if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0)
                        break;
 
                /* submit the URBs */
@@ -618,8 +639,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                                        "usb_submit_urb [%d] err %d", n, ret);
                                gspca_dev->streaming = 0;
                                destroy_urbs(gspca_dev);
-                               if (ret == -ENOSPC)
+                               if (ret == -ENOSPC) {
+                                       msleep(20);     /* wait for kill
+                                                        * complete */
                                        break;  /* try the previous alt */
+                               }
                                goto out;
                        }
                }
@@ -637,7 +661,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
 
        ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
        if (ret < 0)
-               PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret);
+               PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
        return ret;
 }
 
@@ -645,7 +669,6 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
 static void gspca_stream_off(struct gspca_dev *gspca_dev)
 {
        gspca_dev->streaming = 0;
-       atomic_set(&gspca_dev->nevent, 0);
        if (gspca_dev->present
            && gspca_dev->sd_desc->stopN)
                gspca_dev->sd_desc->stopN(gspca_dev);
@@ -727,7 +750,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                        if (fmtdesc->index == index)
                                break;          /* new format */
                        index++;
-                       if (index >= sizeof fmt_tb / sizeof fmt_tb[0])
+                       if (index >= ARRAY_SIZE(fmt_tb))
                                return -EINVAL;
                }
        }
@@ -752,8 +775,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        struct gspca_dev *gspca_dev = priv;
        int mode;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        mode = gspca_dev->curr_mode;
        memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode],
                sizeof fmt->fmt.pix);
@@ -765,8 +786,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
 {
        int w, h, mode, mode2;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        w = fmt->fmt.pix.width;
        h = fmt->fmt.pix.height;
 
@@ -846,11 +865,11 @@ out:
        return ret;
 }
 
-static void gspca_delete(struct kref *kref)
+static void gspca_release(struct video_device *vfd)
 {
-       struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref);
+       struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
 
-       PDEBUG(D_STREAM, "device deleted");
+       PDEBUG(D_STREAM, "device released");
 
        kfree(gspca_dev->usb_buf);
        kfree(gspca_dev);
@@ -862,7 +881,7 @@ static int dev_open(struct inode *inode, struct file *file)
        int ret;
 
        PDEBUG(D_STREAM, "%s open", current->comm);
-       gspca_dev = video_drvdata(file);
+       gspca_dev = (struct gspca_dev *) video_devdata(file);
        if (mutex_lock_interruptible(&gspca_dev->queue_lock))
                return -ERESTARTSYS;
        if (!gspca_dev->present) {
@@ -883,17 +902,14 @@ static int dev_open(struct inode *inode, struct file *file)
 
        gspca_dev->users++;
 
-       /* one more user */
-       kref_get(&gspca_dev->kref);
-
        file->private_data = gspca_dev;
 #ifdef GSPCA_DEBUG
        /* activate the v4l2 debug */
        if (gspca_debug & D_V4L2)
-               gspca_dev->vdev->debug |= V4L2_DEBUG_IOCTL
+               gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL
                                        | V4L2_DEBUG_IOCTL_ARG;
        else
-               gspca_dev->vdev->debug &= ~(V4L2_DEBUG_IOCTL
+               gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
                                        | V4L2_DEBUG_IOCTL_ARG);
 #endif
        ret = 0;
@@ -932,8 +948,6 @@ static int dev_close(struct inode *inode, struct file *file)
 
        PDEBUG(D_STREAM, "close done");
 
-       kref_put(&gspca_dev->kref, gspca_delete);
-
        return 0;
 }
 
@@ -1053,6 +1067,35 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
        return -EINVAL;
 }
 
+/*fixme: have an audio flag in gspca_dev?*/
+static int vidioc_s_audio(struct file *file, void *priv,
+                        struct v4l2_audio *audio)
+{
+       if (audio->index != 0)
+               return -EINVAL;
+       return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv,
+                        struct v4l2_audio *audio)
+{
+       memset(audio, 0, sizeof *audio);
+       strcpy(audio->name, "Microphone");
+       return 0;
+}
+
+static int vidioc_enumaudio(struct file *file, void *priv,
+                        struct v4l2_audio *audio)
+{
+       if (audio->index != 0)
+               return -EINVAL;
+
+       strcpy(audio->name, "Microphone");
+       audio->capability = 0;
+       audio->mode = 0;
+       return 0;
+}
+
 static int vidioc_querymenu(struct file *file, void *priv,
                            struct v4l2_querymenu *qmenu)
 {
@@ -1096,8 +1139,6 @@ static int vidioc_reqbufs(struct file *file, void *priv,
        struct gspca_dev *gspca_dev = priv;
        int i, ret = 0;
 
-       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        switch (rb->memory) {
        case GSPCA_MEMORY_READ:                 /* (internal call) */
        case V4L2_MEMORY_MMAP:
@@ -1162,8 +1203,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
        struct gspca_dev *gspca_dev = priv;
        struct gspca_frame *frame;
 
-       if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-           || v4l2_buf->index < 0
+       if (v4l2_buf->index < 0
            || v4l2_buf->index >= gspca_dev->nframes)
                return -EINVAL;
 
@@ -1186,7 +1226,8 @@ static int vidioc_streamon(struct file *file, void *priv,
                ret = -ENODEV;
                goto out;
        }
-       if (gspca_dev->nframes == 0) {
+       if (gspca_dev->nframes == 0
+           || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) {
                ret = -EINVAL;
                goto out;
        }
@@ -1236,7 +1277,6 @@ static int vidioc_streamoff(struct file *file, void *priv,
        gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
        gspca_dev->last_packet_type = DISCARD_PACKET;
        gspca_dev->sequence = 0;
-       atomic_set(&gspca_dev->nevent, 0);
        ret = 0;
 out:
        mutex_unlock(&gspca_dev->queue_lock);
@@ -1281,6 +1321,17 @@ static int vidioc_g_parm(struct file *filp, void *priv,
        memset(parm, 0, sizeof *parm);
        parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        parm->parm.capture.readbuffers = gspca_dev->nbufread;
+
+       if (gspca_dev->sd_desc->get_streamparm) {
+               int ret;
+
+               if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+                       return -ERESTARTSYS;
+               ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+               mutex_unlock(&gspca_dev->usb_lock);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -1295,6 +1346,17 @@ static int vidioc_s_parm(struct file *filp, void *priv,
                parm->parm.capture.readbuffers = gspca_dev->nbufread;
        else
                gspca_dev->nbufread = n;
+
+       if (gspca_dev->sd_desc->set_streamparm) {
+               int ret;
+
+               if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+                       return -ERESTARTSYS;
+               ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+               mutex_unlock(&gspca_dev->usb_lock);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -1440,33 +1502,22 @@ static int frame_wait(struct gspca_dev *gspca_dev,
        i = gspca_dev->fr_o;
        j = gspca_dev->fr_queue[i];
        frame = &gspca_dev->frame[j];
-       if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) {
-               atomic_dec(&gspca_dev->nevent);
-               goto ok;
-       }
-       if (nonblock_ing)                       /* no frame yet */
-               return -EAGAIN;
 
-       /* wait till a frame is ready */
-       for (;;) {
+       if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) {
+               if (nonblock_ing)
+                       return -EAGAIN;
+
+               /* wait till a frame is ready */
                ret = wait_event_interruptible_timeout(gspca_dev->wq,
-                                       atomic_read(&gspca_dev->nevent) > 0,
-                                       msecs_to_jiffies(3000));
-               if (ret <= 0) {
-                       if (ret < 0)
-                               return ret;     /* interrupt */
-                       return -EIO;            /* timeout */
-               }
-               atomic_dec(&gspca_dev->nevent);
-               if (!gspca_dev->streaming || !gspca_dev->present)
+                       (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) ||
+                       !gspca_dev->streaming || !gspca_dev->present,
+                       msecs_to_jiffies(3000));
+               if (ret < 0)
+                       return ret;
+               if (ret == 0 || !gspca_dev->streaming || !gspca_dev->present)
                        return -EIO;
-               i = gspca_dev->fr_o;
-               j = gspca_dev->fr_queue[i];
-               frame = &gspca_dev->frame[j];
-               if (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
-                       break;
        }
-ok:
+
        gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
        PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
                gspca_dev->fr_q,
@@ -1494,8 +1545,6 @@ static int vidioc_dqbuf(struct file *file, void *priv,
        int i, ret;
 
        PDEBUG(D_FRAM, "dqbuf");
-       if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
        if (v4l2_buf->memory != gspca_dev->memory)
                return -EINVAL;
 
@@ -1550,8 +1599,6 @@ static int vidioc_qbuf(struct file *file, void *priv,
        int i, index, ret;
 
        PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index);
-       if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
 
        if (mutex_lock_interruptible(&gspca_dev->queue_lock))
                return -ERESTARTSYS;
@@ -1761,7 +1808,7 @@ static struct file_operations dev_fops = {
        .release = dev_close,
        .read = dev_read,
        .mmap = dev_mmap,
-       .ioctl = video_ioctl2,
+       .unlocked_ioctl = __video_ioctl2,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = v4l_compat_ioctl32,
 #endif
@@ -1781,6 +1828,9 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_queryctrl       = vidioc_queryctrl,
        .vidioc_g_ctrl          = vidioc_g_ctrl,
        .vidioc_s_ctrl          = vidioc_s_ctrl,
+       .vidioc_g_audio         = vidioc_g_audio,
+       .vidioc_s_audio         = vidioc_s_audio,
+       .vidioc_enumaudio       = vidioc_enumaudio,
        .vidioc_querymenu       = vidioc_querymenu,
        .vidioc_enum_input      = vidioc_enum_input,
        .vidioc_g_input         = vidioc_g_input,
@@ -1802,7 +1852,7 @@ static struct video_device gspca_template = {
        .name = "gspca main driver",
        .fops = &dev_fops,
        .ioctl_ops = &dev_ioctl_ops,
-       .release = video_device_release,
+       .release = gspca_release,
        .minor = -1,
 };
 
@@ -1840,7 +1890,6 @@ int gspca_dev_probe(struct usb_interface *intf,
                err("couldn't kzalloc gspca struct");
                return -ENOMEM;
        }
-       kref_init(&gspca_dev->kref);
        gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL);
        if (!gspca_dev->usb_buf) {
                err("out of memory");
@@ -1852,12 +1901,13 @@ int gspca_dev_probe(struct usb_interface *intf,
        gspca_dev->nbalt = intf->num_altsetting;
        gspca_dev->sd_desc = sd_desc;
        gspca_dev->nbufread = 2;
+       gspca_dev->empty_packet = -1;   /* don't check the empty packets */
 
        /* configure the subdriver and initialize the USB device */
-       ret = gspca_dev->sd_desc->config(gspca_dev, id);
+       ret = sd_desc->config(gspca_dev, id);
        if (ret < 0)
                goto out;
-       ret = gspca_dev->sd_desc->init(gspca_dev);
+       ret = sd_desc->init(gspca_dev);
        if (ret < 0)
                goto out;
        ret = gspca_set_alt0(gspca_dev);
@@ -1871,18 +1921,15 @@ int gspca_dev_probe(struct usb_interface *intf,
        init_waitqueue_head(&gspca_dev->wq);
 
        /* init video stuff */
-       gspca_dev->vdev = video_device_alloc();
-       memcpy(gspca_dev->vdev, &gspca_template, sizeof gspca_template);
-       gspca_dev->vdev->parent = &dev->dev;
+       memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
+       gspca_dev->vdev.parent = &dev->dev;
        gspca_dev->module = module;
        gspca_dev->present = 1;
-       video_set_drvdata(gspca_dev->vdev, gspca_dev);
-       ret = video_register_device(gspca_dev->vdev,
+       ret = video_register_device(&gspca_dev->vdev,
                                  VFL_TYPE_GRABBER,
                                  video_nr);
        if (ret < 0) {
                err("video_register_device err %d", ret);
-               video_device_release(gspca_dev->vdev);
                goto out;
        }
 
@@ -1906,15 +1953,14 @@ void gspca_disconnect(struct usb_interface *intf)
 {
        struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 
-       usb_set_intfdata(intf, NULL);
-
-/* We don't want people trying to open up the device */
-       video_unregister_device(gspca_dev->vdev);
-
        gspca_dev->present = 0;
        gspca_dev->streaming = 0;
 
-       kref_put(&gspca_dev->kref, gspca_delete);
+       usb_set_intfdata(intf, NULL);
+
+       /* release the device */
+       /* (this will call gspca_release() immediatly or on last close) */
+       video_unregister_device(&gspca_dev->vdev);
 
        PDEBUG(D_PROBE, "disconnect complete");
 }
@@ -1992,7 +2038,7 @@ int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
           desired lumination fast (with the risc of a slight overshoot) */
        steps = abs(desired_avg_lum - avg_lum) / deadzone;
 
-       PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n",
+       PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
                avg_lum, desired_avg_lum, steps);
 
        for (i = 0; i < steps; i++) {
index d25e8d69373b8d94335579d4d337054e80164f31..c90af9cb1e079b6c3aaa322c0ff739a2652207dc 100644 (file)
@@ -56,8 +56,12 @@ extern int gspca_debug;
 /* device information - set at probe time */
 struct cam {
        int bulk_size;          /* buffer size when image transfer by bulk */
-       struct v4l2_pix_format *cam_mode;       /* size nmodes */
+       const struct v4l2_pix_format *cam_mode; /* size nmodes */
        char nmodes;
+       __u8 bulk_nurbs;        /* number of URBs in bulk mode
+                                * - cannot be > MAX_NURBS
+                                * - when 0 and bulk_size != 0 means
+                                *   1 URB and submit done by subdriver */
        __u8 epaddr;
 };
 
@@ -70,6 +74,8 @@ typedef void (*cam_v_op) (struct gspca_dev *);
 typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *);
 typedef int (*cam_jpg_op) (struct gspca_dev *,
                                struct v4l2_jpegcompression *);
+typedef int (*cam_streamparm_op) (struct gspca_dev *,
+                                 struct v4l2_streamparm *);
 typedef int (*cam_qmnu_op) (struct gspca_dev *,
                        struct v4l2_querymenu *);
 typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
@@ -102,6 +108,8 @@ struct sd_desc {
        cam_jpg_op get_jcomp;
        cam_jpg_op set_jcomp;
        cam_qmnu_op querymenu;
+       cam_streamparm_op get_streamparm;
+       cam_streamparm_op set_streamparm;
 };
 
 /* packet types when moving from iso buf to frame buf */
@@ -120,10 +128,9 @@ struct gspca_frame {
 };
 
 struct gspca_dev {
-       struct video_device *vdev;
+       struct video_device vdev;       /* !! must be the first item */
        struct module *module;          /* subdriver handling the device */
        struct usb_device *dev;
-       struct kref kref;
        struct file *capt_file;         /* file doing video capture */
 
        struct cam cam;                         /* device information */
@@ -142,22 +149,20 @@ struct gspca_dev {
        char fr_q;                              /* next frame to queue */
        char fr_o;                              /* next frame to dequeue */
        signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */
-       char last_packet_type;
+       __u8 last_packet_type;
+       __s8 empty_packet;              /* if (-1) don't check empty packets */
+       __u8 streaming;
 
-       __u8 iface;                     /* USB interface number */
-       __u8 alt;                       /* USB alternate setting */
        __u8 curr_mode;                 /* current camera mode */
        __u32 pixfmt;                   /* current mode parameters */
        __u16 width;
        __u16 height;
+       __u32 sequence;                 /* frame sequence number */
 
-       atomic_t nevent;                /* number of frames done */
        wait_queue_head_t wq;           /* wait queue */
        struct mutex usb_lock;          /* usb exchange protection */
        struct mutex read_lock;         /* read protection */
        struct mutex queue_lock;        /* ISOC queue protection */
-       __u32 sequence;                 /* frame sequence number */
-       char streaming;
 #ifdef CONFIG_PM
        char frozen;                    /* suspend - resume */
 #endif
@@ -166,6 +171,8 @@ struct gspca_dev {
        char nbufread;                  /* number of buffers for read() */
        char nurbs;                     /* number of allocated URBs */
        char memory;                    /* memory type (V4L2_MEMORY_xxx) */
+       __u8 iface;                     /* USB interface number */
+       __u8 alt;                       /* USB alternate setting */
        __u8 nbalt;                     /* number of USB alternate settings */
 };
 
index 1a37ae4bc82dad9dbe4589cfb7aeb3966e347dc6..a3f3b7a0c7e75e59f8262751d9370d48cf0ccf79 100644 (file)
 
 /*****************************************************************************/
 
-#define M5602_XB_SENSOR_TYPE 0x00
-#define M5602_XB_SENSOR_CTRL 0x01
-#define M5602_XB_LINE_OF_FRAME_H 0x02
-#define M5602_XB_LINE_OF_FRAME_L 0x03
-#define M5602_XB_PIX_OF_LINE_H 0x04
-#define M5602_XB_PIX_OF_LINE_L 0x05
-#define M5602_XB_VSYNC_PARA 0x06
-#define M5602_XB_HSYNC_PARA 0x07
-#define M5602_XB_TEST_MODE_1 0x08
-#define M5602_XB_TEST_MODE_2 0x09
-#define M5602_XB_SIG_INI 0x0a
-#define M5602_XB_DS_PARA 0x0e
-#define M5602_XB_TRIG_PARA 0x0f
-#define M5602_XB_CLK_PD 0x10
-#define M5602_XB_MCU_CLK_CTRL 0x12
-#define M5602_XB_MCU_CLK_DIV 0x13
-#define M5602_XB_SEN_CLK_CTRL 0x14
-#define M5602_XB_SEN_CLK_DIV 0x15
-#define M5602_XB_AUD_CLK_CTRL 0x16
-#define M5602_XB_AUD_CLK_DIV 0x17
-#define M5602_XB_DEVCTR1 0x41
-#define M5602_XB_EPSETR0 0x42
-#define M5602_XB_EPAFCTR 0x47
-#define M5602_XB_EPBFCTR 0x49
-#define M5602_XB_EPEFCTR 0x4f
-#define M5602_XB_TEST_REG 0x53
-#define M5602_XB_ALT2SIZE 0x54
-#define M5602_XB_ALT3SIZE 0x55
-#define M5602_XB_OBSFRAME 0x56
-#define M5602_XB_PWR_CTL 0x59
-#define M5602_XB_ADC_CTRL 0x60
-#define M5602_XB_ADC_DATA 0x61
-#define M5602_XB_MISC_CTRL 0x62
-#define M5602_XB_SNAPSHOT 0x63
-#define M5602_XB_SCRATCH_1 0x64
-#define M5602_XB_SCRATCH_2 0x65
-#define M5602_XB_SCRATCH_3 0x66
-#define M5602_XB_SCRATCH_4 0x67
-#define M5602_XB_I2C_CTRL 0x68
-#define M5602_XB_I2C_CLK_DIV 0x69
-#define M5602_XB_I2C_DEV_ADDR 0x6a
-#define M5602_XB_I2C_REG_ADDR 0x6b
-#define M5602_XB_I2C_DATA 0x6c
-#define M5602_XB_I2C_STATUS 0x6d
-#define M5602_XB_GPIO_DAT_H 0x70
-#define M5602_XB_GPIO_DAT_L 0x71
-#define M5602_XB_GPIO_DIR_H 0x72
-#define M5602_XB_GPIO_DIR_L 0x73
-#define M5602_XB_GPIO_EN_H 0x74
-#define M5602_XB_GPIO_EN_L 0x75
-#define M5602_XB_GPIO_DAT 0x76
-#define M5602_XB_GPIO_DIR 0x77
-#define M5602_XB_MISC_CTL 0x70
+#define M5602_XB_SENSOR_TYPE           0x00
+#define M5602_XB_SENSOR_CTRL           0x01
+#define M5602_XB_LINE_OF_FRAME_H       0x02
+#define M5602_XB_LINE_OF_FRAME_L       0x03
+#define M5602_XB_PIX_OF_LINE_H         0x04
+#define M5602_XB_PIX_OF_LINE_L         0x05
+#define M5602_XB_VSYNC_PARA            0x06
+#define M5602_XB_HSYNC_PARA            0x07
+#define M5602_XB_TEST_MODE_1           0x08
+#define M5602_XB_TEST_MODE_2           0x09
+#define M5602_XB_SIG_INI               0x0a
+#define M5602_XB_DS_PARA               0x0e
+#define M5602_XB_TRIG_PARA             0x0f
+#define M5602_XB_CLK_PD                        0x10
+#define M5602_XB_MCU_CLK_CTRL          0x12
+#define M5602_XB_MCU_CLK_DIV           0x13
+#define M5602_XB_SEN_CLK_CTRL          0x14
+#define M5602_XB_SEN_CLK_DIV           0x15
+#define M5602_XB_AUD_CLK_CTRL          0x16
+#define M5602_XB_AUD_CLK_DIV           0x17
+#define M5602_XB_DEVCTR1               0x41
+#define M5602_XB_EPSETR0               0x42
+#define M5602_XB_EPAFCTR               0x47
+#define M5602_XB_EPBFCTR               0x49
+#define M5602_XB_EPEFCTR               0x4f
+#define M5602_XB_TEST_REG              0x53
+#define M5602_XB_ALT2SIZE              0x54
+#define M5602_XB_ALT3SIZE              0x55
+#define M5602_XB_OBSFRAME              0x56
+#define M5602_XB_PWR_CTL               0x59
+#define M5602_XB_ADC_CTRL              0x60
+#define M5602_XB_ADC_DATA              0x61
+#define M5602_XB_MISC_CTRL             0x62
+#define M5602_XB_SNAPSHOT              0x63
+#define M5602_XB_SCRATCH_1             0x64
+#define M5602_XB_SCRATCH_2             0x65
+#define M5602_XB_SCRATCH_3             0x66
+#define M5602_XB_SCRATCH_4             0x67
+#define M5602_XB_I2C_CTRL              0x68
+#define M5602_XB_I2C_CLK_DIV           0x69
+#define M5602_XB_I2C_DEV_ADDR          0x6a
+#define M5602_XB_I2C_REG_ADDR          0x6b
+#define M5602_XB_I2C_DATA              0x6c
+#define M5602_XB_I2C_STATUS            0x6d
+#define M5602_XB_GPIO_DAT_H            0x70
+#define M5602_XB_GPIO_DAT_L            0x71
+#define M5602_XB_GPIO_DIR_H            0x72
+#define M5602_XB_GPIO_DIR_L            0x73
+#define M5602_XB_GPIO_EN_H             0x74
+#define M5602_XB_GPIO_EN_L             0x75
+#define M5602_XB_GPIO_DAT              0x76
+#define M5602_XB_GPIO_DIR              0x77
+#define M5602_XB_MISC_CTL              0x70
 
 #define I2C_BUSY 0x80
 
 #define M5602_ISOC_ENDPOINT_ADDR 0x81
 #define M5602_INTR_ENDPOINT_ADDR 0x82
 
-#define M5602_MAX_FRAMES       32
-#define M5602_URBS             2
-#define M5602_ISOC_PACKETS     14
-
-#define M5602_URB_TIMEOUT      msecs_to_jiffies(2 * M5602_ISOC_PACKETS)
 #define M5602_URB_MSG_TIMEOUT   5000
-#define M5602_FRAME_TIMEOUT    2
 
 /*****************************************************************************/
 
@@ -115,7 +109,6 @@ static const unsigned char sensor_urb_skeleton[] = {
        0x13, M5602_XB_I2C_CTRL, 0x81, 0x11
 };
 
-/* m5602 device descriptor, currently it just wraps the m5602_camera struct */
 struct sd {
        struct gspca_dev gspca_dev;
 
@@ -140,4 +133,10 @@ int m5602_read_bridge(
 int m5602_write_bridge(
        struct sd *sd, u8 address, u8 i2c_data);
 
+int m5602_write_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len);
+
+int m5602_read_sensor(struct sd *sd, const u8 address,
+                     u8 *i2c_data, const u8 len);
+
 #endif
index fd6ce384b487a224b586415502086c38a44f3c0e..ed906fe31287d4350fe16f1b860b966187ed30f3 100644 (file)
@@ -24,7 +24,7 @@
 
 /* Kernel module parameters */
 int force_sensor;
-int dump_bridge;
+static int dump_bridge;
 int dump_sensor;
 
 static const __devinitdata struct usb_device_id m5602_table[] = {
@@ -80,6 +80,97 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
        return (err < 0) ? err : 0;
 }
 
+int m5602_read_sensor(struct sd *sd, const u8 address,
+                      u8 *i2c_data, const u8 len)
+{
+       int err, i;
+
+       if (!len || len > sd->sensor->i2c_regW)
+               return -EINVAL;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
+       } while ((*i2c_data & I2C_BUSY) && !err);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
+                                sd->sensor->i2c_slave_id);
+       if (err < 0)
+               goto out;
+
+       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
+       if (err < 0)
+               goto out;
+
+       if (sd->sensor->i2c_regW == 1) {
+               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len);
+               if (err < 0)
+                       goto out;
+
+               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
+               if (err < 0)
+                       goto out;
+       } else {
+               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
+               if (err < 0)
+                       goto out;
+       }
+
+       for (i = 0; (i < len) && !err; i++) {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
+
+               PDEBUG(D_CONF, "Reading sensor register "
+                              "0x%x containing 0x%x ", address, *i2c_data);
+       }
+out:
+       return err;
+}
+
+int m5602_write_sensor(struct sd *sd, const u8 address,
+                       u8 *i2c_data, const u8 len)
+{
+       int err, i;
+       u8 *p;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       /* No sensor with a data width larger than 16 bits has yet been seen */
+       if (len > sd->sensor->i2c_regW || !len)
+               return -EINVAL;
+
+       memcpy(buf, sensor_urb_skeleton,
+              sizeof(sensor_urb_skeleton));
+
+       buf[11] = sd->sensor->i2c_slave_id;
+       buf[15] = address;
+
+       /* Special case larger sensor writes */
+       p = buf + 16;
+
+       /* Copy a four byte write sequence for each byte to be written to */
+       for (i = 0; i < len; i++) {
+               memcpy(p, sensor_urb_skeleton + 16, 4);
+               p[3] = i2c_data[i];
+               p += 4;
+               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
+                      address, i2c_data[i]);
+       }
+
+       /* Copy the tailer */
+       memcpy(p, sensor_urb_skeleton + 20, 4);
+
+       /* Set the total length */
+       p[3] = 0x10 + len;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x19,
+                             0x0000, buf,
+                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+
+       return (err < 0) ? err : 0;
+}
+
 /* Dump all the registers of the m5602 bridge,
    unfortunately this breaks the camera until it's power cycled */
 static void m5602_dump_bridge(struct sd *sd)
@@ -150,11 +241,15 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev)
 
        /* Send start command to the camera */
        const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
+
+       if (sd->sensor->start)
+               sd->sensor->start(sd);
+
        memcpy(buf, buffer, sizeof(buffer));
        err = usb_control_msg(gspca_dev->dev,
                              usb_sndctrlpipe(gspca_dev->dev, 0),
                              0x04, 0x40, 0x19, 0x0000, buf,
-                             4, M5602_URB_MSG_TIMEOUT);
+                             sizeof(buffer), M5602_URB_MSG_TIMEOUT);
 
        PDEBUG(D_STREAM, "Transfer started");
        return (err < 0) ? err : 0;
@@ -284,6 +379,7 @@ static int __init mod_m5602_init(void)
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
+
 static void __exit mod_m5602_exit(void)
 {
        usb_deregister(&sd_driver);
index fb700c2d055acf4775cd00c5ccb889a08170f7e7..c0e71c33145433a80437a44ec0e7adc6659c3449 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "m5602_mt9m111.h"
 
+static void mt9m111_dump_registers(struct sd *sd);
+
 int mt9m111_probe(struct sd *sd)
 {
        u8 data[2] = {0x00, 0x00};
@@ -44,12 +46,12 @@ int mt9m111_probe(struct sd *sd)
                } else {
                        data[0] = preinit_mt9m111[i][2];
                        data[1] = preinit_mt9m111[i][3];
-                       mt9m111_write_sensor(sd,
+                       m5602_write_sensor(sd,
                                preinit_mt9m111[i][1], data, 2);
                }
        }
 
-       if (mt9m111_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
+       if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
                return -ENODEV;
 
        if ((data[0] == 0x14) && (data[1] == 0x3a)) {
@@ -72,7 +74,7 @@ int mt9m111_init(struct sd *sd)
        int i, err = 0;
 
        /* Init the sensor */
-       for (i = 0; i < ARRAY_SIZE(init_mt9m111); i++) {
+       for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
                u8 data[2];
 
                if (init_mt9m111[i][0] == BRIDGE) {
@@ -82,7 +84,7 @@ int mt9m111_init(struct sd *sd)
                } else {
                        data[0] = init_mt9m111[i][2];
                        data[1] = init_mt9m111[i][3];
-                       err = mt9m111_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                init_mt9m111[i][1], data, 2);
                }
        }
@@ -104,12 +106,12 @@ int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                  data, 2);
        *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -121,19 +123,19 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
 
        /* Set the correct page map */
-       err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+       err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
                goto out;
 
-       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
        if (err < 0)
                goto out;
 
        data[0] = (data[0] & 0xfe) | val;
-       err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+       err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                   data, 2);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -142,12 +144,12 @@ int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                  data, 2);
        *val = data[0] & MT9M111_RMB_MIRROR_COLS;
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -159,19 +161,19 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 
        /* Set the correct page map */
-       err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+       err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
                goto out;
 
-       err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
        if (err < 0)
                goto out;
 
        data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
-       err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
+       err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                        data, 2);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -180,7 +182,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = mt9m111_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
+       err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
        tmp = ((data[1] << 8) | data[0]);
 
        *val = ((tmp & (1 << 10)) * 2) |
@@ -190,7 +192,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 
        PDEBUG(D_V4L2, "Read gain %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -200,7 +202,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        /* Set the correct page map */
-       err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
+       err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
                goto out;
 
@@ -225,90 +227,13 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
               data[1], data[0]);
 
-       err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
+       err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
                                   data, 2);
 out:
-       return (err < 0) ? err : 0;
-}
-
-int mt9m111_read_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len) {
-       int err, i;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
-                                sd->sensor->i2c_slave_id);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x1a);
-       if (err < 0)
-               goto out;
-
-       for (i = 0; i < len && !err; i++) {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
-               PDEBUG(D_CONF, "Reading sensor register "
-                      "0x%x contains 0x%x ", address, *i2c_data);
-       }
-out:
-       return (err < 0) ? err : 0;
-}
-
-int mt9m111_write_sensor(struct sd *sd, const u8 address,
-                               u8 *i2c_data, const u8 len)
-{
-       int err, i;
-       u8 *p;
-       struct usb_device *udev = sd->gspca_dev.dev;
-       __u8 *buf = sd->gspca_dev.usb_buf;
-
-       /* No sensor with a data width larger
-          than 16 bits has yet been seen, nor with 0 :p*/
-       if (len > 2 || !len)
-               return -EINVAL;
-
-       memcpy(buf, sensor_urb_skeleton,
-              sizeof(sensor_urb_skeleton));
-
-       buf[11] = sd->sensor->i2c_slave_id;
-       buf[15] = address;
-
-       p = buf + 16;
-
-       /* Copy a four byte write sequence for each byte to be written to */
-       for (i = 0; i < len; i++) {
-               memcpy(p, sensor_urb_skeleton + 16, 4);
-               p[3] = i2c_data[i];
-               p += 4;
-               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
-                      address, i2c_data[i]);
-       }
-
-       /* Copy the tailer */
-       memcpy(p, sensor_urb_skeleton + 20, 4);
-
-       /* Set the total length */
-       p[3] = 0x10 + len;
-
-       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             0x04, 0x40, 0x19,
-                             0x0000, buf,
-                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
-       return (err < 0) ? err : 0;
+       return err;
 }
 
-void mt9m111_dump_registers(struct sd *sd)
+static void mt9m111_dump_registers(struct sd *sd)
 {
        u8 address, value[2] = {0x00, 0x00};
 
@@ -316,27 +241,27 @@ void mt9m111_dump_registers(struct sd *sd)
 
        info("Dumping the mt9m111 sensor core registers");
        value[1] = MT9M111_SENSOR_CORE;
-       mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+       m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
        for (address = 0; address < 0xff; address++) {
-               mt9m111_read_sensor(sd, address, value, 2);
+               m5602_read_sensor(sd, address, value, 2);
                info("register 0x%x contains 0x%x%x",
                     address, value[0], value[1]);
        }
 
        info("Dumping the mt9m111 color pipeline registers");
        value[1] = MT9M111_COLORPIPE;
-       mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+       m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
        for (address = 0; address < 0xff; address++) {
-               mt9m111_read_sensor(sd, address, value, 2);
+               m5602_read_sensor(sd, address, value, 2);
                info("register 0x%x contains 0x%x%x",
                     address, value[0], value[1]);
        }
 
        info("Dumping the mt9m111 camera control registers");
        value[1] = MT9M111_CAMERA_CONTROL;
-       mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
+       m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
        for (address = 0; address < 0xff; address++) {
-               mt9m111_read_sensor(sd, address, value, 2);
+               m5602_read_sensor(sd, address, value, 2);
                info("register 0x%x contains 0x%x%x",
                     address, value[0], value[1]);
        }
index 315209d5aeefdc679f482e34ebbeb05a807e3dac..e795ab7a36c92adf8c7baaadef3a087f63811b2b 100644 (file)
@@ -87,14 +87,6 @@ int mt9m111_probe(struct sd *sd);
 int mt9m111_init(struct sd *sd);
 int mt9m111_power_down(struct sd *sd);
 
-int mt9m111_read_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len);
-
-int mt9m111_write_sensor(struct sd *sd, const u8 address,
-                        u8 *i2c_data, const u8 len);
-
-void mt9m111_dump_registers(struct sd *sd);
-
 int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
 int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
 int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
@@ -106,14 +98,12 @@ static struct m5602_sensor mt9m111 = {
        .name = "MT9M111",
 
        .i2c_slave_id = 0xba,
+       .i2c_regW = 2,
 
        .probe = mt9m111_probe,
        .init = mt9m111_init,
        .power_down = mt9m111_power_down,
 
-       .read_sensor = mt9m111_read_sensor,
-       .write_sensor = mt9m111_write_sensor,
-
        .nctrls = 3,
        .ctrls = {
        {
@@ -1003,7 +993,7 @@ static const unsigned char init_mt9m111[][4] =
        {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, /* 639*/
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
index 837c7e47661c044aa13aad1426901e25f6fd2e36..c908a8d6970a2aad0c648bd02bcfd6241e4ef817 100644 (file)
 
 #include "m5602_ov9650.h"
 
-int ov9650_read_sensor(struct sd *sd, const u8 address,
-                     u8 *i2c_data, const u8 len)
-{
-       int err, i;
-
-       /* The ov9650 registers have a max depth of one byte */
-       if (len > 1 || !len)
-               return -EINVAL;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-
-       m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
-                          ov9650.i2c_slave_id);
-       m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
-       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
-       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
-
-       for (i = 0; i < len; i++) {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
-               PDEBUG(D_CONF, "Reading sensor register "
-                               "0x%x containing 0x%x ", address, *i2c_data);
-       }
-       return (err < 0) ? err : 0;
-}
-
-int ov9650_write_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len)
-{
-       int err, i;
-       u8 *p;
-       struct usb_device *udev = sd->gspca_dev.dev;
-       __u8 *buf = sd->gspca_dev.usb_buf;
-
-       /* The ov9650 only supports one byte writes */
-       if (len > 1 || !len)
-               return -EINVAL;
-
-       memcpy(buf, sensor_urb_skeleton,
-              sizeof(sensor_urb_skeleton));
-
-       buf[11] = sd->sensor->i2c_slave_id;
-       buf[15] = address;
-
-       /* Special case larger sensor writes */
-       p = buf + 16;
-
-       /* Copy a four byte write sequence for each byte to be written to */
-       for (i = 0; i < len; i++) {
-               memcpy(p, sensor_urb_skeleton + 16, 4);
-               p[3] = i2c_data[i];
-               p += 4;
-               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
-                      address, i2c_data[i]);
-       }
-
-       /* Copy the tailer */
-       memcpy(p, sensor_urb_skeleton + 20, 4);
-
-       /* Set the total length */
-       p[3] = 0x10 + len;
-
-       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             0x04, 0x40, 0x19,
-                             0x0000, buf,
-                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
+/* Vertically and horizontally flips the image if matched, needed for machines
+   where the sensor is mounted upside down */
+static
+    const
+       struct dmi_system_id ov9650_flip_dmi_table[] = {
+       {
+               .ident = "ASUS A6VC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+               }
+       },
+       {
+               .ident = "ASUS A6VM",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+               }
+       },
+       {
+               .ident = "ASUS A6JC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
+               }
+       },
+       {
+               .ident = "ASUS A6Ja",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
+               }
+       },
+       {
+               .ident = "ASUS A6Kt",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
+               }
+       },
+       {
+               .ident = "Alienware Aurora m9700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
+               }
+       },
+       { }
+};
 
-       return (err < 0) ? err : 0;
-}
+static void ov9650_dump_registers(struct sd *sd);
 
 int ov9650_probe(struct sd *sd)
 {
@@ -110,16 +90,16 @@ int ov9650_probe(struct sd *sd)
        for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) {
                u8 data = preinit_ov9650[i][2];
                if (preinit_ov9650[i][0] == SENSOR)
-                       ov9650_write_sensor(sd,
+                       m5602_write_sensor(sd,
                                            preinit_ov9650[i][1], &data, 1);
                else
                        m5602_write_bridge(sd, preinit_ov9650[i][1], data);
        }
 
-       if (ov9650_read_sensor(sd, OV9650_PID, &prod_id, 1))
+       if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
                return -ENODEV;
 
-       if (ov9650_read_sensor(sd, OV9650_VER, &ver_id, 1))
+       if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
                return -ENODEV;
 
        if ((prod_id == 0x96) && (ver_id == 0x52)) {
@@ -148,34 +128,90 @@ int ov9650_init(struct sd *sd)
        for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
                data = init_ov9650[i][2];
                if (init_ov9650[i][0] == SENSOR)
-                       err = ov9650_write_sensor(sd, init_ov9650[i][1],
+                       err = m5602_write_sensor(sd, init_ov9650[i][1],
                                                  &data, 1);
                else
                        err = m5602_write_bridge(sd, init_ov9650[i][1], data);
        }
 
-       if (!err && dmi_check_system(ov9650_flip_dmi_table)) {
+       if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
                info("vflip quirk active");
                data = 0x30;
-               err = ov9650_write_sensor(sd, OV9650_MVFP, &data, 1);
+               err = m5602_write_sensor(sd, OV9650_MVFP, &data, 1);
        }
+       return err;
+}
+
+int ov9650_start(struct sd *sd)
+{
+       int i, err = 0;
+       struct cam *cam = &sd->gspca_dev.cam;
 
-       return (err < 0) ? err : 0;
+       for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
+               u8 data = res_init_ov9650[i][1];
+               err = m5602_write_bridge(sd, res_init_ov9650[i][0], data);
+       }
+       if (err < 0)
+               return err;
+
+       switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
+       {
+       case 640:
+               PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+
+               for (i = 0; i < ARRAY_SIZE(VGA_ov9650) && !err; i++) {
+                       u8 data = VGA_ov9650[i][2];
+                       if (VGA_ov9650[i][0] == SENSOR)
+                               err = m5602_write_sensor(sd,
+                                       VGA_ov9650[i][1], &data, 1);
+                       else
+                               err = m5602_write_bridge(sd, VGA_ov9650[i][1], data);
+               }
+               break;
+
+       case 352:
+               PDEBUG(D_V4L2, "Configuring camera for CIF mode");
+
+               for (i = 0; i < ARRAY_SIZE(CIF_ov9650) && !err; i++) {
+                       u8 data = CIF_ov9650[i][2];
+                       if (CIF_ov9650[i][0] == SENSOR)
+                               err = m5602_write_sensor(sd,
+                                       CIF_ov9650[i][1], &data, 1);
+                       else
+                               err = m5602_write_bridge(sd, CIF_ov9650[i][1], data);
+               }
+               break;
+
+       case 320:
+               PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+
+               for (i = 0; i < ARRAY_SIZE(QVGA_ov9650) && !err; i++) {
+                       u8 data = QVGA_ov9650[i][2];
+                       if (QVGA_ov9650[i][0] == SENSOR)
+                               err = m5602_write_sensor(sd,
+                                       QVGA_ov9650[i][1], &data, 1);
+                       else
+                               err = m5602_write_bridge(sd, QVGA_ov9650[i][1], data);
+               }
+               break;
+       }
+       return err;
 }
 
 int ov9650_power_down(struct sd *sd)
 {
-       int i;
-       for (i = 0; i < ARRAY_SIZE(power_down_ov9650); i++) {
+       int i, err = 0;
+       for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) {
                u8 data = power_down_ov9650[i][2];
                if (power_down_ov9650[i][0] == SENSOR)
-                       ov9650_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                            power_down_ov9650[i][1], &data, 1);
                else
-                       m5602_write_bridge(sd, power_down_ov9650[i][1], data);
+                       err = m5602_write_bridge(sd, power_down_ov9650[i][1],
+                                                data);
        }
 
-       return 0;
+       return err;
 }
 
 int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
@@ -184,24 +220,24 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = ov9650_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
        if (err < 0)
                goto out;
        *val = i2c_data & 0x03;
 
-       err = ov9650_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
        if (err < 0)
                goto out;
        *val |= (i2c_data << 2);
 
-       err = ov9650_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
        if (err < 0)
                goto out;
        *val |= (i2c_data & 0x3f) << 10;
 
        PDEBUG(D_V4L2, "Read exposure %d", *val);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
@@ -215,24 +251,24 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 
        /* The 6 MSBs */
        i2c_data = (val >> 10) & 0x3f;
-       err = ov9650_write_sensor(sd, OV9650_AECHM,
+       err = m5602_write_sensor(sd, OV9650_AECHM,
                                  &i2c_data, 1);
        if (err < 0)
                goto out;
 
        /* The 8 middle bits */
        i2c_data = (val >> 2) & 0xff;
-       err = ov9650_write_sensor(sd, OV9650_AECH,
+       err = m5602_write_sensor(sd, OV9650_AECH,
                                  &i2c_data, 1);
        if (err < 0)
                goto out;
 
        /* The 2 LSBs */
        i2c_data = val & 0x03;
-       err = ov9650_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
 
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -241,13 +277,13 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
        *val = (i2c_data & 0x03) << 8;
 
-       err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
        *val |= i2c_data;
        PDEBUG(D_V4L2, "Read gain %d", *val);
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -259,16 +295,16 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        /* The 2 MSB */
        /* Read the OV9650_VREF register first to avoid
           corrupting the VREF high and low bits */
-       ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
        /* Mask away all uninteresting bits */
        i2c_data = ((val & 0x0300) >> 2) |
                        (i2c_data & 0x3F);
-       err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
 
        /* The 8 LSBs */
        i2c_data = val & 0xff;
-       err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
-       return (err < 0) ? err : 0;
+       err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       return err;
 }
 
 int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -277,12 +313,12 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1);
        *val = i2c_data;
 
        PDEBUG(D_V4L2, "Read red gain %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -295,9 +331,9 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
                             val & 0xff);
 
        i2c_data = val & 0xff;
-       err = ov9650_write_sensor(sd, OV9650_RED, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -306,12 +342,12 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
        *val = i2c_data;
 
        PDEBUG(D_V4L2, "Read blue gain %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -324,9 +360,9 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
               val & 0xff);
 
        i2c_data = val & 0xff;
-       err = ov9650_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -335,14 +371,14 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (dmi_check_system(ov9650_flip_dmi_table))
                *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
        else
                *val = (i2c_data & OV9650_HFLIP) >> 5;
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -352,20 +388,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
                goto out;
 
        if (dmi_check_system(ov9650_flip_dmi_table))
                i2c_data = ((i2c_data & 0xdf) |
-                               (((val ? 0 : 1) & 0x01) << 5));
+                          (((val ? 0 : 1) & 0x01) << 5));
        else
                i2c_data = ((i2c_data & 0xdf) |
-                               ((val & 0x01) << 5));
+                          ((val & 0x01) << 5));
 
-       err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -374,14 +410,14 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (dmi_check_system(ov9650_flip_dmi_table))
                *val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
        else
                *val = (i2c_data & 0x10) >> 4;
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -391,7 +427,7 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-       err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
                goto out;
 
@@ -402,9 +438,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
                i2c_data = ((i2c_data & 0xef) |
                                ((val & 0x01) << 4));
 
-       err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -413,16 +449,16 @@ int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
        if (err < 0)
                goto out;
        *val = (i2c_data & 0x03) << 8;
 
-       err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
        *val |= i2c_data;
        PDEBUG(D_V4L2, "Read gain %d", *val);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -435,22 +471,22 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 
        /* Read the OV9650_VREF register first to avoid
                corrupting the VREF high and low bits */
-       err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
        if (err < 0)
                goto out;
 
        /* Mask away all uninteresting bits */
        i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
-       err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
        if (err < 0)
                goto out;
 
        /* The 8 LSBs */
        i2c_data = val & 0xff;
-       err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
 
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -459,11 +495,11 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        *val = (i2c_data & OV9650_AWB_EN) >> 1;
        PDEBUG(D_V4L2, "Read auto white balance %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -473,14 +509,14 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        PDEBUG(D_V4L2, "Set auto white balance to %d", val);
-       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                goto out;
 
        i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
-       err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -489,11 +525,11 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        *val = (i2c_data & OV9650_AGC_EN) >> 2;
        PDEBUG(D_V4L2, "Read auto gain control %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -503,23 +539,23 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        PDEBUG(D_V4L2, "Set auto gain control to %d", val);
-       err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                goto out;
 
        i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
-       err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
+       err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
-void ov9650_dump_registers(struct sd *sd)
+static void ov9650_dump_registers(struct sd *sd)
 {
        int address;
        info("Dumping the ov9650 register state");
        for (address = 0; address < 0xa9; address++) {
                u8 value;
-               ov9650_read_sensor(sd, address, &value, 1);
+               m5602_read_sensor(sd, address, &value, 1);
                info("register 0x%x contains 0x%x",
                     address, value);
        }
@@ -531,9 +567,9 @@ void ov9650_dump_registers(struct sd *sd)
                u8 old_value, ctrl_value;
                u8 test_value[2] = {0xff, 0xff};
 
-               ov9650_read_sensor(sd, address, &old_value, 1);
-               ov9650_write_sensor(sd, address, test_value, 1);
-               ov9650_read_sensor(sd, address, &ctrl_value, 1);
+               m5602_read_sensor(sd, address, &old_value, 1);
+               m5602_write_sensor(sd, address, test_value, 1);
+               m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                if (ctrl_value == test_value[0])
                        info("register 0x%x is writeable", address);
@@ -541,6 +577,6 @@ void ov9650_dump_registers(struct sd *sd)
                        info("register 0x%x is read only", address);
 
                /* Restore original value */
-               ov9650_write_sensor(sd, address, &old_value, 1);
+               m5602_write_sensor(sd, address, &old_value, 1);
        }
 }
index 065632f0378ebd04bdd2a01d0470293d4d186cfc..f4b33b8e8daebe08a62fb67d8b151f4cdfd76f98 100644 (file)
@@ -20,7 +20,6 @@
 #define M5602_OV9650_H_
 
 #include <linux/dmi.h>
-
 #include "m5602_sensor.h"
 
 /*****************************************************************************/
@@ -36,6 +35,7 @@
 #define OV9650_PID                     0x0a
 #define OV9650_VER                     0x0b
 #define OV9650_COM3                    0x0c
+#define OV9650_COM4                    0x0d
 #define OV9650_COM5                    0x0e
 #define OV9650_COM6                    0x0f
 #define OV9650_AECH                    0x10
@@ -94,6 +94,8 @@
 
 #define OV9650_REGISTER_RESET          (1 << 7)
 #define OV9650_VGA_SELECT              (1 << 6)
+#define OV9650_CIF_SELECT              (1 << 5)
+#define OV9650_QVGA_SELECT             (1 << 4)
 #define OV9650_RGB_SELECT              (1 << 2)
 #define OV9650_RAW_RGB_SELECT          (1 << 0)
 
 #define OV9650_SYSTEM_CLK_SEL          (1 << 7)
 #define OV9650_SLAM_MODE               (1 << 4)
 
+#define OV9650_QVGA_VARIOPIXEL         (1 << 7)
+
 #define OV9650_VFLIP                   (1 << 4)
 #define OV9650_HFLIP                   (1 << 5)
 
@@ -124,15 +128,9 @@ extern int dump_sensor;
 
 int ov9650_probe(struct sd *sd);
 int ov9650_init(struct sd *sd);
+int ov9650_start(struct sd *sd);
 int ov9650_power_down(struct sd *sd);
 
-int ov9650_read_sensor(struct sd *sd, const u8 address,
-                      u8 *i2c_data, const u8 len);
-int ov9650_write_sensor(struct sd *sd, const u8 address,
-                      u8 *i2c_data, const u8 len);
-
-void ov9650_dump_registers(struct sd *sd);
-
 int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
 int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
@@ -155,11 +153,11 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
 static struct m5602_sensor ov9650 = {
        .name = "OV9650",
        .i2c_slave_id = 0x60,
+       .i2c_regW = 1,
        .probe = ov9650_probe,
        .init = ov9650_init,
+       .start = ov9650_start,
        .power_down = ov9650_power_down,
-       .read_sensor = ov9650_read_sensor,
-       .write_sensor = ov9650_write_sensor,
 
        .nctrls = 8,
        .ctrls = {
@@ -264,18 +262,38 @@ static struct m5602_sensor ov9650 = {
        }
        },
 
-       .nmodes = 1,
+       .nmodes = 3,
        .modes = {
        {
-               M5602_DEFAULT_FRAME_WIDTH,
-               M5602_DEFAULT_FRAME_HEIGHT,
+               320,
+               240,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       320 * 240,
+               .bytesperline = 320,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }, {
+               352,
+               288,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       352 * 288,
+               .bytesperline = 352,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }, {
+               640,
+               480,
                V4L2_PIX_FMT_SBGGR8,
                V4L2_FIELD_NONE,
                .sizeimage =
-                       M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
-               .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
+                       640 * 480,
+               .bytesperline = 640,
                .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 1
+               .priv = 0
        }
        }
 };
@@ -324,6 +342,7 @@ static const unsigned char init_ov9650[][3] =
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
+
        /* Reset chip */
        {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
        /* Enable double clock */
@@ -331,8 +350,6 @@ static const unsigned char init_ov9650[][3] =
        /* Do something out of spec with the power */
        {SENSOR, OV9650_OFON, 0x40},
 
-       /* Set QQVGA */
-       {SENSOR, OV9650_COM1, 0x20},
        /* Set fast AGC/AEC algorithm with unlimited step size */
        {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
                              OV9650_AEC_UNLIM_STEP_SIZE |
@@ -343,7 +360,7 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_ACOM38, 0x81},
        /* Turn off color matrix coefficient double option */
        {SENSOR, OV9650_COM16, 0x00},
-               /* Enable color matrix for RGB/YUV, Delay Y channel,
+       /* Enable color matrix for RGB/YUV, Delay Y channel,
        set output Y/UV delay to 1 */
        {SENSOR, OV9650_COM13, 0x19},
        /* Enable digital BLC, Set output mode to U Y V Y */
@@ -352,7 +369,7 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_COM24, 0x00},
        /* Enable HREF and some out of spec things */
        {SENSOR, OV9650_COM12, 0x73},
-               /* Set all DBLC offset signs to positive and
+       /* Set all DBLC offset signs to positive and
        do some out of spec stuff */
        {SENSOR, OV9650_DBLC1, 0xdf},
        {SENSOR, OV9650_COM21, 0x06},
@@ -364,7 +381,7 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_RSVD96, 0x04},
        /* Enable full range output */
        {SENSOR, OV9650_COM15, 0x0},
-               /* Enable HREF at optical black, enable ADBLC bias,
+       /* Enable HREF at optical black, enable ADBLC bias,
        enable ADBLC, reset timings at format change */
        {SENSOR, OV9650_COM6, 0x4b},
        /* Subtract 32 from the B channel bias */
@@ -385,7 +402,7 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_AEB, 0x5c},
        /* Set the high and low limit nibbles to 3 */
        {SENSOR, OV9650_VPT, 0xc3},
-               /* Set the Automatic Gain Ceiling (AGC) to 128x,
+       /* Set the Automatic Gain Ceiling (AGC) to 128x,
        drop VSYNC at frame drop,
        limit exposure timing,
        drop frame when the AEC step is larger than the exposure gap */
@@ -394,9 +411,9 @@ static const unsigned char init_ov9650[][3] =
        and set PWDN to SLVS (slave mode vertical sync) */
        {SENSOR, OV9650_COM10, 0x42},
        /* Set horizontal column start high to default value */
-       {SENSOR, OV9650_HSTART, 0x1a},
+       {SENSOR, OV9650_HSTART, 0x1a}, /* 210 */
        /* Set horizontal column end */
-       {SENSOR, OV9650_HSTOP, 0xbf},
+       {SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */
        /* Complementing register to the two writes above */
        {SENSOR, OV9650_HREF, 0xb2},
        /* Set vertical row start high bits */
@@ -405,10 +422,6 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_VSTOP, 0x7e},
        /* Set complementing vertical frame control */
        {SENSOR, OV9650_VREF, 0x10},
-       /* Set raw RGB output format with VGA resolution */
-       {SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
-                             OV9650_RGB_SELECT |
-                             OV9650_RAW_RGB_SELECT},
        {SENSOR, OV9650_ADC, 0x04},
        {SENSOR, OV9650_HV, 0x40},
        /* Enable denoise, and white-pixel erase */
@@ -417,30 +430,15 @@ static const unsigned char init_ov9650[][3] =
        /* Set the high bits of the exposure value */
        {SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)},
 
+       /* Enable VARIOPIXEL */
+       {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
+       {SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL},
+
        /* Set the low bits of the exposure value */
        {SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)},
        {SENSOR, OV9650_GAIN, GAIN_DEFAULT},
        {SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT},
        {SENSOR, OV9650_RED, RED_GAIN_DEFAULT},
-
-       {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
-       {SENSOR, OV9650_COM5, OV9650_SYSTEM_CLK_SEL},
-
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x5e},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0xde}
 };
 
 static const unsigned char power_down_ov9650[][3] =
@@ -460,43 +458,76 @@ static const unsigned char power_down_ov9650[][3] =
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x06},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
 };
 
-/* Vertically and horizontally flips the image if matched, needed for machines
-   where the sensor is mounted upside down */
-static
-    const
-       struct dmi_system_id ov9650_flip_dmi_table[] = {
-       {
-               .ident = "ASUS A6VC",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
-               }
-       },
-       {
-               .ident = "ASUS A6VM",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
-               }
-       },
-       {
-               .ident = "ASUS A6JC",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
-               }
-       },
-       {
-               .ident = "ASUS A6Kt",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
-               }
-       },
-       { }
+static const unsigned char res_init_ov9650[][2] =
+{
+       {M5602_XB_LINE_OF_FRAME_H, 0x82},
+       {M5602_XB_LINE_OF_FRAME_L, 0x00},
+       {M5602_XB_PIX_OF_LINE_H, 0x82},
+       {M5602_XB_PIX_OF_LINE_L, 0x00},
+       {M5602_XB_SIG_INI, 0x01}
+};
+
+static const unsigned char VGA_ov9650[][3] =
+{
+       /* Moves the view window in a vertical orientation */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, /* 640 + 98 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0xe2},
+
+       {SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
+                             OV9650_RGB_SELECT |
+                             OV9650_RAW_RGB_SELECT},
+};
+
+static const unsigned char CIF_ov9650[][3] =
+{
+       /* Moves the view window in a vertical orientation */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x20}, /* 288 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 352 + 98 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0xc2},
+
+       {SENSOR, OV9650_COM7, OV9650_CIF_SELECT |
+                             OV9650_RGB_SELECT |
+                             OV9650_RAW_RGB_SELECT},
+};
+
+static const unsigned char QVGA_ov9650[][3] =
+{
+       /* Moves the view window in a vertical orientation */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x08},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xf0}, /* 240 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x31}, /* 50 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 320 + 50 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x71},
+
+       {SENSOR, OV9650_COM7, OV9650_QVGA_SELECT |
+                             OV9650_RGB_SELECT |
+                             OV9650_RAW_RGB_SELECT},
 };
 
 #endif
index d17ac52566e68c00eb5a791bc3e29afa271510f6..2e7fb91673cfe175392fb15cc117f214beea730c 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "m5602_po1030.h"
 
+static void po1030_dump_registers(struct sd *sd);
+
 int po1030_probe(struct sd *sd)
 {
        u8 prod_id = 0, ver_id = 0, i;
@@ -38,16 +40,16 @@ int po1030_probe(struct sd *sd)
        for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
                u8 data = preinit_po1030[i][2];
                if (preinit_po1030[i][0] == SENSOR)
-                       po1030_write_sensor(sd,
+                       m5602_write_sensor(sd,
                                preinit_po1030[i][1], &data, 1);
                else
                        m5602_write_bridge(sd, preinit_po1030[i][1], data);
        }
 
-       if (po1030_read_sensor(sd, 0x3, &prod_id, 1))
+       if (m5602_read_sensor(sd, 0x3, &prod_id, 1))
                return -ENODEV;
 
-       if (po1030_read_sensor(sd, 0x4, &ver_id, 1))
+       if (m5602_read_sensor(sd, 0x4, &ver_id, 1))
                return -ENODEV;
 
        if ((prod_id == 0x02) && (ver_id == 0xef)) {
@@ -64,78 +66,12 @@ sensor_found:
        return 0;
 }
 
-int po1030_read_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len)
-{
-       int err, i;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-
-       m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
-                          sd->sensor->i2c_slave_id);
-       m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
-       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len);
-       m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
-
-       for (i = 0; i < len; i++) {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
-               PDEBUG(D_CONF, "Reading sensor register "
-                               "0x%x containing 0x%x ", address, *i2c_data);
-       }
-       return (err < 0) ? err : 0;
-}
-
-int po1030_write_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len)
-{
-       int err, i;
-       u8 *p;
-       struct usb_device *udev = sd->gspca_dev.dev;
-       __u8 *buf = sd->gspca_dev.usb_buf;
-
-       /* The po1030 only supports one byte writes */
-       if (len > 1 || !len)
-               return -EINVAL;
-
-       memcpy(buf, sensor_urb_skeleton, sizeof(sensor_urb_skeleton));
-
-       buf[11] = sd->sensor->i2c_slave_id;
-       buf[15] = address;
-
-       p = buf + 16;
-
-       /* Copy a four byte write sequence for each byte to be written to */
-       for (i = 0; i < len; i++) {
-               memcpy(p, sensor_urb_skeleton + 16, 4);
-               p[3] = i2c_data[i];
-               p += 4;
-               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
-                      address, i2c_data[i]);
-       }
-
-       /* Copy the footer */
-       memcpy(p, sensor_urb_skeleton + 20, 4);
-
-       /* Set the total length */
-       p[3] = 0x10 + len;
-
-       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             0x04, 0x40, 0x19,
-                             0x0000, buf,
-                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
-       return (err < 0) ? err : 0;
-}
-
 int po1030_init(struct sd *sd)
 {
        int i, err = 0;
 
        /* Init the sensor */
-       for (i = 0; i < ARRAY_SIZE(init_po1030); i++) {
+       for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) {
                u8 data[2] = {0x00, 0x00};
 
                switch (init_po1030[i][0]) {
@@ -147,16 +83,10 @@ int po1030_init(struct sd *sd)
 
                case SENSOR:
                        data[0] = init_po1030[i][2];
-                       err = po1030_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                init_po1030[i][1], data, 1);
                        break;
 
-               case SENSOR_LONG:
-                       data[0] = init_po1030[i][2];
-                       data[1] = init_po1030[i][3];
-                       err = po1030_write_sensor(sd,
-                               init_po1030[i][1], data, 2);
-                       break;
                default:
                        info("Invalid stream command, exiting init");
                        return -EINVAL;
@@ -166,7 +96,7 @@ int po1030_init(struct sd *sd)
        if (dump_sensor)
                po1030_dump_registers(sd);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
@@ -175,19 +105,19 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_H,
+       err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H,
                                 &i2c_data, 1);
        if (err < 0)
                goto out;
        *val = (i2c_data << 8);
 
-       err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_M,
+       err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M,
                                 &i2c_data, 1);
        *val |= i2c_data;
 
        PDEBUG(D_V4L2, "Exposure read as %d", *val);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
@@ -202,7 +132,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
               i2c_data);
 
-       err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+       err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H,
                                  &i2c_data, 1);
        if (err < 0)
                goto out;
@@ -210,11 +140,11 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        i2c_data = (val & 0xff);
        PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
               i2c_data);
-       err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+       err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M,
                                  &i2c_data, 1);
 
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -223,12 +153,12 @@ int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+       err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
                                 &i2c_data, 1);
        *val = i2c_data;
        PDEBUG(D_V4L2, "Read global gain %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -237,14 +167,14 @@ int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = po1030_read_sensor(sd, PO1030_REG_CONTROL2,
+       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2,
                                 &i2c_data, 1);
 
        *val = (i2c_data >> 7) & 0x01 ;
 
        PDEBUG(D_V4L2, "Read hflip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -254,13 +184,17 @@ int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        PDEBUG(D_V4L2, "Set hflip %d", val);
+       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+       if (err < 0)
+               goto out;
 
-       i2c_data = (val & 0x01) << 7;
+       i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
 
-       err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
-                                 &i2c_data, 1);
+       err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+                                &i2c_data, 1);
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -269,14 +203,14 @@ int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN,
+       err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
                                 &i2c_data, 1);
 
        *val = (i2c_data >> 6) & 0x01;
 
        PDEBUG(D_V4L2, "Read vflip %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -286,13 +220,17 @@ int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        PDEBUG(D_V4L2, "Set vflip %d", val);
+       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+       if (err < 0)
+               goto out;
 
-       i2c_data = (val & 0x01) << 6;
+       i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
 
-       err = po1030_write_sensor(sd, PO1030_REG_CONTROL2,
-                                 &i2c_data, 1);
+       err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+                                &i2c_data, 1);
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -303,9 +241,9 @@ int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
-       err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+       err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN,
                                  &i2c_data, 1);
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -314,11 +252,11 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN,
+       err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN,
                                 &i2c_data, 1);
        *val = i2c_data;
        PDEBUG(D_V4L2, "Read red gain %d", *val);
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -329,9 +267,9 @@ int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
-       err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN,
+       err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN,
                                  &i2c_data, 1);
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
@@ -340,12 +278,12 @@ int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
        u8 i2c_data;
        int err;
 
-       err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+       err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN,
                                 &i2c_data, 1);
        *val = i2c_data;
        PDEBUG(D_V4L2, "Read blue gain %d", *val);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -355,10 +293,10 @@ int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
        int err;
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
-       err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN,
+       err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN,
                                  &i2c_data, 1);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int po1030_power_down(struct sd *sd)
@@ -366,14 +304,14 @@ int po1030_power_down(struct sd *sd)
        return 0;
 }
 
-void po1030_dump_registers(struct sd *sd)
+static void po1030_dump_registers(struct sd *sd)
 {
        int address;
        u8 value = 0;
 
        info("Dumping the po1030 sensor core registers");
        for (address = 0; address < 0x7f; address++) {
-               po1030_read_sensor(sd, address, &value, 1);
+               m5602_read_sensor(sd, address, &value, 1);
                info("register 0x%x contains 0x%x",
                     address, value);
        }
@@ -385,9 +323,9 @@ void po1030_dump_registers(struct sd *sd)
                u8 old_value, ctrl_value;
                u8 test_value[2] = {0xff, 0xff};
 
-               po1030_read_sensor(sd, address, &old_value, 1);
-               po1030_write_sensor(sd, address, test_value, 1);
-               po1030_read_sensor(sd, address, &ctrl_value, 1);
+               m5602_read_sensor(sd, address, &old_value, 1);
+               m5602_write_sensor(sd, address, test_value, 1);
+               m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                if (ctrl_value == test_value[0])
                        info("register 0x%x is writeable", address);
@@ -395,6 +333,6 @@ void po1030_dump_registers(struct sd *sd)
                        info("register 0x%x is read only", address);
 
                /* Restore original value */
-               po1030_write_sensor(sd, address, &old_value, 1);
+               m5602_write_sensor(sd, address, &old_value, 1);
        }
 }
index a0b75ff61d797c966a1ee266f31c4e9896f8b046..def39d5bcec6a4985bce5921610073a9c3572ca4 100644 (file)
@@ -10,7 +10,7 @@
  * v4l2 interface modeled after the V4L2 driver
  * for SN9C10x PC Camera Controllers
  *
- * Register defines taken from Pascal Stangs Proxycon Armlib
+ * Register defines taken from Pascal Stangs Procyon Armlib
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -128,13 +128,6 @@ int po1030_probe(struct sd *sd);
 int po1030_init(struct sd *sd);
 int po1030_power_down(struct sd *sd);
 
-void po1030_dump_registers(struct sd *sd);
-
-int po1030_read_sensor(struct sd *sd, const u8 address,
-                             u8 *i2c_data, const u8 len);
-int po1030_write_sensor(struct sd *sd, const u8 address,
-                              u8 *i2c_data, const u8 len);
-
 int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
 int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
@@ -152,6 +145,7 @@ static struct m5602_sensor po1030 = {
        .name = "PO1030",
 
        .i2c_slave_id = 0xdc,
+       .i2c_regW = 1,
 
        .probe = po1030_probe,
        .init = po1030_init,
index 14b1eac5b812517723e79a9fa910cf061ee6c099..e564a61a72d77b15db396d1cb1c9ba7f97a58335 100644 (file)
 
 #include "m5602_s5k4aa.h"
 
+static
+    const
+       struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
+       {
+               .ident = "Fujitsu-Siemens Amilo Xa 2528",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
+               }
+       }, {
+               .ident = "Fujitsu-Siemens Amilo Xi 2550",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
+               }
+       }, {
+               .ident = "MSI GX700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
+                       DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
+               }
+       }, {
+               .ident = "MSI GX700/GX705/EX700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
+               }
+       },
+       { }
+};
+
+static void s5k4aa_dump_registers(struct sd *sd);
+
 int s5k4aa_probe(struct sd *sd)
 {
        u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -49,7 +83,7 @@ int s5k4aa_probe(struct sd *sd)
 
                case SENSOR:
                        data[0] = preinit_s5k4aa[i][2];
-                       err = s5k4aa_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                                  preinit_s5k4aa[i][1],
                                                  data, 1);
                        break;
@@ -57,7 +91,7 @@ int s5k4aa_probe(struct sd *sd)
                case SENSOR_LONG:
                        data[0] = preinit_s5k4aa[i][2];
                        data[1] = preinit_s5k4aa[i][3];
-                       err = s5k4aa_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                                  preinit_s5k4aa[i][1],
                                                  data, 2);
                        break;
@@ -68,13 +102,14 @@ int s5k4aa_probe(struct sd *sd)
        }
 
        /* Test some registers, but we don't know their exact meaning yet */
-       if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
+       if (m5602_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
                return -ENODEV;
 
        if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
                return -ENODEV;
        else
                info("Detected a s5k4aa sensor");
+
 sensor_found:
        sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
        sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
@@ -84,90 +119,6 @@ sensor_found:
        return 0;
 }
 
-int s5k4aa_read_sensor(struct sd *sd, const u8 address,
-                      u8 *i2c_data, const u8 len)
-{
-       int err, i;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
-                                sd->sensor->i2c_slave_id);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
-       if (err < 0)
-               goto out;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-       if (err < 0)
-               goto out;
-
-       for (i = 0; (i < len) & !err; i++) {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
-               PDEBUG(D_CONF, "Reading sensor register "
-                                 "0x%x containing 0x%x ", address, *i2c_data);
-       }
-out:
-       return (err < 0) ? err : 0;
-}
-
-int s5k4aa_write_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len)
-{
-       int err, i;
-       u8 *p;
-       struct usb_device *udev = sd->gspca_dev.dev;
-       __u8 *buf = sd->gspca_dev.usb_buf;
-
-       /* No sensor with a data width larger than 16 bits has yet been seen */
-       if (len > 2 || !len)
-               return -EINVAL;
-
-       memcpy(buf, sensor_urb_skeleton,
-              sizeof(sensor_urb_skeleton));
-
-       buf[11] = sd->sensor->i2c_slave_id;
-       buf[15] = address;
-
-       /* Special case larger sensor writes */
-       p = buf + 16;
-
-       /* Copy a four byte write sequence for each byte to be written to */
-       for (i = 0; i < len; i++) {
-               memcpy(p, sensor_urb_skeleton + 16, 4);
-               p[3] = i2c_data[i];
-               p += 4;
-               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
-                      address, i2c_data[i]);
-       }
-
-       /* Copy the tailer */
-       memcpy(p, sensor_urb_skeleton + 20, 4);
-
-       /* Set the total length */
-       p[3] = 0x10 + len;
-
-       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             0x04, 0x40, 0x19,
-                             0x0000, buf,
-                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
-       return (err < 0) ? err : 0;
-}
-
 int s5k4aa_init(struct sd *sd)
 {
        int i, err = 0;
@@ -184,14 +135,14 @@ int s5k4aa_init(struct sd *sd)
 
                case SENSOR:
                        data[0] = init_s5k4aa[i][2];
-                       err = s5k4aa_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                init_s5k4aa[i][1], data, 1);
                        break;
 
                case SENSOR_LONG:
                        data[0] = init_s5k4aa[i][2];
                        data[1] = init_s5k4aa[i][3];
-                       err = s5k4aa_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                init_s5k4aa[i][1], data, 2);
                        break;
                default:
@@ -206,21 +157,21 @@ int s5k4aa_init(struct sd *sd)
        if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
                u8 data = 0x02;
                info("vertical flip quirk active");
-               s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-               s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+               m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+               m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
                data |= S5K4AA_RM_V_FLIP;
                data &= ~S5K4AA_RM_H_FLIP;
-               s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+               m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
 
                /* Decrement COLSTART to preserve color order (BGGR) */
-               s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
                data--;
-               s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
 
                /* Increment ROWSTART to preserve color order (BGGR) */
-               s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
                data++;
-               s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
        }
 
        return (err < 0) ? err : 0;
@@ -237,20 +188,20 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
 
-       err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
        if (err < 0)
                goto out;
 
        *val = data << 8;
-       err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
        *val |= data;
        PDEBUG(D_V4L2, "Read exposure %d", *val);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
@@ -260,17 +211,17 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        PDEBUG(D_V4L2, "Set exposure to %d", val);
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
        data = (val >> 8) & 0xff;
-       err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
        if (err < 0)
                goto out;
        data = val & 0xff;
-       err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -279,16 +230,16 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
 
-       err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        *val = (data & S5K4AA_RM_V_FLIP) >> 7;
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -298,35 +249,35 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
-       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                goto out;
        data = ((data & ~S5K4AA_RM_V_FLIP)
                        | ((val & 0x01) << 7));
-       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                goto out;
 
        if (val) {
-               err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
                if (err < 0)
                        goto out;
 
                data++;
-               err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
        } else {
-               err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
                if (err < 0)
                        goto out;
 
                data--;
-               err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+               err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
        }
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -335,15 +286,15 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
 
-       err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        *val = (data & S5K4AA_RM_H_FLIP) >> 6;
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -354,35 +305,35 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 
        PDEBUG(D_V4L2, "Set horizontal flip to %d",
               val);
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
-       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                goto out;
 
        data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
-       err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                goto out;
 
        if (val) {
-               err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
                if (err < 0)
                        goto out;
                data++;
-               err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
                if (err < 0)
                        goto out;
        } else {
-               err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
                if (err < 0)
                        goto out;
                data--;
-               err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+               err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
        }
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -391,16 +342,16 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
 
-       err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
        *val = data;
        PDEBUG(D_V4L2, "Read gain %d", *val);
 
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -410,28 +361,28 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        int err;
 
        PDEBUG(D_V4L2, "Set gain to %d", val);
-       err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                goto out;
 
        data = val & 0xff;
-       err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
 
 out:
-       return (err < 0) ? err : 0;
+       return err;
 }
 
-void s5k4aa_dump_registers(struct sd *sd)
+static void s5k4aa_dump_registers(struct sd *sd)
 {
        int address;
        u8 page, old_page;
-       s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+       m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
        for (page = 0; page < 16; page++) {
-               s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+               m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
                info("Dumping the s5k4aa register state for page 0x%x", page);
                for (address = 0; address <= 0xff; address++) {
                        u8 value = 0;
-                       s5k4aa_read_sensor(sd, address, &value, 1);
+                       m5602_read_sensor(sd, address, &value, 1);
                        info("register 0x%x contains 0x%x",
                             address, value);
                }
@@ -439,15 +390,15 @@ void s5k4aa_dump_registers(struct sd *sd)
        info("s5k4aa register state dump complete");
 
        for (page = 0; page < 16; page++) {
-               s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
+               m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
                info("Probing for which registers that are "
                     "read/write for page 0x%x", page);
                for (address = 0; address <= 0xff; address++) {
                        u8 old_value, ctrl_value, test_value = 0xff;
 
-                       s5k4aa_read_sensor(sd, address, &old_value, 1);
-                       s5k4aa_write_sensor(sd, address, &test_value, 1);
-                       s5k4aa_read_sensor(sd, address, &ctrl_value, 1);
+                       m5602_read_sensor(sd, address, &old_value, 1);
+                       m5602_write_sensor(sd, address, &test_value, 1);
+                       m5602_read_sensor(sd, address, &ctrl_value, 1);
 
                        if (ctrl_value == test_value)
                                info("register 0x%x is writeable", address);
@@ -455,9 +406,9 @@ void s5k4aa_dump_registers(struct sd *sd)
                                info("register 0x%x is read only", address);
 
                        /* Restore original value */
-                       s5k4aa_write_sensor(sd, address, &old_value, 1);
+                       m5602_write_sensor(sd, address, &old_value, 1);
                }
        }
        info("Read/write register probing complete");
-       s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
+       m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
 }
index eaef67655afa9cd282d010b7645ac0ee2e0dd307..1f88b0d040c4649eea1f14cae040f6930da9cf4d 100644 (file)
 #define S5K4AA_WINDOW_HEIGHT_LO                0x09
 #define S5K4AA_WINDOW_WIDTH_HI         0x0a
 #define S5K4AA_WINDOW_WIDTH_LO         0x0b
-#define S5K4AA_GLOBAL_GAIN__           0x0f /* Only a guess ATM !!! */
-#define S5K4AA_H_BLANK_HI__            0x1d /* Only a guess ATM !!! sync lost
-                                               if too low, reduces frame rate
-                                               if too high */
-#define S5K4AA_H_BLANK_LO__            0x1e /* Only a guess ATM !!! */
+#define S5K4AA_GLOBAL_GAIN__           0x0f
+/* sync lost, if too low, reduces frame rate if too high */
+#define S5K4AA_H_BLANK_HI__            0x1d
+#define S5K4AA_H_BLANK_LO__            0x1e
 #define S5K4AA_EXPOSURE_HI             0x17
 #define S5K4AA_EXPOSURE_LO             0x18
 #define S5K4AA_GAIN_1                  0x1f /* (digital?) gain : 5 bits */
@@ -68,13 +67,6 @@ int s5k4aa_probe(struct sd *sd);
 int s5k4aa_init(struct sd *sd);
 int s5k4aa_power_down(struct sd *sd);
 
-void s5k4aa_dump_registers(struct sd *sd);
-
-int s5k4aa_read_sensor(struct sd *sd, const u8 address,
-                      u8 *i2c_data, const u8 len);
-int s5k4aa_write_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len);
-
 int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
 int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
@@ -89,9 +81,8 @@ static struct m5602_sensor s5k4aa = {
        .probe = s5k4aa_probe,
        .init = s5k4aa_init,
        .power_down = s5k4aa_power_down,
-       .read_sensor = s5k4aa_read_sensor,
-       .write_sensor = s5k4aa_write_sensor,
        .i2c_slave_id = 0x5a,
+       .i2c_regW = 2,
        .nctrls = 4,
        .ctrls = {
        {
@@ -338,32 +329,4 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
 };
 
-static
-    const
-       struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
-       {
-               .ident = "Fujitsu-Siemens Amilo Xa 2528",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
-               }
-       },
-       {
-               .ident = "Fujitsu-Siemens Amilo Xi 2550",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
-               }
-       },
-               {
-               .ident = "MSI GX700",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
-                       DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
-               }
-       },
-       { }
-};
-
 #endif
index 8988a728e0b400dbeb395b2ac78a53d6869b1f4f..af3f2dc2c70263452d3351194646fd0fa0cdb291 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "m5602_s5k83a.h"
 
+static void s5k83a_dump_registers(struct sd *sd);
+
 int s5k83a_probe(struct sd *sd)
 {
        u8 prod_id = 0, ver_id = 0;
@@ -39,7 +41,7 @@ int s5k83a_probe(struct sd *sd)
        for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
                u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
                if (preinit_s5k83a[i][0] == SENSOR)
-                       err = s5k83a_write_sensor(sd, preinit_s5k83a[i][1],
+                       err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
                                data, 2);
                else
                        err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
@@ -49,10 +51,10 @@ int s5k83a_probe(struct sd *sd)
        /* We don't know what register (if any) that contain the product id
         * Just pick the first addresses that seem to produce the same results
         * on multiple machines */
-       if (s5k83a_read_sensor(sd, 0x00, &prod_id, 1))
+       if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
                return -ENODEV;
 
-       if (s5k83a_read_sensor(sd, 0x01, &ver_id, 1))
+       if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
                return -ENODEV;
 
        if ((prod_id == 0xff) || (ver_id == 0xff))
@@ -68,91 +70,6 @@ sensor_found:
        return 0;
 }
 
-int s5k83a_read_sensor(struct sd *sd, const u8 address,
-                             u8 *i2c_data, const u8 len)
-{
-       int err, i;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
-                                sd->sensor->i2c_slave_id);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
-       if (err < 0)
-               goto out;
-
-       err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
-       if (err < 0)
-               goto out;
-
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
-
-       if (err < 0)
-               goto out;
-       for (i = 0; i < len && !len; i++) {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
-
-               PDEBUG(D_CONF, "Reading sensor register "
-                                 "0x%x containing 0x%x ", address, *i2c_data);
-       }
-
-out:
-       return (err < 0) ? err : 0;
-}
-
-int s5k83a_write_sensor(struct sd *sd, const u8 address,
-                              u8 *i2c_data, const u8 len)
-{
-       int err, i;
-       u8 *p;
-       struct usb_device *udev = sd->gspca_dev.dev;
-       __u8 *buf = sd->gspca_dev.usb_buf;
-
-       /* No sensor with a data width larger than 16 bits has yet been seen */
-       if (len > 2 || !len)
-               return -EINVAL;
-
-       memcpy(buf, sensor_urb_skeleton,
-              sizeof(sensor_urb_skeleton));
-
-       buf[11] = sd->sensor->i2c_slave_id;
-       buf[15] = address;
-
-       /* Special case larger sensor writes */
-       p = buf + 16;
-
-       /* Copy a four byte write sequence for each byte to be written to */
-       for (i = 0; i < len; i++) {
-               memcpy(p, sensor_urb_skeleton + 16, 4);
-               p[3] = i2c_data[i];
-               p += 4;
-               PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
-                      address, i2c_data[i]);
-       }
-
-       /* Copy the tailer */
-       memcpy(p, sensor_urb_skeleton + 20, 4);
-
-       /* Set the total length */
-       p[3] = 0x10 + len;
-
-       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             0x04, 0x40, 0x19,
-                             0x0000, buf,
-                             20 + len * 4, M5602_URB_MSG_TIMEOUT);
-
-       return (err < 0) ? err : 0;
-}
-
 int s5k83a_init(struct sd *sd)
 {
        int i, err = 0;
@@ -169,14 +86,14 @@ int s5k83a_init(struct sd *sd)
 
                case SENSOR:
                        data[0] = init_s5k83a[i][2];
-                       err = s5k83a_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                init_s5k83a[i][1], data, 1);
                        break;
 
                case SENSOR_LONG:
                        data[0] = init_s5k83a[i][2];
                        data[1] = init_s5k83a[i][3];
-                       err = s5k83a_write_sensor(sd,
+                       err = m5602_write_sensor(sd,
                                init_s5k83a[i][1], data, 2);
                        break;
                default:
@@ -200,14 +117,14 @@ void s5k83a_dump_registers(struct sd *sd)
 {
        int address;
        u8 page, old_page;
-       s5k83a_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+       m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 
        for (page = 0; page < 16; page++) {
-               s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
                info("Dumping the s5k83a register state for page 0x%x", page);
                for (address = 0; address <= 0xff; address++) {
                        u8 val = 0;
-                       s5k83a_read_sensor(sd, address, &val, 1);
+                       m5602_read_sensor(sd, address, &val, 1);
                        info("register 0x%x contains 0x%x",
                             address, val);
                }
@@ -215,15 +132,15 @@ void s5k83a_dump_registers(struct sd *sd)
        info("s5k83a register state dump complete");
 
        for (page = 0; page < 16; page++) {
-               s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
                info("Probing for which registers that are read/write "
                      "for page 0x%x", page);
                for (address = 0; address <= 0xff; address++) {
                        u8 old_val, ctrl_val, test_val = 0xff;
 
-                       s5k83a_read_sensor(sd, address, &old_val, 1);
-                       s5k83a_write_sensor(sd, address, &test_val, 1);
-                       s5k83a_read_sensor(sd, address, &ctrl_val, 1);
+                       m5602_read_sensor(sd, address, &old_val, 1);
+                       m5602_write_sensor(sd, address, &test_val, 1);
+                       m5602_read_sensor(sd, address, &ctrl_val, 1);
 
                        if (ctrl_val == test_val)
                                info("register 0x%x is writeable", address);
@@ -231,11 +148,11 @@ void s5k83a_dump_registers(struct sd *sd)
                                info("register 0x%x is read only", address);
 
                        /* Restore original val */
-                       s5k83a_write_sensor(sd, address, &old_val, 1);
+                       m5602_write_sensor(sd, address, &old_val, 1);
                }
        }
        info("Read/write register probing complete");
-       s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+       m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 }
 
 int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -244,11 +161,15 @@ int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = s5k83a_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+       err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+       if (err < 0)
+               goto out;
+
        data[1] = data[1] << 1;
        *val = data[1];
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -259,23 +180,24 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 
        data[0] = 0x00;
        data[1] = 0x20;
-       err = s5k83a_write_sensor(sd, 0x14, data, 2);
+       err = m5602_write_sensor(sd, 0x14, data, 2);
        if (err < 0)
-               return err;
+               goto out;
 
        data[0] = 0x01;
        data[1] = 0x00;
-       err = s5k83a_write_sensor(sd, 0x0d, data, 2);
+       err = m5602_write_sensor(sd, 0x0d, data, 2);
        if (err < 0)
-               return err;
+               goto out;
 
        /* FIXME: This is not sane, we need to figure out the composition
                  of these registers */
        data[0] = val >> 3; /* brightness, high 5 bits */
        data[1] = val >> 1; /* brightness, high 7 bits */
-       err = s5k83a_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+       err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -284,10 +206,14 @@ int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data;
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = s5k83a_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
+       err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
+       if (err < 0)
+               goto out;
 
        *val = data;
-       return (err < 0) ? err : 0;
+
+out:
+       return err;
 }
 
 int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
@@ -297,9 +223,9 @@ int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        data[0] = val;
-       err = s5k83a_write_sensor(sd, S5K83A_WHITENESS, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1);
 
-       return (err < 0) ? err : 0;
+       return err;
 }
 
 int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
@@ -308,7 +234,9 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
 
-       err = s5k83a_read_sensor(sd, S5K83A_GAIN, data, 2);
+       err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2);
+       if (err < 0)
+               goto out;
 
        data[1] = data[1] & 0x3f;
        if (data[1] > S5K83A_MAXIMUM_GAIN)
@@ -316,7 +244,8 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 
        *val = data[1];
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -327,9 +256,8 @@ int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 
        data[0] = 0;
        data[1] = val;
-       err = s5k83a_write_sensor(sd, S5K83A_GAIN, data, 2);
-
-       return (err < 0) ? err : 0;
+       err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
+       return err;
 }
 
 int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -339,14 +267,15 @@ int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        data[0] = 0x05;
-       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
-       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
        *val = (data[0] | 0x40) ? 1 : 0;
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -356,25 +285,26 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        data[0] = 0x05;
-       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
-       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
        /* set or zero six bit, seven is hflip */
        data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
                        : (data[0] & 0x80) | S5K83A_FLIP_MASK;
-       err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
        data[0] = (val) ? 0x0b : 0x0a;
-       err = s5k83a_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -384,14 +314,15 @@ int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        data[0] = 0x05;
-       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
-       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
        *val = (data[0] | 0x80) ? 1 : 0;
 
-       return (err < 0) ? err : 0;
+out:
+       return err;
 }
 
 int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -401,23 +332,23 @@ int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        data[0] = 0x05;
-       err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
-       err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1);
+       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
        /* set or zero seven bit, six is vflip */
        data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
                        : (data[0] & 0x40) | S5K83A_FLIP_MASK;
-       err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1);
+       err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
        if (err < 0)
-               return err;
+               goto out;
 
        data[0] = (val) ? 0x0a : 0x0b;
-       err = s5k83a_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
-
-       return (err < 0) ? err : 0;
+       err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
+out:
+       return err;
 }
index ee3ee9cfca1d96083283ba16a5723f2ce7c46349..05ccb5b57a88578108884a06c42a1e52d12216fb 100644 (file)
 #include "m5602_sensor.h"
 
 #define S5K83A_FLIP                            0x01
-#define S5K83A_HFLIP_TUNE              0x03
-#define S5K83A_VFLIP_TUNE              0x05
-#define S5K83A_WHITENESS               0x0a
+#define S5K83A_HFLIP_TUNE                      0x03
+#define S5K83A_VFLIP_TUNE                      0x05
+#define S5K83A_WHITENESS                       0x0a
 #define S5K83A_GAIN                            0x18
-#define S5K83A_BRIGHTNESS              0x1b
-#define S5K83A_PAGE_MAP                        0xec
+#define S5K83A_BRIGHTNESS                      0x1b
+#define S5K83A_PAGE_MAP                                0xec
 
-#define S5K83A_DEFAULT_BRIGHTNESS      0x71
-#define S5K83A_DEFAULT_WHITENESS       0x7e
+#define S5K83A_DEFAULT_BRIGHTNESS              0x71
+#define S5K83A_DEFAULT_WHITENESS               0x7e
 #define S5K83A_DEFAULT_GAIN                    0x00
 #define S5K83A_MAXIMUM_GAIN                    0x3c
 #define S5K83A_FLIP_MASK                       0x10
@@ -46,13 +46,6 @@ int s5k83a_probe(struct sd *sd);
 int s5k83a_init(struct sd *sd);
 int s5k83a_power_down(struct sd *sd);
 
-void s5k83a_dump_registers(struct sd *sd);
-
-int s5k83a_read_sensor(struct sd *sd, const u8 address,
-                      u8 *i2c_data, const u8 len);
-int s5k83a_write_sensor(struct sd *sd, const u8 address,
-                       u8 *i2c_data, const u8 len);
-
 int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
 int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
 int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
@@ -64,15 +57,13 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
 int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
 int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
 
-
 static struct m5602_sensor s5k83a = {
        .name = "S5K83A",
        .probe = s5k83a_probe,
        .init = s5k83a_init,
        .power_down = s5k83a_power_down,
-       .read_sensor = s5k83a_read_sensor,
-       .write_sensor = s5k83a_write_sensor,
        .i2c_slave_id = 0x5a,
+       .i2c_regW = 2,
        .nctrls = 5,
        .ctrls = {
        {
index 60c9a48e0c0291cb478c3d51d60e6608438fb6a1..261623f0da4818c220e21f2a0fa052648ac11ba3 100644 (file)
@@ -49,23 +49,21 @@ struct m5602_sensor {
        /* What i2c address the sensor is connected to */
        u8 i2c_slave_id;
 
+       /* Width of each i2c register (in bytes) */
+       u8 i2c_regW;
+
        /* Probes if the sensor is connected */
        int (*probe)(struct sd *sd);
 
        /* Performs a initialization sequence */
        int (*init)(struct sd *sd);
 
+       /* Executed when the camera starts to send data */
+       int (*start)(struct sd *sd);
+
        /* Performs a power down sequence */
        int (*power_down)(struct sd *sd);
 
-       /* Reads a sensor register */
-       int (*read_sensor)(struct sd *sd, const u8 address,
-             u8 *i2c_data, const u8 len);
-
-       /* Writes to a sensor register */
-       int (*write_sensor)(struct sd *sd, const u8 address,
-             u8 *i2c_data, const u8 len);
-
        int nctrls;
        struct ctrl ctrls[M5602_MAX_CTRLS];
 
index 277ca34a881775cf8ee72a7801bb4202e2864f5c..3d2090e67a633046417738ce1e14b4d6ec451295 100644 (file)
@@ -39,7 +39,7 @@ struct sd {
 static struct ctrl sd_ctrls[] = {
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 589,
@@ -123,7 +123,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam = &gspca_dev->cam;
        cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
-       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       cam->nmodes = ARRAY_SIZE(vga_mode);
        sd->qindex = 1;                 /* set the quantization table */
        return 0;
 }
index ca671194679e3adef083dbbe3f3e20df8956ebf2..ee232956c812523aa050fa77d7f129b257f3db79 100644 (file)
@@ -3,7 +3,18 @@
  *
  * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
  *
- * (This module is adapted from the ov51x-jpeg package)
+ * This module is adapted from the ov51x-jpeg package, which itself
+ * was adapted from the ov511 driver.
+ *
+ * Original copyright for the ov511 driver is:
+ *
+ * Copyright (c) 1999-2004 Mark W. McClelland
+ * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach
+ *
+ * ov51x-jpeg original copyright is:
+ *
+ * Copyright (c) 2004-2007 Romain Beauxis <toots@rastageeks.org>
+ * Support for OV7670 sensors was contributed by Sam Skipsey <aoanla@yahoo.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
@@ -40,22 +51,18 @@ struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
        /* Determined by sensor type */
-       char sif;
-
-       unsigned char primary_i2c_slave;        /* I2C write id of sensor */
+       __u8 sif;
 
-       unsigned char brightness;
-       unsigned char contrast;
-       unsigned char colors;
+       __u8 brightness;
+       __u8 contrast;
+       __u8 colors;
        __u8 hflip;
        __u8 vflip;
 
-       char compress;          /* Should the next frame be compressed? */
-       char compress_inited;   /* Are compression params uploaded? */
-       char stopped;           /* Streaming is temporarily paused */
+       __u8 stopped;           /* Streaming is temporarily paused */
 
-       char frame_rate;        /* current Framerate (OV519 only) */
-       char clockdiv;          /* clockdiv override for OV519 only */
+       __u8 frame_rate;        /* current Framerate (OV519 only) */
+       __u8 clockdiv;          /* clockdiv override for OV519 only */
 
        char sensor;            /* Type of image sensor chip (SEN_*) */
 #define SEN_UNKNOWN 0
@@ -67,7 +74,6 @@ struct sd {
 #define SEN_OV7670 6
 #define SEN_OV76BE 7
 #define SEN_OV8610 8
-
 };
 
 /* V4L2 controls supported by the driver */
@@ -158,7 +164,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -170,7 +176,7 @@ static struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -184,15 +190,15 @@ static struct v4l2_pix_format sif_mode[] = {
 };
 
 /* OV519 Camera interface register numbers */
-#define OV519_CAM_H_SIZE               0x10
-#define OV519_CAM_V_SIZE               0x11
-#define OV519_CAM_X_OFFSETL            0x12
-#define OV519_CAM_X_OFFSETH            0x13
-#define OV519_CAM_Y_OFFSETL            0x14
-#define OV519_CAM_Y_OFFSETH            0x15
-#define OV519_CAM_DIVIDER              0x16
-#define OV519_CAM_DFR                  0x20
-#define OV519_CAM_FORMAT               0x25
+#define OV519_R10_H_SIZE               0x10
+#define OV519_R11_V_SIZE               0x11
+#define OV519_R12_X_OFFSETL            0x12
+#define OV519_R13_X_OFFSETH            0x13
+#define OV519_R14_Y_OFFSETL            0x14
+#define OV519_R15_Y_OFFSETH            0x15
+#define OV519_R16_DIVIDER              0x16
+#define OV519_R20_DFR                  0x20
+#define OV519_R25_FORMAT               0x25
 
 /* OV519 System Controller register numbers */
 #define OV519_SYS_RESET1 0x51
@@ -562,8 +568,8 @@ static const struct ov_i2c_regvals norm_7670[] = {
        { OV7670_REG_VSTOP, 0x7a },
        { OV7670_REG_VREF, 0x0a },
 
-       { OV7670_REG_COM3, 0 },
-       { OV7670_REG_COM14, 0 },
+       { OV7670_REG_COM3, 0x00 },
+       { OV7670_REG_COM14, 0x00 },
 /* Mystery scaling numbers */
        { 0x70, 0x3a },
        { 0x71, 0x35 },
@@ -595,8 +601,8 @@ static const struct ov_i2c_regvals norm_7670[] = {
        { OV7670_REG_COM8, OV7670_COM8_FASTAEC
                         | OV7670_COM8_AECSTEP
                         | OV7670_COM8_BFILT },
-       { OV7670_REG_GAIN, 0 },
-       { OV7670_REG_AECH, 0 },
+       { OV7670_REG_GAIN, 0x00 },
+       { OV7670_REG_AECH, 0x00 },
        { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
        { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
        { OV7670_REG_BD50MAX, 0x05 },
@@ -634,16 +640,16 @@ static const struct ov_i2c_regvals norm_7670[] = {
        { OV7670_REG_COM12, 0x78 },
        { 0x4d, 0x40 },
        { 0x4e, 0x20 },
-       { OV7670_REG_GFIX, 0 },
+       { OV7670_REG_GFIX, 0x00 },
        { 0x6b, 0x4a },
        { 0x74, 0x10 },
        { 0x8d, 0x4f },
-       { 0x8e, 0 },
-       { 0x8f, 0 },
-       { 0x90, 0 },
-       { 0x91, 0 },
-       { 0x96, 0 },
-       { 0x9a, 0 },
+       { 0x8e, 0x00 },
+       { 0x8f, 0x00 },
+       { 0x90, 0x00 },
+       { 0x91, 0x00 },
+       { 0x96, 0x00 },
+       { 0x9a, 0x00 },
        { 0xb0, 0x84 },
        { 0xb1, 0x0c },
        { 0xb2, 0x0e },
@@ -681,17 +687,17 @@ static const struct ov_i2c_regvals norm_7670[] = {
 /* Matrix coefficients */
        { 0x4f, 0x80 },
        { 0x50, 0x80 },
-       { 0x51, 0 },
+       { 0x51, 0x00 },
        { 0x52, 0x22 },
        { 0x53, 0x5e },
        { 0x54, 0x80 },
        { 0x58, 0x9e },
 
        { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
-       { OV7670_REG_EDGE, 0 },
+       { OV7670_REG_EDGE, 0x00 },
        { 0x75, 0x05 },
        { 0x76, 0xe1 },
-       { 0x4c, 0 },
+       { 0x4c, 0x00 },
        { 0x77, 0x01 },
        { OV7670_REG_COM13, OV7670_COM13_GAMMA
                          | OV7670_COM13_UVSAT
@@ -704,7 +710,7 @@ static const struct ov_i2c_regvals norm_7670[] = {
        { 0x34, 0x11 },
        { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
        { 0xa4, 0x88 },
-       { 0x96, 0 },
+       { 0x96, 0x00 },
        { 0x97, 0x30 },
        { 0x98, 0x20 },
        { 0x99, 0x30 },
@@ -942,11 +948,11 @@ static int i2c_w(struct sd *sd,
 
        /* Initiate 3-byte write cycle */
        rc = reg_w(sd, R518_I2C_CTL, 0x01);
+       if (rc < 0)
+               return rc;
 
        /* wait for write complete */
        msleep(4);
-       if (rc < 0)
-               return rc;
        return reg_r8(sd, R518_I2C_CTL);
 }
 
@@ -1029,7 +1035,7 @@ static inline int ov51x_restart(struct sd *sd)
  */
 static int init_ov_sensor(struct sd *sd)
 {
-       int i, success;
+       int i;
 
        /* Reset the sensor */
        if (i2c_w(sd, 0x12, 0x80) < 0)
@@ -1038,11 +1044,11 @@ static int init_ov_sensor(struct sd *sd)
        /* Wait for it to initialize */
        msleep(150);
 
-       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+       for (i = 0; i < i2c_detect_tries; i++) {
                if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
                    i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
-                       success = 1;
-                       continue;
+                       PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);
+                       return 0;
                }
 
                /* Reset the sensor */
@@ -1054,10 +1060,7 @@ static int init_ov_sensor(struct sd *sd)
                if (i2c_r(sd, 0x00) < 0)
                        return -EIO;
        }
-       if (!success)
-               return -EIO;
-       PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i);
-       return 0;
+       return -EIO;
 }
 
 /* Set the read and write slave IDs. The "slave" argument is the write slave,
@@ -1073,7 +1076,6 @@ static int ov51x_set_slave_ids(struct sd *sd,
        rc = reg_w(sd, R51x_I2C_W_SID, slave);
        if (rc < 0)
                return rc;
-       sd->primary_i2c_slave = slave;
        return reg_w(sd, R51x_I2C_R_SID, slave + 1);
 }
 
@@ -1285,7 +1287,6 @@ static int ov6xx0_configure(struct sd *sd)
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
 static void ov51x_led_control(struct sd *sd, int on)
 {
-/*     PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */
        reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
 }
 
@@ -1352,7 +1353,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        }
                        if (ov8xx0_configure(sd) < 0) {
                                PDEBUG(D_ERR,
-                                  "Failed to configure OV8xx0 sensor");
+                                       "Failed to configure OV8xx0 sensor");
                                goto error;
                        }
                }
@@ -1482,7 +1483,7 @@ static int ov519_mode_init_regs(struct sd *sd)
                        return -EIO;
                if (sd->sensor == SEN_OV7640) {
                        /* Select 8-bit input mode */
-                       reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10);
+                       reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
                }
        } else {
                if (write_regvals(sd, mode_init_519_ov7670,
@@ -1490,14 +1491,14 @@ static int ov519_mode_init_regs(struct sd *sd)
                        return -EIO;
        }
 
-       reg_w(sd, OV519_CAM_H_SIZE,     sd->gspca_dev.width >> 4);
-       reg_w(sd, OV519_CAM_V_SIZE,     sd->gspca_dev.height >> 3);
-       reg_w(sd, OV519_CAM_X_OFFSETL,  0x00);
-       reg_w(sd, OV519_CAM_X_OFFSETH,  0x00);
-       reg_w(sd, OV519_CAM_Y_OFFSETL,  0x00);
-       reg_w(sd, OV519_CAM_Y_OFFSETH,  0x00);
-       reg_w(sd, OV519_CAM_DIVIDER,    0x00);
-       reg_w(sd, OV519_CAM_FORMAT,     0x03); /* YUV422 */
+       reg_w(sd, OV519_R10_H_SIZE,     sd->gspca_dev.width >> 4);
+       reg_w(sd, OV519_R11_V_SIZE,     sd->gspca_dev.height >> 3);
+       reg_w(sd, OV519_R12_X_OFFSETL,  0x00);
+       reg_w(sd, OV519_R13_X_OFFSETH,  0x00);
+       reg_w(sd, OV519_R14_Y_OFFSETL,  0x00);
+       reg_w(sd, OV519_R15_Y_OFFSETH,  0x00);
+       reg_w(sd, OV519_R16_DIVIDER,    0x00);
+       reg_w(sd, OV519_R25_FORMAT,     0x03); /* YUV422 */
        reg_w(sd, 0x26,                 0x00); /* Undocumented */
 
        /******** Set the framerate ********/
@@ -1509,8 +1510,8 @@ static int ov519_mode_init_regs(struct sd *sd)
        switch (sd->sensor) {
        case SEN_OV7640:
                switch (sd->frame_rate) {
-/*fixme: default was 30 fps */
-               case 30:
+               default:
+/*             case 30: */
                        reg_w(sd, 0xa4, 0x0c);
                        reg_w(sd, 0x23, 0xff);
                        break;
@@ -1522,8 +1523,7 @@ static int ov519_mode_init_regs(struct sd *sd)
                        reg_w(sd, 0xa4, 0x0c);
                        reg_w(sd, 0x23, 0x1b);
                        break;
-               default:
-/*             case 15: */
+               case 15:
                        reg_w(sd, 0xa4, 0x04);
                        reg_w(sd, 0x23, 0xff);
                        sd->clockdiv = 1;
@@ -1576,7 +1576,6 @@ static int ov519_mode_init_regs(struct sd *sd)
                }
                break;
        }
-
        return 0;
 }
 
@@ -1667,7 +1666,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
                 * the gain or the contrast. The "reserved" bits seem
                 * to have some effect in this case. */
                i2c_w(sd, 0x2d, 0x85);
-       } else if (sd->clockdiv >= 0) {
+       } else {
                i2c_w(sd, 0x11, sd->clockdiv);
        }
 
@@ -1869,7 +1868,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        ret = ov51x_restart(sd);
        if (ret < 0)
                goto out;
-       PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
        ov51x_led_control(sd, 1);
        return 0;
 out:
@@ -1879,8 +1877,10 @@ out:
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       ov51x_stop((struct sd *) gspca_dev);
-       ov51x_led_control((struct sd *) gspca_dev, 0);
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       ov51x_stop(sd);
+       ov51x_led_control(sd, 0);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -1935,9 +1935,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
        int val;
 
        val = sd->brightness;
-       PDEBUG(D_CONF, "brightness:%d", val);
-/*     if (gspca_dev->streaming)
- *             ov51x_stop(sd); */
        switch (sd->sensor) {
        case SEN_OV8610:
        case SEN_OV7610:
@@ -1959,8 +1956,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
                break;
        }
-/*     if (gspca_dev->streaming)
- *             ov51x_restart(sd); */
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1969,9 +1964,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        int val;
 
        val = sd->contrast;
-       PDEBUG(D_CONF, "contrast:%d", val);
-/*     if (gspca_dev->streaming)
-               ov51x_stop(sd); */
        switch (sd->sensor) {
        case SEN_OV7610:
        case SEN_OV6620:
@@ -2007,8 +1999,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
                break;
        }
-/*     if (gspca_dev->streaming)
-               ov51x_restart(sd); */
 }
 
 static void setcolors(struct gspca_dev *gspca_dev)
@@ -2017,9 +2007,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
        int val;
 
        val = sd->colors;
-       PDEBUG(D_CONF, "saturation:%d", val);
-/*     if (gspca_dev->streaming)
-               ov51x_stop(sd); */
        switch (sd->sensor) {
        case SEN_OV8610:
        case SEN_OV7610:
@@ -2044,8 +2031,6 @@ static void setcolors(struct gspca_dev *gspca_dev)
                /* set REG_COM13 values for UV sat auto mode */
                break;
        }
-/*     if (gspca_dev->streaming)
-               ov51x_restart(sd); */
 }
 
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -2053,7 +2038,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->brightness = val;
-       setbrightness(gspca_dev);
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
        return 0;
 }
 
@@ -2070,7 +2056,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->contrast = val;
-       setcontrast(gspca_dev);
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
        return 0;
 }
 
@@ -2087,7 +2074,8 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->colors = val;
-       setcolors(gspca_dev);
+       if (gspca_dev->streaming)
+               setcolors(gspca_dev);
        return 0;
 }
 
@@ -2104,7 +2092,8 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->hflip = val;
-       sethvflip(sd);
+       if (gspca_dev->streaming)
+               sethvflip(sd);
        return 0;
 }
 
@@ -2121,7 +2110,8 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->vflip = val;
-       sethvflip(sd);
+       if (gspca_dev->streaming)
+               sethvflip(sd);
        return 0;
 }
 
@@ -2162,7 +2152,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x05a9, 0x8519)},
        {}
 };
-#undef DVNAME
+
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
new file mode 100644 (file)
index 0000000..3bf15e4
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * ov534/ov772x gspca driver
+ * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
+ * Copyright (C) 2008 Jim Paris <jim@jtan.com>
+ *
+ * Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
+ * USB protocol reverse engineered by Jim Paris <jim@jtan.com>
+ * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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
+ */
+
+#define MODULE_NAME "ov534"
+
+#include "gspca.h"
+
+#define OV534_REG_ADDRESS      0xf1    /* ? */
+#define OV534_REG_SUBADDR      0xf2
+#define OV534_REG_WRITE                0xf3
+#define OV534_REG_READ         0xf4
+#define OV534_REG_OPERATION    0xf5
+#define OV534_REG_STATUS       0xf6
+
+#define OV534_OP_WRITE_3       0x37
+#define OV534_OP_WRITE_2       0x33
+#define OV534_OP_READ_2                0xf9
+
+#define CTRL_TIMEOUT 500
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;     /* !! must be the first item */
+       __u32 last_fid;
+       __u32 last_pts;
+       int frame_rate;
+};
+
+/* V4L2 controls supported by the driver */
+static struct ctrl sd_ctrls[] = {
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+       {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+        .bytesperline = 640 * 2,
+        .sizeimage = 640 * 480 * 2,
+        .colorspace = V4L2_COLORSPACE_JPEG,
+        .priv = 0},
+};
+
+static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       int ret;
+
+       PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+       gspca_dev->usb_buf[0] = val;
+       ret = usb_control_msg(udev,
+                             usb_sndctrlpipe(udev, 0),
+                             0x1,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+       if (ret < 0)
+               PDEBUG(D_ERR, "write failed");
+}
+
+static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+       struct usb_device *udev = gspca_dev->dev;
+       int ret;
+
+       ret = usb_control_msg(udev,
+                             usb_rcvctrlpipe(udev, 0),
+                             0x1,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+       PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]);
+       if (ret < 0)
+               PDEBUG(D_ERR, "read failed");
+       return gspca_dev->usb_buf[0];
+}
+
+/* Two bits control LED: 0x21 bit 7 and 0x23 bit 7.
+ * (direction and output)? */
+static void ov534_set_led(struct gspca_dev *gspca_dev, int status)
+{
+       u8 data;
+
+       PDEBUG(D_CONF, "led status: %d", status);
+
+       data = ov534_reg_read(gspca_dev, 0x21);
+       data |= 0x80;
+       ov534_reg_write(gspca_dev, 0x21, data);
+
+       data = ov534_reg_read(gspca_dev, 0x23);
+       if (status)
+               data |= 0x80;
+       else
+               data &= ~(0x80);
+
+       ov534_reg_write(gspca_dev, 0x23, data);
+}
+
+static int sccb_check_status(struct gspca_dev *gspca_dev)
+{
+       u8 data;
+       int i;
+
+       for (i = 0; i < 5; i++) {
+               data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
+
+               switch (data) {
+               case 0x00:
+                       return 1;
+               case 0x04:
+                       return 0;
+               case 0x03:
+                       break;
+               default:
+                       PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+                              data, i + 1);
+               }
+       }
+       return 0;
+}
+
+static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+       PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%02x", reg, val);
+       ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+       ov534_reg_write(gspca_dev, OV534_REG_WRITE, val);
+       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
+
+       if (!sccb_check_status(gspca_dev))
+               PDEBUG(D_ERR, "sccb_reg_write failed");
+}
+
+#ifdef GSPCA_DEBUG
+static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+       ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
+       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
+       if (!sccb_check_status(gspca_dev))
+               PDEBUG(D_ERR, "sccb_reg_read failed 1");
+
+       ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
+       if (!sccb_check_status(gspca_dev))
+               PDEBUG(D_ERR, "sccb_reg_read failed 2");
+
+       return ov534_reg_read(gspca_dev, OV534_REG_READ);
+}
+#endif
+
+static const __u8 ov534_reg_initdata[][2] = {
+       { 0xe7, 0x3a },
+
+       { OV534_REG_ADDRESS, 0x42 }, /* select OV772x sensor */
+
+       { 0xc2, 0x0c },
+       { 0x88, 0xf8 },
+       { 0xc3, 0x69 },
+       { 0x89, 0xff },
+       { 0x76, 0x03 },
+       { 0x92, 0x01 },
+       { 0x93, 0x18 },
+       { 0x94, 0x10 },
+       { 0x95, 0x10 },
+       { 0xe2, 0x00 },
+       { 0xe7, 0x3e },
+
+       { 0x96, 0x00 },
+
+       { 0x97, 0x20 },
+       { 0x97, 0x20 },
+       { 0x97, 0x20 },
+       { 0x97, 0x0a },
+       { 0x97, 0x3f },
+       { 0x97, 0x4a },
+       { 0x97, 0x20 },
+       { 0x97, 0x15 },
+       { 0x97, 0x0b },
+
+       { 0x8e, 0x40 },
+       { 0x1f, 0x81 },
+       { 0x34, 0x05 },
+       { 0xe3, 0x04 },
+       { 0x88, 0x00 },
+       { 0x89, 0x00 },
+       { 0x76, 0x00 },
+       { 0xe7, 0x2e },
+       { 0x31, 0xf9 },
+       { 0x25, 0x42 },
+       { 0x21, 0xf0 },
+
+       { 0x1c, 0x00 },
+       { 0x1d, 0x40 },
+       { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */
+       { 0x1d, 0x00 }, /* payload size */
+       { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */
+       { 0x1d, 0x58 }, /* frame size */
+       { 0x1d, 0x00 }, /* frame size */
+
+       { 0x1c, 0x0a },
+       { 0x1d, 0x08 }, /* turn on UVC header */
+       { 0x1d, 0x0e }, /* .. */
+
+       { 0x8d, 0x1c },
+       { 0x8e, 0x80 },
+       { 0xe5, 0x04 },
+
+       { 0xc0, 0x50 },
+       { 0xc1, 0x3c },
+       { 0xc2, 0x0c },
+};
+
+static const __u8 ov772x_reg_initdata[][2] = {
+       { 0x12, 0x80 },
+       { 0x11, 0x01 },
+
+       { 0x3d, 0x03 },
+       { 0x17, 0x26 },
+       { 0x18, 0xa0 },
+       { 0x19, 0x07 },
+       { 0x1a, 0xf0 },
+       { 0x32, 0x00 },
+       { 0x29, 0xa0 },
+       { 0x2c, 0xf0 },
+       { 0x65, 0x20 },
+       { 0x11, 0x01 },
+       { 0x42, 0x7f },
+       { 0x63, 0xe0 },
+       { 0x64, 0xff },
+       { 0x66, 0x00 },
+       { 0x13, 0xf0 },
+       { 0x0d, 0x41 },
+       { 0x0f, 0xc5 },
+       { 0x14, 0x11 },
+
+       { 0x22, 0x7f },
+       { 0x23, 0x03 },
+       { 0x24, 0x40 },
+       { 0x25, 0x30 },
+       { 0x26, 0xa1 },
+       { 0x2a, 0x00 },
+       { 0x2b, 0x00 },
+       { 0x6b, 0xaa },
+       { 0x13, 0xff },
+
+       { 0x90, 0x05 },
+       { 0x91, 0x01 },
+       { 0x92, 0x03 },
+       { 0x93, 0x00 },
+       { 0x94, 0x60 },
+       { 0x95, 0x3c },
+       { 0x96, 0x24 },
+       { 0x97, 0x1e },
+       { 0x98, 0x62 },
+       { 0x99, 0x80 },
+       { 0x9a, 0x1e },
+       { 0x9b, 0x08 },
+       { 0x9c, 0x20 },
+       { 0x9e, 0x81 },
+
+       { 0xa6, 0x04 },
+       { 0x7e, 0x0c },
+       { 0x7f, 0x16 },
+       { 0x80, 0x2a },
+       { 0x81, 0x4e },
+       { 0x82, 0x61 },
+       { 0x83, 0x6f },
+       { 0x84, 0x7b },
+       { 0x85, 0x86 },
+       { 0x86, 0x8e },
+       { 0x87, 0x97 },
+       { 0x88, 0xa4 },
+       { 0x89, 0xaf },
+       { 0x8a, 0xc5 },
+       { 0x8b, 0xd7 },
+       { 0x8c, 0xe8 },
+       { 0x8d, 0x20 },
+
+       { 0x0c, 0x90 },
+
+       { 0x2b, 0x00 },
+       { 0x22, 0x7f },
+       { 0x23, 0x03 },
+       { 0x11, 0x01 },
+       { 0x0c, 0xd0 },
+       { 0x64, 0xff },
+       { 0x0d, 0x41 },
+
+       { 0x14, 0x41 },
+       { 0x0e, 0xcd },
+       { 0xac, 0xbf },
+       { 0x8e, 0x00 },
+       { 0x0c, 0xd0 }
+};
+
+/* set framerate */
+static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int fr = sd->frame_rate;
+
+       switch (fr) {
+       case 50:
+               sccb_reg_write(gspca_dev, 0x11, 0x01);
+               sccb_reg_write(gspca_dev, 0x0d, 0x41);
+               ov534_reg_write(gspca_dev, 0xe5, 0x02);
+               break;
+       case 40:
+               sccb_reg_write(gspca_dev, 0x11, 0x02);
+               sccb_reg_write(gspca_dev, 0x0d, 0xc1);
+               ov534_reg_write(gspca_dev, 0xe5, 0x04);
+               break;
+/*     case 30: */
+       default:
+               fr = 30;
+               sccb_reg_write(gspca_dev, 0x11, 0x04);
+               sccb_reg_write(gspca_dev, 0x0d, 0x81);
+               ov534_reg_write(gspca_dev, 0xe5, 0x02);
+               break;
+       case 15:
+               sccb_reg_write(gspca_dev, 0x11, 0x03);
+               sccb_reg_write(gspca_dev, 0x0d, 0x41);
+               ov534_reg_write(gspca_dev, 0xe5, 0x04);
+               break;
+       }
+
+       sd->frame_rate = fr;
+       PDEBUG(D_PROBE, "frame_rate: %d", fr);
+}
+
+/* setup method */
+static void ov534_setup(struct gspca_dev *gspca_dev)
+{
+       int i;
+
+       /* Initialize bridge chip */
+       for (i = 0; i < ARRAY_SIZE(ov534_reg_initdata); i++)
+               ov534_reg_write(gspca_dev, ov534_reg_initdata[i][0],
+                               ov534_reg_initdata[i][1]);
+
+       PDEBUG(D_PROBE, "sensor is ov%02x%02x",
+               sccb_reg_read(gspca_dev, 0x0a),
+               sccb_reg_read(gspca_dev, 0x0b));
+
+       ov534_set_led(gspca_dev, 1);
+
+       /* Initialize sensor */
+       for (i = 0; i < ARRAY_SIZE(ov772x_reg_initdata); i++)
+               sccb_reg_write(gspca_dev, ov772x_reg_initdata[i][0],
+                              ov772x_reg_initdata[i][1]);
+
+       ov534_reg_write(gspca_dev, 0xe0, 0x09);
+       ov534_set_led(gspca_dev, 0);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                    const struct usb_device_id *id)
+{
+       struct cam *cam;
+
+       cam = &gspca_dev->cam;
+
+       cam->epaddr = 0x01;
+       cam->cam_mode = vga_mode;
+       cam->nmodes = ARRAY_SIZE(vga_mode);
+
+       cam->bulk_size = 16384;
+       cam->bulk_nurbs = 2;
+
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       ov534_setup(gspca_dev);
+       ov534_set_frame_rate(gspca_dev);
+
+       return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+       /* start streaming data */
+       ov534_set_led(gspca_dev, 1);
+       ov534_reg_write(gspca_dev, 0xe0, 0x00);
+
+       return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+       /* stop streaming data */
+       ov534_reg_write(gspca_dev, 0xe0, 0x09);
+       ov534_set_led(gspca_dev, 0);
+}
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH (1 << 7)
+#define UVC_STREAM_ERR (1 << 6)
+#define UVC_STREAM_STI (1 << 5)
+#define UVC_STREAM_RES (1 << 4)
+#define UVC_STREAM_SCR (1 << 3)
+#define UVC_STREAM_PTS (1 << 2)
+#define UVC_STREAM_EOF (1 << 1)
+#define UVC_STREAM_FID (1 << 0)
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
+                       __u8 *data, int len)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u32 this_pts;
+       int this_fid;
+       int remaining_len = len;
+       __u8 *next_data = data;
+
+scan_next:
+       if (remaining_len <= 0)
+               return;
+
+       data = next_data;
+       len = min(remaining_len, 2048);
+       remaining_len -= len;
+       next_data += len;
+
+       /* Payloads are prefixed with a UVC-style header.  We
+          consider a frame to start when the FID toggles, or the PTS
+          changes.  A frame ends when EOF is set, and we've received
+          the correct number of bytes. */
+
+       /* Verify UVC header.  Header length is always 12 */
+       if (data[0] != 12 || len < 12) {
+               PDEBUG(D_PACK, "bad header");
+               goto discard;
+       }
+
+       /* Check errors */
+       if (data[1] & UVC_STREAM_ERR) {
+               PDEBUG(D_PACK, "payload error");
+               goto discard;
+       }
+
+       /* Extract PTS and FID */
+       if (!(data[1] & UVC_STREAM_PTS)) {
+               PDEBUG(D_PACK, "PTS not present");
+               goto discard;
+       }
+       this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
+       this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
+
+       /* If PTS or FID has changed, start a new frame. */
+       if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+               sd->last_pts = this_pts;
+               sd->last_fid = this_fid;
+       }
+
+       /* Add the data from this payload */
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                               data + 12, len - 12);
+
+       /* If this packet is marked as EOF, end the frame */
+       if (data[1] & UVC_STREAM_EOF) {
+               sd->last_pts = 0;
+
+               if ((frame->data_end - frame->data) !=
+                   (gspca_dev->width * gspca_dev->height * 2)) {
+                       PDEBUG(D_PACK, "short frame");
+                       goto discard;
+               }
+
+               gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
+       }
+
+       /* Done this payload */
+       goto scan_next;
+
+discard:
+       /* Discard data until a new frame starts. */
+       gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+       goto scan_next;
+}
+
+/* get stream parameters (framerate) */
+static int sd_get_streamparm(struct gspca_dev *gspca_dev,
+                            struct v4l2_streamparm *parm)
+{
+       struct v4l2_captureparm *cp = &parm->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cp->capability |= V4L2_CAP_TIMEPERFRAME;
+       tpf->numerator = 1;
+       tpf->denominator = sd->frame_rate;
+
+       return 0;
+}
+
+/* set stream parameters (framerate) */
+static int sd_set_streamparm(struct gspca_dev *gspca_dev,
+                            struct v4l2_streamparm *parm)
+{
+       struct v4l2_captureparm *cp = &parm->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       /* Set requested framerate */
+       sd->frame_rate = tpf->denominator / tpf->numerator;
+       ov534_set_frame_rate(gspca_dev);
+
+       /* Return the actual framerate */
+       tpf->numerator = 1;
+       tpf->denominator = sd->frame_rate;
+
+       return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name     = MODULE_NAME,
+       .ctrls    = sd_ctrls,
+       .nctrls   = ARRAY_SIZE(sd_ctrls),
+       .config   = sd_config,
+       .init     = sd_init,
+       .start    = sd_start,
+       .stopN    = sd_stopN,
+       .pkt_scan = sd_pkt_scan,
+       .get_streamparm = sd_get_streamparm,
+       .set_streamparm = sd_set_streamparm,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x06f8, 0x3002)},   /* Hercules Blog Webcam */
+       {USB_DEVICE(0x06f8, 0x3003)},   /* Hercules Dualpix HD Weblog */
+       {USB_DEVICE(0x1415, 0x2000)},   /* Sony HD Eye for PS3 (SLEH 00201) */
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+       .name       = MODULE_NAME,
+       .id_table   = device_table,
+       .probe      = sd_probe,
+       .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend    = gspca_suspend,
+       .resume     = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "registered");
+       return 0;
+}
+
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
index 0b0c573d06da1ee3da37fed3d3f74948375845c4..c90ac852bac07eace63ab95756796d8a804f3693 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Pixart PAC207BCA library
  *
- * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2008 Hans de Goede <hdgoede@redhat.com>
  * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
  * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
  *
@@ -27,7 +27,7 @@
 
 #include "gspca.h"
 
-MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
 MODULE_DESCRIPTION("Pixart PAC207");
 MODULE_LICENSE("GPL");
 
@@ -149,7 +149,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = (176 + 2) * 144,
@@ -529,6 +529,7 @@ static const struct sd_desc sd_desc = {
 static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x041e, 0x4028)},
        {USB_DEVICE(0x093a, 0x2460)},
+       {USB_DEVICE(0x093a, 0x2461)},
        {USB_DEVICE(0x093a, 0x2463)},
        {USB_DEVICE(0x093a, 0x2464)},
        {USB_DEVICE(0x093a, 0x2468)},
@@ -536,6 +537,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2471)},
        {USB_DEVICE(0x093a, 0x2472)},
        {USB_DEVICE(0x093a, 0x2476)},
+       {USB_DEVICE(0x145f, 0x013a)},
        {USB_DEVICE(0x2001, 0xf115)},
        {}
 };
index fbd45e235d970934633132385a081270adbbd5ef..a9c95cba710e350e14fb70df6121d2a721700fa1 100644 (file)
@@ -226,7 +226,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 8 + 590,
@@ -1064,10 +1064,13 @@ static __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
        {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
        {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
+       {USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+       {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302},
        {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302},
+       {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index 6c69bc7778fc2f9cf322d0282a3151a91bcc9f82..b3e4e0677b683546135400609c373a81d879974d 100644 (file)
@@ -132,8 +132,6 @@ struct sensor_data {
    ignore atleast the 2 next frames for the new settings to come into effect
    before doing any other adjustments */
 #define AUTOGAIN_IGNORE_FRAMES 3
-#define AUTOGAIN_DEADZONE 1000
-#define DESIRED_AVG_LUM 7000
 
 /* V4L2 controls supported by the driver */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
@@ -229,7 +227,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120,
@@ -251,7 +249,7 @@ static struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
 };
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120,
@@ -827,18 +825,29 @@ static void setfreq(struct gspca_dev *gspca_dev)
 
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
+       int deadzone, desired_avg_lum;
        struct sd *sd = (struct sd *) gspca_dev;
        int avg_lum = atomic_read(&sd->avg_lum);
 
        if (avg_lum == -1)
                return;
 
+       /* SIF / VGA sensors have a different autoexposure area and thus
+          different avg_lum values for the same picture brightness */
+       if (sensor_data[sd->sensor].flags & F_SIF) {
+               deadzone = 1000;
+               desired_avg_lum = 7000;
+       } else {
+               deadzone = 3000;
+               desired_avg_lum = 23000;
+       }
+
        if (sd->autogain_ignore_frames > 0)
                sd->autogain_ignore_frames--;
        else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
-                       sd->brightness * DESIRED_AVG_LUM / 127,
-                       AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
-               PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
+                       sd->brightness * desired_avg_lum / 127,
+                       deadzone, GAIN_KNEE, EXPOSURE_KNEE)) {
+               PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d",
                        (int)sd->gain, (int)sd->exposure);
                sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
        }
@@ -1226,8 +1235,8 @@ static __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
        {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
        {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
-       {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
 #endif
+       {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
        {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
index 53cb82d9e7c6a28909636595968ae335c9809698..3373b8d9d2a88fa92c8ec40feb5d4d207d9b17ab 100644 (file)
@@ -24,6 +24,8 @@
 #include "gspca.h"
 #include "jpeg.h"
 
+#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
+
 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
 MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
 MODULE_LICENSE("GPL");
@@ -35,23 +37,26 @@ struct sd {
        atomic_t avg_lum;
        unsigned int exposure;
 
-       unsigned short brightness;
-       unsigned char contrast;
-       unsigned char colors;
-       unsigned char autogain;
+       __u16 brightness;
+       __u8 contrast;
+       __u8 colors;
+       __u8 autogain;
+       __u8 blue;
+       __u8 red;
        __u8 vflip;                     /* ov7630 only */
+       __u8 infrared;                  /* mi0360 only */
 
-       signed char ag_cnt;
+       __s8 ag_cnt;
 #define AG_CNT_START 13
 
-       char qindex;
-       unsigned char bridge;
+       __u8 qindex;
+       __u8 bridge;
 #define BRIDGE_SN9C102P 0
 #define BRIDGE_SN9C105 1
 #define BRIDGE_SN9C110 2
 #define BRIDGE_SN9C120 3
 #define BRIDGE_SN9C325 4
-       char sensor;                    /* Type of image sensor chip */
+       __u8 sensor;                    /* Type of image sensor chip */
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
 #define SENSOR_MO4000 2
@@ -59,7 +64,7 @@ struct sd {
 #define SENSOR_OV7630 4
 #define SENSOR_OV7648 5
 #define SENSOR_OV7660 6
-       unsigned char i2c_base;
+       __u8 i2c_base;
 };
 
 /* V4L2 controls supported by the driver */
@@ -69,10 +74,16 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
        {
@@ -84,7 +95,7 @@ static struct ctrl sd_ctrls[] = {
 #define BRIGHTNESS_MAX 0xffff
                .maximum = BRIGHTNESS_MAX,
                .step    = 1,
-#define BRIGHTNESS_DEF 0x7fff
+#define BRIGHTNESS_DEF 0x8000
                .default_value = BRIGHTNESS_DEF,
            },
            .set = sd_setbrightness,
@@ -111,7 +122,7 @@ static struct ctrl sd_ctrls[] = {
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Color",
                .minimum = 0,
-               .maximum = 64,
+               .maximum = 40,
                .step    = 1,
 #define COLOR_DEF 32
                .default_value = COLOR_DEF,
@@ -119,7 +130,35 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
-#define AUTOGAIN_IDX 3
+       {
+           {
+               .id      = V4L2_CID_BLUE_BALANCE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Blue Balance",
+               .minimum = 24,
+               .maximum = 40,
+               .step    = 1,
+#define BLUE_BALANCE_DEF 32
+               .default_value = BLUE_BALANCE_DEF,
+           },
+           .set = sd_setblue_balance,
+           .get = sd_getblue_balance,
+       },
+       {
+           {
+               .id      = V4L2_CID_RED_BALANCE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Red Balance",
+               .minimum = 24,
+               .maximum = 40,
+               .step    = 1,
+#define RED_BALANCE_DEF 32
+               .default_value = RED_BALANCE_DEF,
+           },
+           .set = sd_setred_balance,
+           .get = sd_getred_balance,
+       },
+#define AUTOGAIN_IDX 5
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -135,7 +174,7 @@ static struct ctrl sd_ctrls[] = {
            .get = sd_getautogain,
        },
 /* ov7630 only */
-#define VFLIP_IDX 4
+#define VFLIP_IDX 6
        {
            {
                .id      = V4L2_CID_VFLIP,
@@ -150,9 +189,43 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setvflip,
            .get = sd_getvflip,
        },
+/* mi0360 only */
+#define INFRARED_IDX 7
+       {
+           {
+               .id      = V4L2_CID_INFRARED,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Infrared",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define INFRARED_DEF 0
+               .default_value = INFRARED_DEF,
+           },
+           .set = sd_setinfrared,
+           .get = sd_getinfrared,
+       },
+};
+
+/* table of the disabled controls */
+static __u32 ctrl_dis[] = {
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+                                               /* SENSOR_HV7131R 0 */
+       (1 << VFLIP_IDX),
+                                               /* SENSOR_MI0360 1 */
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+                                               /* SENSOR_MO4000 2 */
+       (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+                                               /* SENSOR_OM6802 3 */
+       (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX),
+                                               /* SENSOR_OV7630 4 */
+       (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+                                               /* SENSOR_OV7648 5 */
+       (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX),
+                                               /* SENSOR_OV7660 6 */
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 4 / 8 + 590,
@@ -231,13 +304,13 @@ static const __u8 sn_ov7630[] = {
 
 static const __u8 sn_ov7648[] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x00,   0x21,   0x62,   0x00,   0x1a,   0x20,   0x20,   0x20,
+       0x00,   0x63,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
-       0xa1,   0x6e,   0x18,   0x65,   0x00,   0x00,   0x00,   0x10,
+       0x81,   0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x10,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
-       0x03,   0x00,   0x00,   0x06,   0x06,   0x28,   0x1e,   0x82,
+       0x03,   0x00,   0x00,   0x01,   0x00,   0x28,   0x1e,   0x00,
 /*     reg18   reg19   reg1a   reg1b   reg1c   reg1d   reg1e   reg1f */
-       0x07,   0x00,   0x00,   0x00,   0x00,   0x00
+       0x0b,   0x00,   0x00,   0x00,   0x00,   0x00
 };
 
 static const __u8 sn_ov7660[]  = {
@@ -469,6 +542,53 @@ static const __u8 ov7630_sensor_init[][8] = {
 /*     {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */
        {}
 };
+
+static const __u8 ov7648_sensor_init[][8] = {
+       {0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},       /* reset */
+       {0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10},
+       {0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10},
+       {0xc1, 0x21, 0x13, 0xa0, 0x04, 0x84, 0x00, 0x10},
+       {0xd1, 0x21, 0x17, 0x1a, 0x02, 0xba, 0xf4, 0x10},
+       {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x1f, 0x41, 0xc0, 0x80, 0x80, 0x10},
+       {0xd1, 0x21, 0x23, 0xde, 0xa0, 0x80, 0x32, 0x10},
+       {0xd1, 0x21, 0x27, 0xfe, 0xa0, 0x00, 0x91, 0x10},
+       {0xd1, 0x21, 0x2b, 0x00, 0x88, 0x85, 0x80, 0x10},
+       {0xc1, 0x21, 0x2f, 0x9c, 0x00, 0xc4, 0x00, 0x10},
+       {0xd1, 0x21, 0x60, 0xa6, 0x60, 0x88, 0x12, 0x10},
+       {0xd1, 0x21, 0x64, 0x88, 0x00, 0x00, 0x94, 0x10},
+       {0xd1, 0x21, 0x68, 0x7a, 0x0c, 0x00, 0x00, 0x10},
+       {0xd1, 0x21, 0x6c, 0x11, 0x33, 0x22, 0x00, 0x10},
+       {0xd1, 0x21, 0x70, 0x11, 0x00, 0x10, 0x50, 0x10},
+       {0xd1, 0x21, 0x74, 0x20, 0x06, 0x00, 0xb5, 0x10},
+       {0xd1, 0x21, 0x78, 0x8a, 0x00, 0x00, 0x00, 0x10},
+       {0xb1, 0x21, 0x7c, 0x00, 0x43, 0x00, 0x00, 0x10},
+
+       {0xd1, 0x21, 0x21, 0x86, 0x00, 0xde, 0xa0, 0x10},
+/*     {0xd1, 0x21, 0x25, 0x80, 0x32, 0xfe, 0xa0, 0x10}, jfm done */
+/*     {0xd1, 0x21, 0x29, 0x00, 0x91, 0x00, 0x88, 0x10}, jfm done */
+       {0xb1, 0x21, 0x2d, 0x85, 0x00, 0x00, 0x00, 0x10},
+/*...*/
+/*     {0xa1, 0x21, 0x12, 0x08, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xa1, 0x21, 0x75, 0x06, 0x00, 0x00, 0x00, 0x10}, jfm done */
+       {0xa1, 0x21, 0x19, 0x02, 0x00, 0x00, 0x00, 0x10},
+       {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10},
+/*     {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},  * GAIN - def */
+/*     {0xb1, 0x21, 0x01, 0x6c, 0x6c, 0x00, 0x00, 0x10},  * B R - def: 80 */
+/*...*/
+       {0xa1, 0x21, 0x11, 0x81, 0x00, 0x00, 0x00, 0x10}, /* CLKRC */
+/*     {0xa1, 0x21, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xa1, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xa1, 0x21, 0x2a, 0x91, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, jfm done */
+/*     {0xb1, 0x21, 0x01, 0x64, 0x84, 0x00, 0x00, 0x10},  * B R - def: 80 */
+
+       {}
+};
+
 static const __u8 ov7660_sensor_init[][8] = {
        {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
 /*             (delay 20ms) */
@@ -557,64 +677,6 @@ static const __u8 ov7660_sensor_init[][8] = {
        {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10},
        {}
 };
-/*       reg 0x04        reg 0x07                 reg 0x10 */
-/* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */
-
-static const __u8 ov7648_sensor_init[][8] = {
-       {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
-       {0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
-       {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
-       {0xA1, 0x6E, 0x3F, 0x20, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x04, 0x02, 0xB1, 0x02, 0x39, 0x10},
-       {0xD1, 0x6E, 0x08, 0x00, 0x01, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x0C, 0x02, 0x7F, 0x01, 0xE0, 0x10},
-       {0xD1, 0x6E, 0x12, 0x03, 0x02, 0x00, 0x03, 0x10},
-       {0xD1, 0x6E, 0x16, 0x85, 0x40, 0x4A, 0x40, 0x10},
-       {0xC1, 0x6E, 0x1A, 0x00, 0x80, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x1D, 0x08, 0x03, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x23, 0x00, 0xB0, 0x00, 0x94, 0x10},
-       {0xD1, 0x6E, 0x27, 0x58, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x2D, 0x14, 0x35, 0x61, 0x84, 0x10},
-       {0xD1, 0x6E, 0x31, 0xA2, 0xBD, 0xD8, 0xFF, 0x10},
-       {0xD1, 0x6E, 0x35, 0x06, 0x1E, 0x12, 0x02, 0x10},
-       {0xD1, 0x6E, 0x39, 0xAA, 0x53, 0x37, 0xD5, 0x10},
-       {0xA1, 0x6E, 0x3D, 0xF2, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x3E, 0x00, 0x00, 0x80, 0x03, 0x10},
-       {0xD1, 0x6E, 0x42, 0x03, 0x00, 0x00, 0x00, 0x10},
-       {0xC1, 0x6E, 0x46, 0x00, 0x80, 0x80, 0x00, 0x10},
-       {0xD1, 0x6E, 0x4B, 0x02, 0xEF, 0x08, 0xCD, 0x10},
-       {0xD1, 0x6E, 0x4F, 0x00, 0xD0, 0x00, 0xA0, 0x10},
-       {0xD1, 0x6E, 0x53, 0x01, 0xAA, 0x01, 0x40, 0x10},
-       {0xD1, 0x6E, 0x5A, 0x50, 0x04, 0x30, 0x03, 0x10},
-       {0xA1, 0x6E, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x5F, 0x10, 0x40, 0xFF, 0x00, 0x10},
-  /*   {0xD1, 0x6E, 0x63, 0x40, 0x40, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x00, 0x10},
- * This is currently setting a
- * blue tint, and some things more , i leave it here for future test if
- * somene is having problems with color on this sensor
-       {0xD1, 0x6E, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xD1, 0x6E, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x10},
-       {0xC1, 0x6E, 0x73, 0x10, 0x80, 0xEB, 0x00, 0x10},
-       {0xA1, 0x6E, 0x1E, 0x03, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x15, 0x01, 0x00, 0x00, 0x00, 0x10},
-       {0xC1, 0x6E, 0x16, 0x40, 0x40, 0x40, 0x00, 0x10},
-       {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x07, 0xB5, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x18, 0x6B, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x1D, 0x08, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
-       {0xA1, 0x6E, 0x07, 0xB8, 0x00, 0x00, 0x00, 0x10},  */
-       {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00},
-       {0xA1, 0x6E, 0x06, 0x03, 0x00, 0x00, 0x00, 0x10}, /* Bright... */
-       {0xA1, 0x6E, 0x07, 0x66, 0x00, 0x00, 0x00, 0x10}, /* B.. */
-       {0xC1, 0x6E, 0x1A, 0x03, 0x65, 0x90, 0x00, 0x10}, /* Bright/Witen....*/
-/*     {0xC1, 0x6E, 0x16, 0x45, 0x40, 0x60, 0x00, 0x10},  * Bright/Witene */
-       {}
-};
 
 static const __u8 qtable4[] = {
        0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x08, 0x06,
@@ -757,8 +819,6 @@ static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg)
 
 static int probesensor(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-
        i2c_w1(gspca_dev, 0x02, 0);                     /* sensor wakeup */
        msleep(10);
        reg_w1(gspca_dev, 0x02, 0x66);                  /* Gpio on */
@@ -770,8 +830,7 @@ static int probesensor(struct gspca_dev *gspca_dev)
            && gspca_dev->usb_buf[3] == 0x00
            && gspca_dev->usb_buf[4] == 0x00) {
                PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R");
-               sd->sensor = SENSOR_HV7131R;
-               return SENSOR_HV7131R;
+               return 0;
        }
        PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x",
                gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
@@ -827,17 +886,20 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x01, 0x40);
                break;
        case SENSOR_OV7648:
-               reg_w1(gspca_dev, 0x01, 0x43);
-               reg_w1(gspca_dev, 0x17, 0xae);
+               reg_w1(gspca_dev, 0x01, 0x63);
+               reg_w1(gspca_dev, 0x17, 0x20);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
 /*jfm: from win trace */
        case SENSOR_OV7660:
-               reg_w1(gspca_dev, 0x01, 0x61);
-               reg_w1(gspca_dev, 0x17, 0x20);
-               reg_w1(gspca_dev, 0x01, 0x60);
-               reg_w1(gspca_dev, 0x01, 0x40);
-               break;
+               if (sd->bridge == BRIDGE_SN9C120) {
+                       reg_w1(gspca_dev, 0x01, 0x61);
+                       reg_w1(gspca_dev, 0x17, 0x20);
+                       reg_w1(gspca_dev, 0x01, 0x60);
+                       reg_w1(gspca_dev, 0x01, 0x40);
+                       break;
+               }
+               /* fall thru */
        default:
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0x61);
@@ -922,6 +984,13 @@ static void ov7648_InitSensor(struct gspca_dev *gspca_dev)
 {
        int i = 0;
 
+       i2c_w8(gspca_dev, ov7648_sensor_init[i]);
+       i++;
+/* win: dble reset */
+       i2c_w8(gspca_dev, ov7648_sensor_init[i]);       /* reset */
+       i++;
+       msleep(20);
+/* win: i2c reg read 00..7f */
        while (ov7648_sensor_init[i][0]) {
                i2c_w8(gspca_dev, ov7648_sensor_init[i]);
                i++;
@@ -961,19 +1030,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
+       sd->blue = BLUE_BALANCE_DEF;
+       sd->red = RED_BALANCE_DEF;
        sd->autogain = AUTOGAIN_DEF;
        sd->ag_cnt = -1;
+       sd->vflip = VFLIP_DEF;
+       sd->infrared = INFRARED_DEF;
 
-       switch (sd->sensor) {
-       case SENSOR_OV7630:
-       case SENSOR_OV7648:
-       case SENSOR_OV7660:
-               gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX);
-               break;
-       }
-       if (sd->sensor != SENSOR_OV7630)
-               gspca_dev->ctrl_dis |= (1 << VFLIP_IDX);
-
+       gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
        return 0;
 }
 
@@ -981,7 +1045,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
 static int sd_init(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-/*     const __u8 *sn9c1xx; */
        __u8 regGpio[] = { 0x29, 0x74 };
        __u8 regF1;
 
@@ -1100,32 +1163,13 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev,
        return expo;
 }
 
-/* this function is used for sensors o76xx only */
-static void setbrightcont(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       int val;
-       __u8 reg84_full[0x15];
-
-       memcpy(reg84_full, reg84, sizeof reg84_full);
-       val = sd->contrast * 0x30 / CONTRAST_MAX + 0x10;        /* 10..40 */
-       reg84_full[0] = (val + 1) / 2;          /* red */
-       reg84_full[2] = val;                    /* green */
-       reg84_full[4] = (val + 1) / 5;          /* blue */
-       val = (sd->brightness - BRIGHTNESS_DEF) * 0x10
-                       / BRIGHTNESS_MAX;
-       reg84_full[0x12] = val & 0x1f;          /* 5:0 signed value */
-       reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full);
-}
-
-/* sensor != ov76xx */
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned int expo;
        __u8 k2;
 
-       k2 = sd->brightness >> 10;
+       k2 = ((int) sd->brightness - 0x8000) >> 10;
        switch (sd->sensor) {
        case SENSOR_HV7131R:
                expo = sd->brightness << 4;
@@ -1147,38 +1191,49 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                break;
        }
 
-       reg_w1(gspca_dev, 0x96, k2);
+       reg_w1(gspca_dev, 0x96, k2);            /* color matrix Y offset */
 }
 
-/* sensor != ov76xx */
 static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 k2;
-       __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 };
-
-       k2 = sd->contrast;
-       contrast[2] = k2;
-       contrast[0] = (k2 + 1) >> 1;
-       contrast[4] = (k2 + 1) / 5;
-       reg_w(gspca_dev, 0x84, contrast, 6);
+       __u8 contrast[6];
+
+       k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10;   /* 10..40 */
+       contrast[0] = (k2 + 1) / 2;             /* red */
+       contrast[1] = 0;
+       contrast[2] = k2;                       /* green */
+       contrast[3] = 0;
+       contrast[4] = (k2 + 1) / 5;             /* blue */
+       contrast[5] = 0;
+       reg_w(gspca_dev, 0x84, contrast, sizeof contrast);
 }
 
 static void setcolors(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 blue, red;
-
-       if (sd->colors >= 32) {
-               red = 32 + (sd->colors - 32) / 2;
-               blue = 64 - sd->colors;
-       } else {
-               red = sd->colors;
-               blue = 32 + (32 - sd->colors) / 2;
+       int i, v;
+       __u8 reg8a[12];                 /* U & V gains */
+       static __s16 uv[6] = {          /* same as reg84 in signed decimal */
+               -24, -38, 64,           /* UR UG UB */
+                62, -51, -9            /* VR VG VB */
+       };
+       for (i = 0; i < 6; i++) {
+               v = uv[i] * sd->colors / COLOR_DEF;
+               reg8a[i * 2] = v;
+               reg8a[i * 2 + 1] = (v >> 8) & 0x0f;
        }
-       reg_w1(gspca_dev, 0x05, red);
+       reg_w(gspca_dev, 0x8a, reg8a, sizeof reg8a);
+}
+
+static void setredblue(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_w1(gspca_dev, 0x05, sd->red);
 /*     reg_w1(gspca_dev, 0x07, 32); */
-       reg_w1(gspca_dev, 0x06, blue);
+       reg_w1(gspca_dev, 0x06, sd->blue);
 }
 
 static void setautogain(struct gspca_dev *gspca_dev)
@@ -1195,12 +1250,18 @@ static void setautogain(struct gspca_dev *gspca_dev)
 
 static void setvflip(struct sd *sd)
 {
-       if (sd->sensor != SENSOR_OV7630)
-               return;
        i2c_w1(&sd->gspca_dev, 0x75,                    /* COMN */
                sd->vflip ? 0x82 : 0x02);
 }
 
+static void setinfrared(struct sd *sd)
+{
+/*fixme: different sequence for StarCam Clip and StarCam 370i */
+/* Clip */
+       i2c_w1(&sd->gspca_dev, 0x02,                    /* gpio */
+               sd->infrared ? 0x66 : 0x64);
+}
+
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
@@ -1235,28 +1296,39 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg17 = 0xe2;
                break;
        case SENSOR_OV7648:
-               reg17 = 0xae;
+               reg17 = 0x20;
                break;
 /*jfm: from win trace */
        case SENSOR_OV7660:
-               reg17 = 0xa0;
-               break;
+               if (sd->bridge == BRIDGE_SN9C120) {
+                       reg17 = 0xa0;
+                       break;
+               }
+               /* fall thru */
        default:
                reg17 = 0x60;
                break;
        }
        reg_w1(gspca_dev, 0x17, reg17);
-       reg_w1(gspca_dev, 0x05, sn9c1xx[5]);
-       reg_w1(gspca_dev, 0x07, sn9c1xx[7]);
-       reg_w1(gspca_dev, 0x06, sn9c1xx[6]);
+/* set reg1 was here */
+       reg_w1(gspca_dev, 0x05, sn9c1xx[5]);    /* red */
+       reg_w1(gspca_dev, 0x07, sn9c1xx[7]);    /* green */
+       reg_w1(gspca_dev, 0x06, sn9c1xx[6]);    /* blue */
        reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]);
        reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def);
        for (i = 0; i < 8; i++)
                reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
        switch (sd->sensor) {
-       case SENSOR_OV7660:
-               reg_w1(gspca_dev, 0x9a, 0x05);
+       case SENSOR_OV7648:
+               reg_w1(gspca_dev, 0x9a, 0x0a);
+               reg_w1(gspca_dev, 0x99, 0x60);
                break;
+       case SENSOR_OV7660:
+               if (sd->bridge == BRIDGE_SN9C120) {
+                       reg_w1(gspca_dev, 0x9a, 0x05);
+                       break;
+               }
+               /* fall thru */
        default:
                reg_w1(gspca_dev, 0x9a, 0x08);
                reg_w1(gspca_dev, 0x99, 0x59);
@@ -1265,10 +1337,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
        if (mode)
-               reg1 = 0x46;    /* 320 clk 48Mhz */
+               reg1 = 0x46;    /* 320x240: clk 48Mhz, video trf enable */
        else
-               reg1 = 0x06;    /* 640 clk 24Mz */
-       reg17 = 0x61;
+               reg1 = 0x06;    /* 640x480: clk 24Mhz, video trf enable */
+       reg17 = 0x61;           /* 0x:20: enable sensor clock */
        switch (sd->sensor) {
        case SENSOR_HV7131R:
                hv7131R_InitSensor(gspca_dev);
@@ -1298,23 +1370,21 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        case SENSOR_OV7648:
                ov7648_InitSensor(gspca_dev);
-               reg17 = 0xa2;
-               reg1 = 0x44;
-/*             if (mode)
-                       ;                * 320x2...
-               else
-                       ;                * 640x... */
+               reg17 = 0x21;
+/*             reg1 = 0x42;             * 42 - 46? */
                break;
        default:
 /*     case SENSOR_OV7660: */
                ov7660_InitSensor(gspca_dev);
-               if (mode) {
-/*                     reg17 = 0x21;    * 320 */
-/*                     reg1 = 0x44; */
-/*                     reg1 = 0x46;    (done) */
+               if (sd->bridge == BRIDGE_SN9C120) {
+                       if (mode) {             /* 320x240 - 160x120 */
+                               reg17 = 0xa2;
+                               reg1 = 0x44;    /* 48 Mhz, video trf eneble */
+                       }
                } else {
-                       reg17 = 0xa2;   /* 640 */
-                       reg1 = 0x44;
+                       reg17 = 0x22;
+                       reg1 = 0x06;    /* 24 Mhz, video trf eneble
+                                        * inverse power down */
                }
                break;
        }
@@ -1342,23 +1412,18 @@ static int sd_start(struct gspca_dev *gspca_dev)
        reg_w1(gspca_dev, 0x18, reg18);
 
        reg_w1(gspca_dev, 0x17, reg17);
+       reg_w1(gspca_dev, 0x01, reg1);
        switch (sd->sensor) {
-       case SENSOR_HV7131R:
        case SENSOR_MI0360:
-       case SENSOR_MO4000:
-       case SENSOR_OM6802:
-               setbrightness(gspca_dev);
-               setcontrast(gspca_dev);
+               setinfrared(sd);
                break;
        case SENSOR_OV7630:
                setvflip(sd);
-               /* fall thru */
-       default:                        /* OV76xx */
-               setbrightcont(gspca_dev);
                break;
        }
+       setbrightness(gspca_dev);
+       setcontrast(gspca_dev);
        setautogain(gspca_dev);
-       reg_w1(gspca_dev, 0x01, reg1);
        return 0;
 }
 
@@ -1369,6 +1434,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                { 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10 };
        static const __u8 stopmi0360[] =
                { 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10 };
+       static const __u8 stopov7648[] =
+               { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
        __u8 data;
        const __u8 *sn9c1xx;
 
@@ -1382,8 +1449,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
                i2c_w8(gspca_dev, stopmi0360);
                data = 0x29;
                break;
-       case SENSOR_OV7630:
        case SENSOR_OV7648:
+               i2c_w8(gspca_dev, stopov7648);
+               /* fall thru */
+       case SENSOR_OV7630:
                data = 0x29;
                break;
        default:
@@ -1437,7 +1506,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                                expotimes = 0;
                        sd->exposure = setexposure(gspca_dev,
                                                   (unsigned int) expotimes);
-                       setcolors(gspca_dev);
+                       setredblue(gspca_dev);
                        break;
                }
        }
@@ -1491,19 +1560,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->brightness = val;
-       if (gspca_dev->streaming) {
-               switch (sd->sensor) {
-               case SENSOR_HV7131R:
-               case SENSOR_MI0360:
-               case SENSOR_MO4000:
-               case SENSOR_OM6802:
-                       setbrightness(gspca_dev);
-                       break;
-               default:                        /* OV76xx */
-                       setbrightcont(gspca_dev);
-                       break;
-               }
-       }
+       if (gspca_dev->streaming)
+               setbrightness(gspca_dev);
        return 0;
 }
 
@@ -1520,19 +1578,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->contrast = val;
-       if (gspca_dev->streaming) {
-               switch (sd->sensor) {
-               case SENSOR_HV7131R:
-               case SENSOR_MI0360:
-               case SENSOR_MO4000:
-               case SENSOR_OM6802:
-                       setcontrast(gspca_dev);
-                       break;
-               default:                        /* OV76xx */
-                       setbrightcont(gspca_dev);
-                       break;
-               }
-       }
+       if (gspca_dev->streaming)
+               setcontrast(gspca_dev);
        return 0;
 }
 
@@ -1562,6 +1609,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->blue = val;
+       if (gspca_dev->streaming)
+               setredblue(gspca_dev);
+       return 0;
+}
+
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->blue;
+       return 0;
+}
+
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->red = val;
+       if (gspca_dev->streaming)
+               setredblue(gspca_dev);
+       return 0;
+}
+
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->red;
+       return 0;
+}
+
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1598,6 +1681,24 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->infrared = val;
+       if (gspca_dev->streaming)
+               setinfrared(sd);
+       return 0;
+}
+
+static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->infrared;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -1620,12 +1721,15 @@ static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)},
        {USB_DEVICE(0x0458, 0x702e), BSI(SN9C120, OV7660, 0x21)},
+#endif
        {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
-       {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
 #endif
+       {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
+       {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
 /* bw600.inf:
        {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
@@ -1649,7 +1753,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
 /*     {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
 /*bw600.inf:*/
-       {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/
+       {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c110?*/
        {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)},
        {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)},
 /*     {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */
@@ -1657,8 +1761,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)},
 #endif
        {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)},
+       {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
-/*     {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
        {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
 /*     {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
index bca106c153faa3dc4708ad77a6e33eac2c73615d..942f04cd44dd4c9e46a28e272fd558a189bf67a3 100644 (file)
@@ -111,7 +111,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -124,7 +124,7 @@ static struct v4l2_pix_format vga_mode[] = {
                .priv = 0},
 };
 
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -633,10 +633,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->subtype = id->driver_info;
        if (sd->subtype != LogitechClickSmart310) {
                cam->cam_mode = vga_mode;
-               cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+               cam->nmodes = ARRAY_SIZE(vga_mode);
        } else {
                cam->cam_mode = sif_mode;
-               cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+               cam->nmodes = ARRAY_SIZE(sif_mode);
        }
        sd->qindex = 5;
        sd->brightness = BRIGHTNESS_DEF;
index e29954c1c38c2888dfbc892fbcea07b24c8bf4e3..82e3e3e2ada1434cf4d0fa36f7d2df81e8121f3f 100644 (file)
@@ -34,6 +34,8 @@ struct sd {
        unsigned short contrast;
        __u8 brightness;
        __u8 colors;
+       __u8 blue_balance;
+       __u8 red_balance;
 
        char subtype;
 #define Arowana300KCMOSCamera 0
@@ -52,6 +54,10 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 #define MY_BRIGHTNESS 0
@@ -63,7 +69,7 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 127,
                .step    = 1,
-               .default_value = 63,
+               .default_value = 0,
            },
            .set = sd_setbrightness,
            .get = sd_getbrightness,
@@ -75,9 +81,9 @@ static struct ctrl sd_ctrls[] = {
                .type    = V4L2_CTRL_TYPE_INTEGER,
                .name    = "Contrast",
                .minimum = 0,
-               .maximum = 0xffff,
+               .maximum = 64725,
                .step    = 1,
-               .default_value = 0xaa00,
+               .default_value = 64725,
            },
            .set = sd_setcontrast,
            .get = sd_getcontrast,
@@ -91,14 +97,42 @@ static struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 63,
                .step    = 1,
-               .default_value = 31,
+               .default_value = 20,
            },
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
+#define MY_BLUE_BALANCE 3
+       {
+           {
+               .id      = V4L2_CID_BLUE_BALANCE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Blue Balance",
+               .minimum = 0,
+               .maximum = 127,
+               .step    = 1,
+               .default_value = 0,
+           },
+           .set = sd_setblue_balance,
+           .get = sd_getblue_balance,
+       },
+#define MY_RED_BALANCE 4
+       {
+           {
+               .id      = V4L2_CID_RED_BALANCE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Red Balance",
+               .minimum = 0,
+               .maximum = 127,
+               .step    = 1,
+               .default_value = 0,
+           },
+           .set = sd_setred_balance,
+           .get = sd_getred_balance,
+       },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 2,
@@ -1822,29 +1856,6 @@ static int reg_write(struct usb_device *dev,
        return ret;
 }
 
-/* returns: negative is error, pos or zero is data */
-static int reg_read(struct gspca_dev *gspca_dev,
-                       __u16 req,      /* bRequest */
-                       __u16 index,    /* wIndex */
-                       __u16 length)   /* wLength (1 or 2 only) */
-{
-       int ret;
-
-       gspca_dev->usb_buf[1] = 0;
-       ret = usb_control_msg(gspca_dev->dev,
-                       usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       req,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0,              /* value */
-                       index,
-                       gspca_dev->usb_buf, length,
-                       500);                   /* timeout */
-       if (ret < 0) {
-               PDEBUG(D_ERR, "reg_read err %d", ret);
-               return -1;
-       }
-       return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
-}
 
 static int write_vector(struct gspca_dev *gspca_dev,
                        const __u16 data[][3])
@@ -1869,18 +1880,11 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->brightness);
        reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, sd->brightness);
-       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->brightness);
 }
 
 static void getbrightness(struct gspca_dev *gspca_dev)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u16 brightness;
-
-       brightness = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x11, 2);
-       sd->brightness = brightness << 1;
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1895,7 +1899,6 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 
 static void getcontrast(struct gspca_dev *gspca_dev)
 {
-/*     spca50x->contrast = 0xaa01; */
 }
 
 static void setcolors(struct gspca_dev *gspca_dev)
@@ -1906,12 +1909,21 @@ static void setcolors(struct gspca_dev *gspca_dev)
 }
 
 static void getcolors(struct gspca_dev *gspca_dev)
+{
+}
+
+static void setblue_balance(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, sd->blue_balance);
+}
+
+static void setred_balance(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->colors = reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x0c, 2);
-/*     sd->hue = (reg_read(gspca_dev, SPCA501_REG_CCDSP, 0x13, */
-/*                     2) & 0xFF) << 8; */
+       reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, sd->red_balance);
 }
 
 /* this function is called at probe time */
@@ -1930,6 +1942,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value;
        sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value;
 
+       return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
        switch (sd->subtype) {
        case Arowana300KCMOSCamera:
        case SmileIntlCamera:
@@ -1948,15 +1968,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        goto error;
                break;
        }
+       PDEBUG(D_STREAM, "Initializing SPCA501 finished");
        return 0;
 error:
        return -EINVAL;
 }
 
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       int mode;
 
        switch (sd->subtype) {
        case ThreeComHomeConnectLite:
@@ -1976,14 +1998,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
                /* Generic 501 open data */
                write_vector(gspca_dev, spca501_open_data);
        }
-       PDEBUG(D_STREAM, "Initializing SPCA501 finished");
-       return 0;
-}
-
-static int sd_start(struct gspca_dev *gspca_dev)
-{
-       struct usb_device *dev = gspca_dev->dev;
-       int mode;
 
        /* memorize the wanted pixel format */
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
@@ -2113,6 +2127,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->blue_balance = val;
+       if (gspca_dev->streaming)
+               setblue_balance(gspca_dev);
+       return 0;
+}
+
+static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->blue_balance;
+       return 0;
+}
+
+static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->red_balance = val;
+       if (gspca_dev->streaming)
+               setred_balance(gspca_dev);
+       return 0;
+}
+
+static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->red_balance;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
index 895b9fe4018c48e8d1bc6b519ed63c7812ffc45c..2a33a29010ee59f62ca2efed92dc874a23b86e30 100644 (file)
@@ -59,7 +59,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 2,
index 645ee9d44d0267dbb908ddf2e9beea692b413d05..96e2512e0621df5e1cebfaafbb98e436676301d1 100644 (file)
@@ -110,7 +110,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 2,
index 63ec902c895d0398116f30732e098d8d74daeb69..be5d740a315d614b95f7077bcb11b4137e65e32e 100644 (file)
@@ -62,7 +62,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 3 / 2,
index c3de4e44123dc1dc0df17256eeaf3b1ae88441cc..3c9288019e96faea92d22ab0b630404f6c5be0a0 100644 (file)
@@ -32,22 +32,22 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       __u16 contrast;                 /* rev72a only */
-#define CONTRAST_MIN 0x0000
-#define CONTRAST_DEF 0x2000
-#define CONTRAST_MAX 0x3fff
-
        __u16 exposure;                 /* rev12a only */
 #define EXPOSURE_MIN 1
 #define EXPOSURE_DEF 200
 #define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
 
+       __u8 contrast;                  /* rev72a only */
+#define CONTRAST_MIN 0x00
+#define CONTRAST_DEF 0x20
+#define CONTRAST_MAX 0x3f
+
        __u8 brightness;                /* rev72a only */
 #define BRIGHTNESS_MIN 0
-#define BRIGHTNESS_DEF 32
-#define BRIGHTNESS_MAX 63
+#define BRIGHTNESS_DEF 0x20
+#define BRIGHTNESS_MAX 0x3f
 
-       __u8 white;                     /* rev12a only */
+       __u8 white;
 #define WHITE_MIN 1
 #define WHITE_DEF 0x40
 #define WHITE_MAX 0x7f
@@ -73,7 +73,7 @@ struct sd {
 #define AG_CNT_START 13
 };
 
-static struct v4l2_pix_format sif_012a_mode[] = {
+static const struct v4l2_pix_format sif_012a_mode[] = {
        {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120,
@@ -96,7 +96,7 @@ static struct v4l2_pix_format sif_012a_mode[] = {
                .priv = 0},
 };
 
-static struct v4l2_pix_format sif_072a_mode[] = {
+static const struct v4l2_pix_format sif_072a_mode[] = {
        {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120,
@@ -146,98 +146,7 @@ static struct v4l2_pix_format sif_072a_mode[] = {
 #define SPCA561_SNAPBIT 0x20
 #define SPCA561_SNAPCTRL 0x40
 
-static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
-{
-       int ret;
-
-       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-                             0,                /* request */
-                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             value, index, NULL, 0, 500);
-       PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
-       if (ret < 0)
-               PDEBUG(D_ERR, "reg write: error %d", ret);
-}
-
-static void write_vector(struct gspca_dev *gspca_dev,
-                       const __u16 data[][2])
-{
-       struct usb_device *dev = gspca_dev->dev;
-       int i;
-
-       i = 0;
-       while (data[i][1] != 0) {
-               reg_w_val(dev, data[i][1], data[i][0]);
-               i++;
-       }
-}
-
-/* read 'len' bytes to gspca_dev->usb_buf */
-static void reg_r(struct gspca_dev *gspca_dev,
-                 __u16 index, __u16 length)
-{
-       usb_control_msg(gspca_dev->dev,
-                       usb_rcvctrlpipe(gspca_dev->dev, 0),
-                       0,                      /* request */
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0,                      /* value */
-                       index, gspca_dev->usb_buf, length, 500);
-}
-
-static void reg_w_buf(struct gspca_dev *gspca_dev,
-                     __u16 index, const __u8 *buffer, __u16 len)
-{
-       memcpy(gspca_dev->usb_buf, buffer, len);
-       usb_control_msg(gspca_dev->dev,
-                       usb_sndctrlpipe(gspca_dev->dev, 0),
-                       0,                      /* request */
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0,                      /* value */
-                       index, gspca_dev->usb_buf, len, 500);
-}
-
-static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg)
-{
-       int retry = 60;
-       __u8 DataLow;
-       __u8 DataHight;
-
-       DataLow = valeur;
-       DataHight = valeur >> 8;
-       reg_w_val(gspca_dev->dev, 0x8801, reg);
-       reg_w_val(gspca_dev->dev, 0x8805, DataLow);
-       reg_w_val(gspca_dev->dev, 0x8800, DataHight);
-       while (retry--) {
-               reg_r(gspca_dev, 0x8803, 1);
-               if (!gspca_dev->usb_buf[0])
-                       break;
-       }
-}
-
-static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
-{
-       int retry = 60;
-       __u8 value;
-       __u8 vallsb;
-
-       reg_w_val(gspca_dev->dev, 0x8804, 0x92);
-       reg_w_val(gspca_dev->dev, 0x8801, reg);
-       reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
-       do {
-               reg_r(gspca_dev, 0x8803, 1);
-               if (!gspca_dev->usb_buf[0])
-                       break;
-       } while (--retry);
-       if (retry == 0)
-               return -1;
-       reg_r(gspca_dev, 0x8800, 1);
-       value = gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8805, 1);
-       vallsb = gspca_dev->usb_buf[0];
-       return ((int) value << 8) | vallsb;
-}
-
-static const __u16 spca561_init_data[][2] = {
+static const __u16 rev72a_init_data1[][2] = {
        {0x0000, 0x8114},       /* Software GPIO output data */
        {0x0001, 0x8114},       /* Software GPIO output data */
        {0x0000, 0x8112},       /* Some kind of reset */
@@ -247,44 +156,26 @@ static const __u16 spca561_init_data[][2] = {
        {0x0001, 0x8118},       /* Conf sensor */
        {0x0092, 0x8804},       /* I know nothing about these */
        {0x0010, 0x8802},       /* 0x88xx registers, so I won't */
-       /***************/
        {0x000d, 0x8805},       /* sensor default setting */
-       {0x0001, 0x8801},       /* 1 <- 0x0d */
-       {0x0000, 0x8800},
-       {0x0018, 0x8805},
-       {0x0002, 0x8801},       /* 2 <- 0x18 */
-       {0x0000, 0x8800},
-       {0x0065, 0x8805},
-       {0x0004, 0x8801},       /* 4 <- 0x01 0x65 */
-       {0x0001, 0x8800},
-       {0x0021, 0x8805},
-       {0x0005, 0x8801},       /* 5 <- 0x21 */
-       {0x0000, 0x8800},
-       {0x00aa, 0x8805},
-       {0x0007, 0x8801},       /* 7 <- 0xaa */
-       {0x0000, 0x8800},
-       {0x0004, 0x8805},
-       {0x0020, 0x8801},       /* 0x20 <- 0x15 0x04 */
-       {0x0015, 0x8800},
-       {0x0002, 0x8805},
-       {0x0039, 0x8801},       /* 0x39 <- 0x02 */
-       {0x0000, 0x8800},
-       {0x0010, 0x8805},
-       {0x0035, 0x8801},       /* 0x35 <- 0x10 */
-       {0x0000, 0x8800},
-       {0x0049, 0x8805},
-       {0x0009, 0x8801},       /* 0x09 <- 0x10 0x49 */
-       {0x0010, 0x8800},
-       {0x000b, 0x8805},
-       {0x0028, 0x8801},       /* 0x28 <- 0x0b */
-       {0x0000, 0x8800},
-       {0x000f, 0x8805},
-       {0x003b, 0x8801},       /* 0x3b <- 0x0f */
-       {0x0000, 0x8800},
-       {0x0000, 0x8805},
-       {0x003c, 0x8801},       /* 0x3c <- 0x00 */
-       {0x0000, 0x8800},
-       /***************/
+       {}
+};
+static const __u16 rev72a_init_sensor1[][2] = {
+                               /* ms-win values */
+       {0x0001, 0x0018},       /* 0x01 <- 0x0d */
+       {0x0002, 0x0065},       /* 0x02 <- 0x18 */
+       {0x0004, 0x0121},       /* 0x04 <- 0x0165 */
+       {0x0005, 0x00aa},       /* 0x05 <- 0x21 */
+       {0x0007, 0x0004},       /* 0x07 <- 0xaa */
+       {0x0020, 0x1502},       /* 0x20 <- 0x1504 */
+       {0x0039, 0x0010},       /* 0x39 <- 0x02 */
+       {0x0035, 0x0049},       /* 0x35 <- 0x10 */
+       {0x0009, 0x100b},       /* 0x09 <- 0x1049 */
+       {0x0028, 0x000f},       /* 0x28 <- 0x0b */
+       {0x003b, 0x003c},       /* 0x3b <- 0x0f */
+       {0x003c, 0x0000},       /* 0x3c <- 0x00 */
+       {}
+};
+static const __u16 rev72a_init_data2[][2] = {
        {0x0018, 0x8601},       /* Pixel/line selection for color separation */
        {0x0000, 0x8602},       /* Optical black level for user setting */
        {0x0060, 0x8604},       /* Optical black horizontal offset */
@@ -309,10 +200,11 @@ static const __u16 spca561_init_data[][2] = {
        {0x0004, 0x8612},       /* Gr offset for white balance */
        {0x0007, 0x8613},       /* B offset for white balance */
        {0x0000, 0x8614},       /* Gb offset for white balance */
-       {0x008c, 0x8651},       /* R gain for white balance */
-       {0x008c, 0x8652},       /* Gr gain for white balance */
-       {0x00b5, 0x8653},       /* B gain for white balance */
-       {0x008c, 0x8654},       /* Gb gain for white balance */
+/* from ms-win */
+       {0x0035, 0x8651},       /* R gain for white balance */
+       {0x0040, 0x8652},       /* Gr gain for white balance */
+       {0x005f, 0x8653},       /* B gain for white balance */
+       {0x0040, 0x8654},       /* Gb gain for white balance */
        {0x0002, 0x8502},       /* Maximum average bit rate stuff */
 
        {0x0011, 0x8802},
@@ -324,29 +216,22 @@ static const __u16 spca561_init_data[][2] = {
 
        {0x0002, 0x865b},       /* Horizontal offset for valid pixels */
        {0x0003, 0x865c},       /* Vertical offset for valid lines */
-       /***************//* sensor active */
-       {0x0003, 0x8801},       /* 0x03 <- 0x01 0x21 //289 */
-       {0x0021, 0x8805},
-       {0x0001, 0x8800},
-       {0x0004, 0x8801},       /* 0x04 <- 0x01 0x65 //357 */
-       {0x0065, 0x8805},
-       {0x0001, 0x8800},
-       {0x0005, 0x8801},       /* 0x05 <- 0x2f */
-       {0x002f, 0x8805},
-       {0x0000, 0x8800},
-       {0x0006, 0x8801},       /* 0x06 <- 0 */
-       {0x0000, 0x8805},
-       {0x0000, 0x8800},
-       {0x000a, 0x8801},       /* 0x0a <- 2 */
-       {0x0002, 0x8805},
-       {0x0000, 0x8800},
-       {0x0009, 0x8801},       /* 0x09 <- 0x1061 */
-       {0x0061, 0x8805},
-       {0x0010, 0x8800},
-       {0x0035, 0x8801},       /* 0x35 <-0x14 */
-       {0x0014, 0x8805},
-       {0x0000, 0x8800},
+       {}
+};
+static const __u16 rev72a_init_sensor2[][2] = {
+                               /* ms-win values */
+       {0x0003, 0x0121},       /* 0x03 <- 0x01 0x21 //289 */
+       {0x0004, 0x0165},       /* 0x04 <- 0x01 0x65 //357 */
+       {0x0005, 0x002f},       /* 0x05 <- 0x2f */
+       {0x0006, 0x0000},       /* 0x06 <- 0 */
+       {0x000a, 0x0002},       /* 0x0a <- 2 */
+       {0x0009, 0x1061},       /* 0x09 <- 0x1061 */
+       {0x0035, 0x0014},       /* 0x35 <- 0x14 */
+       {}
+};
+static const __u16 rev72a_init_data3[][2] = {
        {0x0030, 0x8112},       /* ISO and drop packet enable */
+/*fixme: should stop here*/
        {0x0000, 0x8112},       /* Some kind of reset ???? */
        {0x0009, 0x8118},       /* Enable sensor and set standby */
        {0x0000, 0x8114},       /* Software GPIO output data */
@@ -434,7 +319,6 @@ static const __u16 spca561_init_data[][2] = {
        {}
 };
 
-
 /******************** QC Express etch2 stuff ********************/
 static const __u16 Pb100_1map8300[][2] = {
        /* reg, value */
@@ -515,22 +399,112 @@ static const __u16 spca561_161rev12A_data2[][2] = {
        {}
 };
 
-static void sensor_mapwrite(struct gspca_dev *gspca_dev,
-                           const __u16 sensormap[][2])
+static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
+{
+       int ret;
+
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                             0,                /* request */
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             value, index, NULL, 0, 500);
+       PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write: error %d", ret);
+}
+
+static void write_vector(struct gspca_dev *gspca_dev,
+                       const __u16 data[][2])
 {
-       int i = 0;
-       __u8 usbval[2];
+       struct usb_device *dev = gspca_dev->dev;
+       int i;
 
-       while (sensormap[i][0]) {
-               usbval[0] = sensormap[i][1];
-               usbval[1] = sensormap[i][1] >> 8;
-               reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2);
+       i = 0;
+       while (data[i][1] != 0) {
+               reg_w_val(dev, data[i][1], data[i][0]);
                i++;
        }
 }
+
+/* read 'len' bytes to gspca_dev->usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+                 __u16 index, __u16 length)
+{
+       usb_control_msg(gspca_dev->dev,
+                       usb_rcvctrlpipe(gspca_dev->dev, 0),
+                       0,                      /* request */
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,                      /* value */
+                       index, gspca_dev->usb_buf, length, 500);
+}
+
+/* write 'len' bytes from gspca_dev->usb_buf */
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+                     __u16 index, __u16 len)
+{
+       usb_control_msg(gspca_dev->dev,
+                       usb_sndctrlpipe(gspca_dev->dev, 0),
+                       0,                      /* request */
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0,                      /* value */
+                       index, gspca_dev->usb_buf, len, 500);
+}
+
+static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
+{
+       int retry = 60;
+
+       reg_w_val(gspca_dev->dev, 0x8801, reg);
+       reg_w_val(gspca_dev->dev, 0x8805, value);
+       reg_w_val(gspca_dev->dev, 0x8800, value >> 8);
+       do {
+               reg_r(gspca_dev, 0x8803, 1);
+               if (!gspca_dev->usb_buf[0])
+                       return;
+       } while (--retry);
+}
+
+static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
+{
+       int retry = 60;
+       __u8 value;
+
+       reg_w_val(gspca_dev->dev, 0x8804, 0x92);
+       reg_w_val(gspca_dev->dev, 0x8801, reg);
+       reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01);
+       do {
+               reg_r(gspca_dev, 0x8803, 1);
+               if (!gspca_dev->usb_buf[0]) {
+                       reg_r(gspca_dev, 0x8800, 1);
+                       value = gspca_dev->usb_buf[0];
+                       reg_r(gspca_dev, 0x8805, 1);
+                       return ((int) value << 8) | gspca_dev->usb_buf[0];
+               }
+       } while (--retry);
+       return -1;
+}
+
+static void sensor_mapwrite(struct gspca_dev *gspca_dev,
+                           const __u16 (*sensormap)[2])
+{
+       while ((*sensormap)[0]) {
+               gspca_dev->usb_buf[0] = (*sensormap)[1];
+               gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8;
+               reg_w_buf(gspca_dev, (*sensormap)[0], 2);
+               sensormap++;
+       }
+}
+
+static void write_sensor_72a(struct gspca_dev *gspca_dev,
+                           const __u16 (*sensor)[2])
+{
+       while ((*sensor)[0]) {
+               i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]);
+               sensor++;
+       }
+}
+
 static void init_161rev12A(struct gspca_dev *gspca_dev)
 {
-/*     sensor_reset(gspca_dev);        (not in win) */
        write_vector(gspca_dev, spca561_161rev12A_data1);
        sensor_mapwrite(gspca_dev, Pb100_1map8300);
 /*fixme: should be in sd_start*/
@@ -598,49 +572,68 @@ static int sd_init_12a(struct gspca_dev *gspca_dev)
 static int sd_init_72a(struct gspca_dev *gspca_dev)
 {
        PDEBUG(D_STREAM, "Chip revision: 072a");
-       write_vector(gspca_dev, spca561_init_data);
+       write_vector(gspca_dev, rev72a_init_data1);
+       write_sensor_72a(gspca_dev, rev72a_init_sensor1);
+       write_vector(gspca_dev, rev72a_init_data2);
+       write_sensor_72a(gspca_dev, rev72a_init_sensor2);
+       write_vector(gspca_dev, rev72a_init_data3);
        return 0;
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* rev 72a only */
+static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
-       __u8 lowb;
+       __u8 value;
 
-       switch (sd->chip_revision) {
-       case Rev072A:
-               lowb = sd->contrast >> 8;
-               reg_w_val(dev, 0x8651, lowb);
-               reg_w_val(dev, 0x8652, lowb);
-               reg_w_val(dev, 0x8653, lowb);
-               reg_w_val(dev, 0x8654, lowb);
-               break;
-       default: {
-/*     case Rev012A: { */
-               static const __u8 Reg8391[] =
-                       { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 };
+       value = sd->brightness;
 
-               reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
-               reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
-               break;
-           }
-       }
+       /* offsets for white balance */
+       reg_w_val(dev, 0x8611, value);          /* R */
+       reg_w_val(dev, 0x8612, value);          /* Gr */
+       reg_w_val(dev, 0x8613, value);          /* B */
+       reg_w_val(dev, 0x8614, value);          /* Gb */
 }
 
-/* rev12a only */
 static void setwhite(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        __u16 white;
-       __u8 reg8614, reg8616;
+       __u8 blue, red;
+       __u16 reg;
 
-       white = sd->white;
        /* try to emulate MS-win as possible */
-       reg8616 = 0x90 - white * 5 / 8;
-       reg_w_val(gspca_dev->dev, 0x8616, reg8616);
-       reg8614 = 0x20 + white * 3 / 8;
-       reg_w_val(gspca_dev->dev, 0x8614, reg8614);
+       white = sd->white;
+       red = 0x20 + white * 3 / 8;
+       blue = 0x90 - white * 5 / 8;
+       if (sd->chip_revision == Rev012A) {
+               reg = 0x8614;
+       } else {
+               reg = 0x8651;
+               red += sd->contrast - 0x20;
+               blue += sd->contrast - 0x20;
+       }
+       reg_w_val(gspca_dev->dev, reg, red);
+       reg_w_val(gspca_dev->dev, reg + 2, blue);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct usb_device *dev = gspca_dev->dev;
+       __u8 value;
+
+       if (sd->chip_revision != Rev072A)
+               return;
+       value = sd->contrast + 0x20;
+
+       /* gains for white balance */
+       setwhite(gspca_dev);
+/*     reg_w_val(dev, 0x8651, value);           * R - done by setwhite */
+       reg_w_val(dev, 0x8652, value);          /* Gr */
+/*     reg_w_val(dev, 0x8653, value);           * B - done by setwhite */
+       reg_w_val(dev, 0x8654, value);          /* Gb */
 }
 
 /* rev 12a only */
@@ -649,7 +642,6 @@ static void setexposure(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        int expo;
        int clock_divider;
-       __u8 data[2];
 
        /* Register 0x8309 controls exposure for the spca561,
           the basic exposure setting goes from 1-2047, where 1 is completely
@@ -673,20 +665,19 @@ static void setexposure(struct gspca_dev *gspca_dev)
                clock_divider = 3;
        }
        expo |= clock_divider << 11;
-       data[0] = expo;
-       data[1] = expo >> 8;
-       reg_w_buf(gspca_dev, 0x8309, data, 2);
+       gspca_dev->usb_buf[0] = expo;
+       gspca_dev->usb_buf[1] = expo >> 8;
+       reg_w_buf(gspca_dev, 0x8309, 2);
 }
 
 /* rev 12a only */
 static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 data[2];
 
-       data[0] = sd->gain;
-       data[1] = 0;
-       reg_w_buf(gspca_dev, 0x8335, data, 2);
+       gspca_dev->usb_buf[0] = sd->gain;
+       gspca_dev->usb_buf[1] = 0;
+       reg_w_buf(gspca_dev, 0x8335, 2);
 }
 
 static void setautogain(struct gspca_dev *gspca_dev)
@@ -702,9 +693,9 @@ static void setautogain(struct gspca_dev *gspca_dev)
 static int sd_start_12a(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
-       int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
-       __u8 Reg8307[] = { 0xaa, 0x00 };
        int mode;
+       static const __u8 Reg8391[8] =
+               {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
 
        mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
        if (mode <= 1) {
@@ -716,14 +707,21 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
                 * is sufficient to push raw frames at ~20fps */
                reg_w_val(dev, 0x8500, mode);
        }               /* -- qq@kuku.eu.org */
-       reg_w_buf(gspca_dev, 0x8307, Reg8307, 2);
-       reg_w_val(gspca_dev->dev, 0x8700, Clck);
+
+       gspca_dev->usb_buf[0] = 0xaa;
+       gspca_dev->usb_buf[1] = 0x00;
+       reg_w_buf(gspca_dev, 0x8307, 2);
+       /* clock - lower 0x8X values lead to fps > 30 */
+       reg_w_val(gspca_dev->dev, 0x8700, 0x8a);
                                        /* 0x8f 0x85 0x27 clock */
        reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
        reg_w_val(gspca_dev->dev, 0x850b, 0x03);
-       setcontrast(gspca_dev);
+       memcpy(gspca_dev->usb_buf, Reg8391, 8);
+       reg_w_buf(gspca_dev, 0x8391, 8);
+       reg_w_buf(gspca_dev, 0x8390, 8);
        setwhite(gspca_dev);
        setautogain(gspca_dev);
+/*     setgain(gspca_dev);             */
        setexposure(gspca_dev);
        return 0;
 }
@@ -750,6 +748,9 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
        reg_w_val(dev, 0x8500, mode);   /* mode */
        reg_w_val(dev, 0x8700, Clck);   /* 0x27 clock */
        reg_w_val(dev, 0x8112, 0x10 | 0x20);
+       setcontrast(gspca_dev);
+/*     setbrightness(gspca_dev);        * fixme: bad values */
+       setwhite(gspca_dev);
        setautogain(gspca_dev);
        return 0;
 }
@@ -791,7 +792,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        __u8 luma_mean = 110;
        __u8 luma_delta = 20;
        __u8 spring = 4;
-       __u8 reg8339[2];
 
        if (sd->ag_cnt < 0)
                return;
@@ -834,13 +834,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
 
                        if (gainG > 0x3f)
                                gainG = 0x3f;
-                       else if (gainG < 4)
+                       else if (gainG < 3)
                                gainG = 3;
                        i2c_write(gspca_dev, gainG, 0x35);
 
-                       if (expotimes >= 0x0256)
+                       if (expotimes > 0x0256)
                                expotimes = 0x0256;
-                       else if (expotimes < 4)
+                       else if (expotimes < 3)
                                expotimes = 3;
                        i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
                }
@@ -848,13 +848,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        case Rev012A:
                reg_r(gspca_dev, 0x8330, 2);
                if (gspca_dev->usb_buf[1] > 0x08) {
-                       reg8339[0] = ++sd->expo12a;
-                       reg8339[1] = 0;
-                       reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+                       gspca_dev->usb_buf[0] = ++sd->expo12a;
+                       gspca_dev->usb_buf[1] = 0;
+                       reg_w_buf(gspca_dev, 0x8339, 2);
                } else if (gspca_dev->usb_buf[1] < 0x02) {
-                       reg8339[0] = --sd->expo12a;
-                       reg8339[1] = 0;
-                       reg_w_buf(gspca_dev, 0x8339, reg8339, 2);
+                       gspca_dev->usb_buf[0] = --sd->expo12a;
+                       gspca_dev->usb_buf[1] = 0;
+                       reg_w_buf(gspca_dev, 0x8339, 2);
                }
                break;
        }
@@ -867,8 +867,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       switch (data[0]) {
-       case 0:         /* start of frame */
+       switch (data[0]) {                      /* sequence number */
+       case 0:                                 /* start of frame */
                frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
                                        data, 0);
                data += SPCA561_OFFSET_DATA;
@@ -890,8 +890,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                                frame, data, len);
                }
                return;
-       case 0xff:              /* drop */
-/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
+       case 0xff:                      /* drop (empty mpackets) */
                return;
        }
        data++;
@@ -899,55 +898,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-/* rev 72a only */
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u8 value;
-
-       value = sd->brightness;
-       reg_w_val(gspca_dev->dev, 0x8611, value);
-       reg_w_val(gspca_dev->dev, 0x8612, value);
-       reg_w_val(gspca_dev->dev, 0x8613, value);
-       reg_w_val(gspca_dev->dev, 0x8614, value);
-}
-
-static void getbrightness(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u16 tot;
-
-       tot = 0;
-       reg_r(gspca_dev, 0x8611, 1);
-       tot += gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8612, 1);
-       tot += gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8613, 1);
-       tot += gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8614, 1);
-       tot += gspca_dev->usb_buf[0];
-       sd->brightness = tot >> 2;
-}
-
-/* rev72a only */
-static void getcontrast(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       __u16 tot;
-
-       tot = 0;
-       reg_r(gspca_dev, 0x8651, 1);
-       tot += gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8652, 1);
-       tot += gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8653, 1);
-       tot += gspca_dev->usb_buf[0];
-       reg_r(gspca_dev, 0x8654, 1);
-       tot += gspca_dev->usb_buf[0];
-       sd->contrast = tot << 6;
-       PDEBUG(D_CONF, "get contrast %d", sd->contrast);
-}
-
 /* rev 72a only */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
@@ -963,7 +913,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getbrightness(gspca_dev);
        *val = sd->brightness;
        return 0;
 }
@@ -983,7 +932,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       getcontrast(gspca_dev);
        *val = sd->contrast;
        return 0;
 }
@@ -1006,7 +954,6 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-/* rev12a only */
 static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1120,6 +1067,19 @@ static struct ctrl sd_ctrls_12a[] = {
 };
 
 static struct ctrl sd_ctrls_72a[] = {
+       {
+           {
+               .id = V4L2_CID_DO_WHITE_BALANCE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "White Balance",
+               .minimum = WHITE_MIN,
+               .maximum = WHITE_MAX,
+               .step = 1,
+               .default_value = WHITE_DEF,
+           },
+           .set = sd_setwhite,
+           .get = sd_getwhite,
+       },
        {
           {
                .id = V4L2_CID_BRIGHTNESS,
index d9d64911f22a21220e73f0aa05ea5e415419ea87..60de9af87fbbe02504aec63ca6891881d7283f26 100644 (file)
@@ -109,7 +109,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -424,10 +424,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 
                /* beginning of the frame */
 #define STKHDRSZ 12
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                               data + STKHDRSZ, len - STKHDRSZ);
-#undef STKHDRSZ
-               return;
+               data += STKHDRSZ;
+               len -= STKHDRSZ;
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
diff --git a/drivers/media/video/gspca/stv06xx/Kconfig b/drivers/media/video/gspca/stv06xx/Kconfig
new file mode 100644 (file)
index 0000000..634ad38
--- /dev/null
@@ -0,0 +1,9 @@
+config USB_STV06XX
+       tristate "STV06XX USB Camera Driver"
+       depends on USB_GSPCA
+       help
+         Say Y here if you want support for cameras based on
+         the ST STV06XX chip.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gspca_stv06xx.
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile
new file mode 100644 (file)
index 0000000..feeaa94
--- /dev/null
@@ -0,0 +1,9 @@
+obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
+
+gspca_stv06xx-objs := stv06xx.o \
+                     stv06xx_vv6410.o \
+                     stv06xx_hdcs.o \
+                     stv06xx_pb0100.o
+
+EXTRA_CFLAGS += -Idrivers/media/video/gspca
+
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
new file mode 100644 (file)
index 0000000..13a021e
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#include "stv06xx_sensor.h"
+
+MODULE_AUTHOR("Erik Andrén");
+MODULE_DESCRIPTION("STV06XX USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+static int dump_bridge;
+static int dump_sensor;
+
+int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
+{
+       int err;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+       u8 len = (i2c_data > 0xff) ? 2 : 1;
+
+       buf[0] = i2c_data & 0xff;
+       buf[1] = (i2c_data >> 8) & 0xff;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, address, 0, buf, len,
+                             STV06XX_URB_MSG_TIMEOUT);
+
+
+       PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d",
+              i2c_data, address, err);
+
+       return (err < 0) ? err : 0;
+}
+
+int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data)
+{
+       int err;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                             0x04, 0xc0, address, 0, buf, 1,
+                             STV06XX_URB_MSG_TIMEOUT);
+
+       *i2c_data = buf[0];
+
+       PDEBUG(D_CONF, "Read 0x%x from address 0x%x, status %d",
+              *i2c_data, address, err);
+
+       return (err < 0) ? err : 0;
+}
+
+/* Wraps the normal write sensor bytes / words functions for writing a
+   single value */
+int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value)
+{
+       if (sd->sensor->i2c_len == 2) {
+               u16 data[2] = { address, value };
+               return stv06xx_write_sensor_words(sd, data, 1);
+       } else {
+               u8 data[2] = { address, value };
+               return stv06xx_write_sensor_bytes(sd, data, 1);
+       }
+}
+
+static int stv06xx_write_sensor_finish(struct sd *sd)
+{
+       int err = 0;
+
+       if (IS_850(sd)) {
+               struct usb_device *udev = sd->gspca_dev.dev;
+               __u8 *buf = sd->gspca_dev.usb_buf;
+
+               /* Quickam Web needs an extra packet */
+               buf[0] = 0;
+               err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                     0x04, 0x40, 0x1704, 0, buf, 1,
+                                     STV06XX_URB_MSG_TIMEOUT);
+       }
+
+       return (err < 0) ? err : 0;
+}
+
+int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
+{
+       int err, i, j;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
+       for (i = 0; i < len;) {
+               /* Build the command buffer */
+               memset(buf, 0, I2C_BUFFER_LENGTH);
+               for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) {
+                       buf[j] = data[2*i];
+                       buf[0x10 + j] = data[2*i+1];
+                       PDEBUG(D_USBO, "I2C: Writing 0x%02x to reg 0x%02x",
+                       data[2*i+1], data[2*i]);
+               }
+               buf[0x20] = sd->sensor->i2c_addr;
+               buf[0x21] = j - 1; /* Number of commands to send - 1 */
+               buf[0x22] = I2C_WRITE_CMD;
+               err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                     0x04, 0x40, 0x0400, 0, buf,
+                                     I2C_BUFFER_LENGTH,
+                                     STV06XX_URB_MSG_TIMEOUT);
+                                     if (err < 0)
+                                       return err;
+       }
+       return stv06xx_write_sensor_finish(sd);
+}
+
+int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
+{
+       int err, i, j;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
+
+       for (i = 0; i < len;) {
+               /* Build the command buffer */
+               memset(buf, 0, I2C_BUFFER_LENGTH);
+               for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) {
+                       buf[j] = data[2*i];
+                       buf[0x10 + j * 2] = data[2*i+1];
+                       buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8;
+                       PDEBUG(D_USBO, "I2C: Writing 0x%04x to reg 0x%02x",
+                               data[2*i+1], data[2*i]);
+               }
+               buf[0x20] = sd->sensor->i2c_addr;
+               buf[0x21] = j - 1; /* Number of commands to send - 1 */
+               buf[0x22] = I2C_WRITE_CMD;
+               err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               0x04, 0x40, 0x0400, 0, buf,
+                               I2C_BUFFER_LENGTH,
+                               STV06XX_URB_MSG_TIMEOUT);
+               if (err < 0)
+                       return err;
+       }
+       return stv06xx_write_sensor_finish(sd);
+}
+
+int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
+{
+       int err;
+       struct usb_device *udev = sd->gspca_dev.dev;
+       __u8 *buf = sd->gspca_dev.usb_buf;
+
+       err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush);
+       if (err < 0)
+               return err;
+
+       /* Clear mem */
+       memset(buf, 0, I2C_BUFFER_LENGTH);
+
+       buf[0] = address;
+       buf[0x20] = sd->sensor->i2c_addr;
+       buf[0x21] = 0;
+
+       /* Read I2C register */
+       buf[0x22] = I2C_READ_CMD;
+
+       err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                             0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
+                             STV06XX_URB_MSG_TIMEOUT);
+       if (err < 0) {
+               PDEBUG(D_ERR, "I2C Read: error writing address: %d", err);
+               return err;
+       }
+
+       err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                             0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len,
+                             STV06XX_URB_MSG_TIMEOUT);
+       if (sd->sensor->i2c_len == 2)
+               *value = buf[0] | (buf[1] << 8);
+       else
+               *value = buf[0];
+
+       PDEBUG(D_USBO, "I2C: Read 0x%x from address 0x%x, status: %d",
+              *value, address, err);
+
+       return (err < 0) ? err : 0;
+}
+
+/* Dumps all bridge registers */
+static void stv06xx_dump_bridge(struct sd *sd)
+{
+       int i;
+       u8 data, buf;
+
+       info("Dumping all stv06xx bridge registers");
+       for (i = 0x1400; i < 0x160f; i++) {
+               stv06xx_read_bridge(sd, i, &data);
+
+               info("Read 0x%x from address 0x%x", data, i);
+       }
+
+       for (i = 0x1400; i < 0x160f; i++) {
+               stv06xx_read_bridge(sd, i, &data);
+               buf = data;
+
+               stv06xx_write_bridge(sd, i, 0xff);
+               stv06xx_read_bridge(sd, i, &data);
+               if (data == 0xff)
+                       info("Register 0x%x is read/write", i);
+               else if (data != buf)
+                       info("Register 0x%x is read/write,"
+                            "but only partially", i);
+               else
+                       info("Register 0x%x is read-only", i);
+
+               stv06xx_write_bridge(sd, i, buf);
+       }
+}
+
+/* this function is called at probe and resume time */
+static int stv06xx_init(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+
+       PDEBUG(D_PROBE, "Initializing camera");
+
+       /* Let the usb init settle for a bit
+          before performing the initialization */
+       msleep(250);
+
+       err = sd->sensor->init(sd);
+
+       if (dump_sensor)
+               sd->sensor->dump(sd);
+
+       return (err < 0) ? err : 0;
+}
+
+/* Start the camera */
+static int stv06xx_start(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+
+       /* Prepare the sensor for start */
+       err = sd->sensor->start(sd);
+       if (err < 0)
+               goto out;
+
+       /* Start isochronous streaming */
+       err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1);
+
+out:
+       if (err < 0)
+               PDEBUG(D_STREAM, "Starting stream failed");
+       else
+               PDEBUG(D_STREAM, "Started streaming");
+
+       return (err < 0) ? err : 0;
+}
+
+static void stv06xx_stopN(struct gspca_dev *gspca_dev)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       /* stop ISO-streaming */
+       err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0);
+       if (err < 0)
+               goto out;
+
+       err = sd->sensor->stop(sd);
+       if (err < 0)
+               goto out;
+
+out:
+       if (err < 0)
+               PDEBUG(D_STREAM, "Failed to stop stream");
+       else
+               PDEBUG(D_STREAM, "Stopped streaming");
+}
+
+/*
+ * Analyse an USB packet of the data stream and store it appropriately.
+ * Each packet contains an integral number of chunks. Each chunk has
+ * 2-bytes identification, followed by 2-bytes that describe the chunk
+ * length. Known/guessed chunk identifications are:
+ * 8001/8005/C001/C005 - Begin new frame
+ * 8002/8006/C002/C006 - End frame
+ * 0200/4200           - Contains actual image data, bayer or compressed
+ * 0005                - 11 bytes of unknown data
+ * 0100                - 2 bytes of unknown data
+ * The 0005 and 0100 chunks seem to appear only in compressed stream.
+ */
+static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       PDEBUG(D_PACK, "Packet of length %d arrived", len);
+
+       /* A packet may contain several frames
+          loop until the whole packet is reached */
+       while (len) {
+               int id, chunk_len;
+
+               if (len < 4) {
+                       PDEBUG(D_PACK, "Packet is smaller than 4 bytes");
+                       return;
+               }
+
+               /* Capture the id */
+               id = (data[0] << 8) | data[1];
+
+               /* Capture the chunk length */
+               chunk_len = (data[2] << 8) | data[3];
+               PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len);
+
+               data += 4;
+               len -= 4;
+
+               if (len < chunk_len) {
+                       PDEBUG(D_ERR, "URB packet length is smaller"
+                               " than the specified chunk length");
+                       return;
+               }
+
+               switch (id) {
+               case 0x0200:
+               case 0x4200:
+                       PDEBUG(D_PACK, "Frame data packet detected");
+
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, chunk_len);
+                       break;
+
+               case 0x8001:
+               case 0x8005:
+               case 0xc001:
+               case 0xc005:
+                       PDEBUG(D_PACK, "Starting new frame");
+
+                       /* Create a new frame, chunk length should be zero */
+                       gspca_frame_add(gspca_dev, FIRST_PACKET,
+                                       frame, data, 0);
+
+                       if (chunk_len)
+                               PDEBUG(D_ERR, "Chunk length is "
+                                             "non-zero on a SOF");
+                       break;
+
+               case 0x8002:
+               case 0x8006:
+               case 0xc002:
+                       PDEBUG(D_PACK, "End of frame detected");
+
+                       /* Complete the last frame (if any) */
+                       gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+
+                       if (chunk_len)
+                               PDEBUG(D_ERR, "Chunk length is "
+                                             "non-zero on a EOF");
+                       break;
+
+               case 0x0005:
+                       PDEBUG(D_PACK, "Chunk 0x005 detected");
+                       /* Unknown chunk with 11 bytes of data,
+                          occurs just before end of each frame
+                          in compressed mode */
+                       break;
+
+               case 0x0100:
+                       PDEBUG(D_PACK, "Chunk 0x0100 detected");
+                       /* Unknown chunk with 2 bytes of data,
+                          occurs 2-3 times per USB interrupt */
+                       break;
+               default:
+                       PDEBUG(D_PACK, "Unknown chunk %d detected", id);
+                       /* Unknown chunk */
+               }
+               data    += chunk_len;
+               len     -= chunk_len;
+       }
+}
+
+static int stv06xx_config(struct gspca_dev *gspca_dev,
+                         const struct usb_device_id *id);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+       .name = MODULE_NAME,
+       .config = stv06xx_config,
+       .init = stv06xx_init,
+       .start = stv06xx_start,
+       .stopN = stv06xx_stopN,
+       .pkt_scan = stv06xx_pkt_scan
+};
+
+/* This function is called at probe time */
+static int stv06xx_config(struct gspca_dev *gspca_dev,
+                         const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+
+       PDEBUG(D_PROBE, "Configuring camera");
+
+       cam = &gspca_dev->cam;
+       cam->epaddr = STV_ISOC_ENDPOINT_ADDR;
+       sd->desc = sd_desc;
+       gspca_dev->sd_desc = &sd->desc;
+
+       if (dump_bridge)
+               stv06xx_dump_bridge(sd);
+
+       sd->sensor = &stv06xx_sensor_vv6410;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       sd->sensor = &stv06xx_sensor_hdcs1x00;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       sd->sensor = &stv06xx_sensor_hdcs1020;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       sd->sensor = &stv06xx_sensor_pb0100;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
+       sd->sensor = NULL;
+       return -ENODEV;
+}
+
+
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */
+       {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */
+       {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */
+       {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+                       const struct usb_device_id *id)
+{
+       PDEBUG(D_PROBE, "Probing for a stv06xx device");
+       return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+                              THIS_MODULE);
+}
+
+static void sd_disconnect(struct usb_interface *intf)
+{
+       struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+       struct sd *sd = (struct sd *) gspca_dev;
+       PDEBUG(D_PROBE, "Disconnecting the stv06xx device");
+
+       if (sd->sensor->disconnect)
+               sd->sensor->disconnect(sd);
+       gspca_disconnect(intf);
+}
+
+static struct usb_driver sd_driver = {
+       .name = MODULE_NAME,
+       .id_table = device_table,
+       .probe = sd_probe,
+       .disconnect = sd_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+       if (usb_register(&sd_driver) < 0)
+               return -1;
+       PDEBUG(D_PROBE, "registered");
+       return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+       usb_deregister(&sd_driver);
+       PDEBUG(D_PROBE, "deregistered");
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
+
+module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
+
+module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup");
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
new file mode 100644 (file)
index 0000000..1207e7d
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#ifndef STV06XX_H_
+#define STV06XX_H_
+
+#include "gspca.h"
+
+#define MODULE_NAME "STV06xx"
+
+#define STV_ISOC_ENDPOINT_ADDR         0x81
+
+#ifndef V4L2_PIX_FMT_SGRBG8
+#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G')
+#endif
+
+#define STV_REG23                      0x0423
+
+/* Control registers of the STV0600 ASIC */
+#define STV_I2C_PARTNER                        0x1420
+#define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421
+#define STV_I2C_READ_WRITE_TOGGLE      0x1422
+#define STV_I2C_FLUSH                  0x1423
+#define STV_I2C_SUCC_READ_REG_VALS     0x1424
+
+#define STV_ISO_ENABLE                 0x1440
+#define STV_SCAN_RATE                  0x1443
+#define STV_LED_CTRL                   0x1445
+#define STV_STV0600_EMULATION          0x1446
+#define STV_REG00                      0x1500
+#define STV_REG01                      0x1501
+#define STV_REG02                      0x1502
+#define STV_REG03                      0x1503
+#define STV_REG04                      0x1504
+
+#define STV_ISO_SIZE_L                 0x15c1
+#define STV_ISO_SIZE_H                 0x15c2
+
+/* Refers to the CIF 352x288 and QCIF 176x144 */
+/* 1: 288 lines, 2: 144 lines */
+#define STV_Y_CTRL                     0x15c3
+
+/* 0xa: 352 columns, 0x6: 176 columns */
+#define STV_X_CTRL                     0x1680
+
+#define STV06XX_URB_MSG_TIMEOUT                5000
+
+#define I2C_MAX_BYTES                  16
+#define I2C_MAX_WORDS                  8
+
+#define I2C_BUFFER_LENGTH              0x23
+#define I2C_READ_CMD                   3
+#define I2C_WRITE_CMD                  1
+
+#define LED_ON                         1
+#define LED_OFF                                0
+
+/* STV06xx device descriptor */
+struct sd {
+       struct gspca_dev gspca_dev;
+
+       /* A pointer to the currently connected sensor */
+       const struct stv06xx_sensor *sensor;
+
+       /* A pointer to the sd_desc struct */
+       struct sd_desc desc;
+
+       /* Sensor private data */
+       void *sensor_priv;
+};
+
+int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data);
+int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data);
+
+int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len);
+int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len);
+
+int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value);
+int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value);
+
+#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
new file mode 100644 (file)
index 0000000..14335a9
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ * Copyright (c) 2008 Chia-I Wu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#include "stv06xx_hdcs.h"
+
+enum hdcs_power_state {
+       HDCS_STATE_SLEEP,
+       HDCS_STATE_IDLE,
+       HDCS_STATE_RUN
+};
+
+/* no lock? */
+struct hdcs {
+       enum hdcs_power_state state;
+       int w, h;
+
+       /* visible area of the sensor array */
+       struct {
+               int left, top;
+               int width, height;
+               int border;
+       } array;
+
+       struct {
+               /* Column timing overhead */
+               u8 cto;
+               /* Column processing overhead */
+               u8 cpo;
+               /* Row sample period constant */
+               u16 rs;
+               /* Exposure reset duration */
+               u16 er;
+       } exp;
+
+       int psmp;
+};
+
+static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
+{
+       u8 regs[I2C_MAX_BYTES * 2];
+       int i;
+
+       if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) ||
+                    (reg + len > 0xff)))
+               return -EINVAL;
+
+       for (i = 0; i < len; i++, reg++) {
+               regs[2*i] = reg;
+               regs[2*i+1] = vals[i];
+       }
+
+       return stv06xx_write_sensor_bytes(sd, regs, len);
+}
+
+static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
+{
+       struct hdcs *hdcs = sd->sensor_priv;
+       u8 val;
+       int ret;
+
+       if (hdcs->state == state)
+               return 0;
+
+       /* we need to go idle before running or sleeping */
+       if (hdcs->state != HDCS_STATE_IDLE) {
+               ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
+               if (ret)
+                       return ret;
+       }
+
+       hdcs->state = HDCS_STATE_IDLE;
+
+       if (state == HDCS_STATE_IDLE)
+               return 0;
+
+       switch (state) {
+       case HDCS_STATE_SLEEP:
+               val = HDCS_SLEEP_MODE;
+               break;
+
+       case HDCS_STATE_RUN:
+               val = HDCS_RUN_ENABLE;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
+       if (ret < 0)
+               hdcs->state = state;
+
+       return ret;
+}
+
+static int hdcs_reset(struct sd *sd)
+{
+       struct hdcs *hdcs = sd->sensor_priv;
+       int err;
+
+       err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
+       if (err < 0)
+               hdcs->state = HDCS_STATE_IDLE;
+
+       return err;
+}
+
+static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct hdcs *hdcs = sd->sensor_priv;
+
+       /* Column time period */
+       int ct;
+       /* Column processing period */
+       int cp;
+       /* Row processing period */
+       int rp;
+       int cycles;
+       int err;
+       int rowexp;
+       u16 data[2];
+
+       err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]);
+       if (err < 0)
+               return err;
+
+       rowexp = (data[1] << 8) | data[0];
+
+       ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
+       cp = hdcs->exp.cto + (hdcs->w * ct / 2);
+       rp = hdcs->exp.rs + cp;
+
+       cycles = rp * rowexp;
+       *val = cycles / HDCS_CLK_FREQ_MHZ;
+       PDEBUG(D_V4L2, "Read exposure %d", *val);
+       return 0;
+}
+
+static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct hdcs *hdcs = sd->sensor_priv;
+       int rowexp, srowexp;
+       int max_srowexp;
+       /* Column time period */
+       int ct;
+       /* Column processing period */
+       int cp;
+       /* Row processing period */
+       int rp;
+       /* Minimum number of column timing periods
+          within the column processing period */
+       int mnct;
+       int cycles, err;
+       u8 exp[4];
+
+       cycles = val * HDCS_CLK_FREQ_MHZ;
+
+       ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
+       cp = hdcs->exp.cto + (hdcs->w * ct / 2);
+
+       /* the cycles one row takes */
+       rp = hdcs->exp.rs + cp;
+
+       rowexp = cycles / rp;
+
+       /* the remaining cycles */
+       cycles -= rowexp * rp;
+
+       /* calculate sub-row exposure */
+       if (IS_1020(sd)) {
+               /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */
+               srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct;
+
+               mnct = (hdcs->exp.er + 12 + ct - 1) / ct;
+               max_srowexp = hdcs->w - mnct;
+       } else {
+               /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */
+               srowexp = cp - hdcs->exp.er - 6 - cycles;
+
+               mnct = (hdcs->exp.er + 5 + ct - 1) / ct;
+               max_srowexp = cp - mnct * ct - 1;
+       }
+
+       if (srowexp < 0)
+               srowexp = 0;
+       else if (srowexp > max_srowexp)
+               srowexp = max_srowexp;
+
+       if (IS_1020(sd)) {
+               exp[0] = rowexp & 0xff;
+               exp[1] = rowexp >> 8;
+               exp[2] = (srowexp >> 2) & 0xff;
+               /* this clears exposure error flag */
+               exp[3] = 0x1;
+               err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+       } else {
+               exp[0] = rowexp & 0xff;
+               exp[1] = rowexp >> 8;
+               exp[2] = srowexp & 0xff;
+               exp[3] = srowexp >> 8;
+               err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+               if (err < 0)
+                       return err;
+
+               /* clear exposure error flag */
+               err = stv06xx_write_sensor(sd,
+                    HDCS_STATUS, BIT(4));
+       }
+       PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
+              val, rowexp, srowexp);
+       return err;
+}
+
+static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b)
+{
+       u8 gains[4];
+
+       /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
+       if (r > 127)
+               r = 0x80 | (r / 2);
+       if (g > 127)
+               g = 0x80 | (g / 2);
+       if (b > 127)
+               b = 0x80 | (b / 2);
+
+       gains[0] = g;
+       gains[1] = r;
+       gains[2] = b;
+       gains[3] = g;
+
+       return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
+}
+
+static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+       u16 data;
+
+       err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data);
+
+       /* Bit 7 doubles the gain */
+       if (data & 0x80)
+               *val = (data & 0x7f) * 2;
+       else
+               *val = data;
+
+       PDEBUG(D_V4L2, "Read gain %d", *val);
+       return err;
+}
+
+static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       PDEBUG(D_V4L2, "Writing gain %d", val);
+       return hdcs_set_gains((struct sd *) gspca_dev,
+                              val & 0xff, val & 0xff, val & 0xff);
+}
+
+static int hdcs_set_size(struct sd *sd,
+               unsigned int width, unsigned int height)
+{
+       struct hdcs *hdcs = sd->sensor_priv;
+       u8 win[4];
+       unsigned int x, y;
+       int err;
+
+       /* must be multiple of 4 */
+       width = (width + 3) & ~0x3;
+       height = (height + 3) & ~0x3;
+
+       if (width > hdcs->array.width)
+               width = hdcs->array.width;
+
+       if (IS_1020(sd)) {
+               /* the borders are also invalid */
+               if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP
+                                 > hdcs->array.height)
+                       height = hdcs->array.height - 2 * hdcs->array.border -
+                               HDCS_1020_BOTTOM_Y_SKIP;
+
+               y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2
+                               + hdcs->array.top;
+       } else {
+               if (height > hdcs->array.height)
+                       height = hdcs->array.height;
+
+               y = hdcs->array.top + (hdcs->array.height - height) / 2;
+       }
+
+       x = hdcs->array.left + (hdcs->array.width - width) / 2;
+
+       win[0] = y / 4;
+       win[1] = x / 4;
+       win[2] = (y + height) / 4 - 1;
+       win[3] = (x + width) / 4 - 1;
+
+       err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4);
+       if (err < 0)
+               return err;
+
+       /* Update the current width and height */
+       hdcs->w = width;
+       hdcs->h = height;
+       return err;
+}
+
+static int hdcs_probe_1x00(struct sd *sd)
+{
+       struct hdcs *hdcs;
+       u16 sensor;
+       int ret;
+
+       ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
+       if (ret < 0 || sensor != 0x08)
+               return -ENODEV;
+
+       info("HDCS-1000/1100 sensor detected");
+
+       sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1x00.modes;
+       sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1x00.nmodes;
+       sd->desc.ctrls = stv06xx_sensor_hdcs1x00.ctrls;
+       sd->desc.nctrls = stv06xx_sensor_hdcs1x00.nctrls;
+
+       hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
+       if (!hdcs)
+               return -ENOMEM;
+
+       hdcs->array.left = 8;
+       hdcs->array.top = 8;
+       hdcs->array.width = HDCS_1X00_DEF_WIDTH;
+       hdcs->array.height = HDCS_1X00_DEF_HEIGHT;
+       hdcs->array.border = 4;
+
+       hdcs->exp.cto = 4;
+       hdcs->exp.cpo = 2;
+       hdcs->exp.rs = 186;
+       hdcs->exp.er = 100;
+
+       /*
+        * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP:
+        *  4 = doesn't work at all
+        *  5 = 7.8 fps,
+        *  6 = 6.9 fps,
+        *  8 = 6.3 fps,
+        * 10 = 5.5 fps,
+        * 15 = 4.4 fps,
+        * 31 = 2.8 fps
+        *
+        * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP:
+        * 15 = doesn't work at all
+        * 18 = doesn't work at all
+        * 19 = 7.3 fps
+        * 20 = 7.4 fps
+        * 21 = 7.4 fps
+        * 22 = 7.4 fps
+        * 24 = 6.3 fps
+        * 30 = 5.4 fps
+        */
+       hdcs->psmp = IS_870(sd) ? 20 : 5;
+
+       sd->sensor_priv = hdcs;
+
+       return 0;
+}
+
+static int hdcs_probe_1020(struct sd *sd)
+{
+       struct hdcs *hdcs;
+       u16 sensor;
+       int ret;
+
+       ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
+       if (ret < 0 || sensor != 0x10)
+               return -ENODEV;
+
+       info("HDCS-1020 sensor detected");
+
+       sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1020.modes;
+       sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1020.nmodes;
+       sd->desc.ctrls = stv06xx_sensor_hdcs1020.ctrls;
+       sd->desc.nctrls = stv06xx_sensor_hdcs1020.nctrls;
+
+       hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
+       if (!hdcs)
+               return -ENOMEM;
+
+       /*
+        * From Andrey's test image: looks like HDCS-1020 upper-left
+        * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
+        * visible pixel at 375,299 (x maybe even larger?)
+        */
+       hdcs->array.left = 24;
+       hdcs->array.top  = 4;
+       hdcs->array.width = HDCS_1020_DEF_WIDTH;
+       hdcs->array.height = 304;
+       hdcs->array.border = 4;
+
+       hdcs->psmp = 6;
+
+       hdcs->exp.cto = 3;
+       hdcs->exp.cpo = 3;
+       hdcs->exp.rs = 155;
+       hdcs->exp.er = 96;
+
+       sd->sensor_priv = hdcs;
+
+       return 0;
+}
+
+static int hdcs_start(struct sd *sd)
+{
+       PDEBUG(D_STREAM, "Starting stream");
+
+       return hdcs_set_state(sd, HDCS_STATE_RUN);
+}
+
+static int hdcs_stop(struct sd *sd)
+{
+       PDEBUG(D_STREAM, "Halting stream");
+
+       return hdcs_set_state(sd, HDCS_STATE_SLEEP);
+}
+
+static void hdcs_disconnect(struct sd *sd)
+{
+       PDEBUG(D_PROBE, "Disconnecting the sensor");
+       kfree(sd->sensor_priv);
+}
+
+static int hdcs_init(struct sd *sd)
+{
+       struct hdcs *hdcs = sd->sensor_priv;
+       int i, err = 0;
+
+       /* Set the STV0602AA in STV0600 emulation mode */
+       if (IS_870(sd))
+               stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
+
+       /* Execute the bridge init */
+       for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) {
+               err = stv06xx_write_bridge(sd, stv_bridge_init[i][0],
+                                          stv_bridge_init[i][1]);
+       }
+       if (err < 0)
+               return err;
+
+       /* sensor soft reset */
+       hdcs_reset(sd);
+
+       /* Execute the sensor init */
+       for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) {
+               err = stv06xx_write_sensor(sd, stv_sensor_init[i][0],
+                                            stv_sensor_init[i][1]);
+       }
+       if (err < 0)
+               return err;
+
+       /* Enable continous frame capture, bit 2: stop when frame complete */
+       err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3));
+       if (err < 0)
+               return err;
+
+       /* Set PGA sample duration
+       (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */
+       if (IS_1020(sd))
+               err = stv06xx_write_sensor(sd, HDCS_TCTRL,
+                               (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
+       else
+               err = stv06xx_write_sensor(sd, HDCS_TCTRL,
+                               (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp);
+       if (err < 0)
+               return err;
+
+       err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN,
+                            HDCS_DEFAULT_GAIN);
+       if (err < 0)
+               return err;
+
+       err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
+       if (err < 0)
+               return err;
+
+       err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
+       return err;
+}
+
+static int hdcs_dump(struct sd *sd)
+{
+       u16 reg, val;
+
+       info("Dumping sensor registers:");
+
+       for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) {
+               stv06xx_read_sensor(sd, reg, &val);
+               info("reg 0x%02x = 0x%02x", reg, val);
+       }
+       return 0;
+}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
new file mode 100644 (file)
index 0000000..9c7279a
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ * Copyright (c) 2008 Chia-I Wu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#ifndef STV06XX_HDCS_H_
+#define STV06XX_HDCS_H_
+
+#include "stv06xx_sensor.h"
+
+#define HDCS_REG_CONFIG(sd)    (IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG)
+#define HDCS_REG_CONTROL(sd)   (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL)
+
+#define HDCS_1X00_DEF_WIDTH    360
+#define HDCS_1X00_DEF_HEIGHT   296
+
+#define HDCS_1020_DEF_WIDTH    352
+#define HDCS_1020_DEF_HEIGHT   292
+
+#define HDCS_1020_BOTTOM_Y_SKIP        4
+
+#define HDCS_CLK_FREQ_MHZ      25
+
+#define HDCS_ADC_START_SIG_DUR 3
+
+/* LSB bit of I2C or register address signifies write (0) or read (1) */
+/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */
+/* Identifications Register */
+#define HDCS_IDENT             (0x00 << 1)
+/* Status Register */
+#define HDCS_STATUS            (0x01 << 1)
+/* Interrupt Mask Register */
+#define HDCS_IMASK             (0x02 << 1)
+/* Pad Control Register */
+#define HDCS_PCTRL             (0x03 << 1)
+/* Pad Drive Control Register */
+#define HDCS_PDRV              (0x04 << 1)
+/* Interface Control Register */
+#define HDCS_ICTRL             (0x05 << 1)
+/* Interface Timing Register */
+#define HDCS_ITMG              (0x06 << 1)
+/* Baud Fraction Register */
+#define HDCS_BFRAC             (0x07 << 1)
+/* Baud Rate Register */
+#define HDCS_BRATE             (0x08 << 1)
+/* ADC Control Register */
+#define HDCS_ADCCTRL           (0x09 << 1)
+/* First Window Row Register */
+#define HDCS_FWROW             (0x0a << 1)
+/* First Window Column Register */
+#define HDCS_FWCOL             (0x0b << 1)
+/* Last Window Row Register */
+#define HDCS_LWROW             (0x0c << 1)
+/* Last Window Column Register */
+#define HDCS_LWCOL             (0x0d << 1)
+/* Timing Control Register */
+#define HDCS_TCTRL             (0x0e << 1)
+/* PGA Gain Register: Even Row, Even Column */
+#define HDCS_ERECPGA           (0x0f << 1)
+/* PGA Gain Register: Even Row, Odd Column */
+#define HDCS_EROCPGA           (0x10 << 1)
+/* PGA Gain Register: Odd Row, Even Column */
+#define HDCS_ORECPGA           (0x11 << 1)
+/* PGA Gain Register: Odd Row, Odd Column */
+#define HDCS_OROCPGA           (0x12 << 1)
+/* Row Exposure Low Register */
+#define HDCS_ROWEXPL           (0x13 << 1)
+/* Row Exposure High Register */
+#define HDCS_ROWEXPH           (0x14 << 1)
+
+/* I2C Registers only for HDCS-1000/1100 */
+/* Sub-Row Exposure Low Register */
+#define HDCS00_SROWEXPL                (0x15 << 1)
+/* Sub-Row Exposure High Register */
+#define HDCS00_SROWEXPH                (0x16 << 1)
+/* Configuration Register */
+#define HDCS00_CONFIG          (0x17 << 1)
+/* Control Register */
+#define HDCS00_CONTROL         (0x18 << 1)
+
+/* I2C Registers only for HDCS-1020 */
+/* Sub-Row Exposure Register */
+#define HDCS20_SROWEXP         (0x15 << 1)
+/* Error Control Register */
+#define HDCS20_ERROR           (0x16 << 1)
+/* Interface Timing 2 Register */
+#define HDCS20_ITMG2           (0x17 << 1)
+/* Interface Control 2 Register        */
+#define HDCS20_ICTRL2          (0x18 << 1)
+/* Horizontal Blank Register */
+#define HDCS20_HBLANK          (0x19 << 1)
+/* Vertical Blank Register */
+#define HDCS20_VBLANK          (0x1a << 1)
+/* Configuration Register */
+#define HDCS20_CONFIG          (0x1b << 1)
+/* Control Register */
+#define HDCS20_CONTROL         (0x1c << 1)
+
+#define HDCS_RUN_ENABLE                (1 << 2)
+#define HDCS_SLEEP_MODE                (1 << 1)
+
+#define HDCS_DEFAULT_EXPOSURE  5000
+#define HDCS_DEFAULT_GAIN      128
+
+static int hdcs_probe_1x00(struct sd *sd);
+static int hdcs_probe_1020(struct sd *sd);
+static int hdcs_start(struct sd *sd);
+static int hdcs_init(struct sd *sd);
+static int hdcs_stop(struct sd *sd);
+static int hdcs_dump(struct sd *sd);
+static void hdcs_disconnect(struct sd *sd);
+
+static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+
+const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
+       .name = "HP HDCS-1000/1100",
+       .i2c_flush = 0,
+       .i2c_addr = (0x55 << 1),
+       .i2c_len = 1,
+
+       .init = hdcs_init,
+       .probe = hdcs_probe_1x00,
+       .start = hdcs_start,
+       .stop = hdcs_stop,
+       .disconnect = hdcs_disconnect,
+       .dump = hdcs_dump,
+
+       .nctrls = 2,
+       .ctrls = {
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0x00,
+                       .maximum        = 0xffff,
+                       .step           = 0x1,
+                       .default_value  = HDCS_DEFAULT_EXPOSURE,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = hdcs_set_exposure,
+               .get = hdcs_get_exposure
+       },
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = HDCS_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = hdcs_set_gain,
+               .get = hdcs_get_gain
+       }
+       },
+
+       .nmodes = 1,
+       .modes = {
+       {
+               HDCS_1X00_DEF_WIDTH,
+               HDCS_1X00_DEF_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
+               .bytesperline = HDCS_1X00_DEF_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
+       .name = "HDCS-1020",
+       .i2c_flush = 0,
+       .i2c_addr = (0x55 << 1),
+       .i2c_len = 1,
+
+       .nctrls = 0,
+       .ctrls = {},
+
+       .init = hdcs_init,
+       .probe = hdcs_probe_1020,
+       .start = hdcs_start,
+       .stop = hdcs_stop,
+       .dump = hdcs_dump,
+
+       .nmodes = 1,
+       .modes = {
+       {
+               HDCS_1020_DEF_WIDTH,
+               HDCS_1020_DEF_HEIGHT,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
+               .bytesperline = HDCS_1020_DEF_WIDTH,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 1
+       }
+       }
+};
+
+static const u16 stv_bridge_init[][2] = {
+       {STV_ISO_ENABLE, 0},
+       {STV_REG23, 0},
+       {STV_REG00, 0x1d},
+       {STV_REG01, 0xb5},
+       {STV_REG02, 0xa8},
+       {STV_REG03, 0x95},
+       {STV_REG04, 0x07},
+
+       {STV_SCAN_RATE, 0x20},
+       {STV_ISO_SIZE_L, 847},
+       {STV_Y_CTRL, 0x01},
+       {STV_X_CTRL, 0x0a}
+};
+
+static const u8 stv_sensor_init[][2] = {
+       /* Clear status (writing 1 will clear the corresponding status bit) */
+       {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
+       /* Disable all interrupts */
+       {HDCS_IMASK, 0x00},
+       {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)},
+       {HDCS_PDRV,  0x00},
+       {HDCS_ICTRL, BIT(5)},
+       {HDCS_ITMG,  BIT(4) | BIT(1)},
+       /* ADC output resolution to 10 bits */
+       {HDCS_ADCCTRL, 10}
+};
+
+#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
new file mode 100644 (file)
index 0000000..d0a0f85
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+/*
+ * The spec file for the PB-0100 suggests the following for best quality
+ * images after the sensor has been reset :
+ *
+ * PB_ADCGAINL      = R60 = 0x03 (3 dec)      : sets low reference of ADC
+                                               to produce good black level
+ * PB_PREADCTRL     = R32 = 0x1400 (5120 dec) : Enables global gain changes
+                                               through R53
+ * PB_ADCMINGAIN    = R52 = 0x10 (16 dec)     : Sets the minimum gain for
+                                               auto-exposure
+ * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec)     : Sets the global gain
+ * PB_EXPGAIN       = R14 = 0x11 (17 dec)     : Sets the auto-exposure value
+ * PB_UPDATEINT     = R23 = 0x02 (2 dec)      : Sets the speed on
+                                               auto-exposure routine
+ * PB_CFILLIN       = R5  = 0x0E (14 dec)     : Sets the frame rate
+ */
+
+#include "stv06xx_pb0100.h"
+
+static int pb0100_probe(struct sd *sd)
+{
+       u16 sensor;
+       int i, err;
+       s32 *sensor_settings;
+
+       err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
+
+       if (err < 0)
+               return -ENODEV;
+
+       if ((sensor >> 8) == 0x64) {
+               sensor_settings = kmalloc(
+                               stv06xx_sensor_pb0100.nctrls * sizeof(s32),
+                               GFP_KERNEL);
+               if (!sensor_settings)
+                       return -ENOMEM;
+
+               info("Photobit pb0100 sensor detected");
+
+               sd->gspca_dev.cam.cam_mode = stv06xx_sensor_pb0100.modes;
+               sd->gspca_dev.cam.nmodes = stv06xx_sensor_pb0100.nmodes;
+               sd->desc.ctrls = stv06xx_sensor_pb0100.ctrls;
+               sd->desc.nctrls = stv06xx_sensor_pb0100.nctrls;
+               for (i = 0; i < stv06xx_sensor_pb0100.nctrls; i++)
+                       sensor_settings[i] = stv06xx_sensor_pb0100.
+                                            ctrls[i].qctrl.default_value;
+               sd->sensor_priv = sensor_settings;
+
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static int pb0100_start(struct sd *sd)
+{
+       int err;
+       struct cam *cam = &sd->gspca_dev.cam;
+       s32 *sensor_settings = sd->sensor_priv;
+       u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+
+       /* Setup sensor window */
+       if (mode & PB0100_CROP_TO_VGA) {
+               stv06xx_write_sensor(sd, PB_RSTART, 30);
+               stv06xx_write_sensor(sd, PB_CSTART, 20);
+               stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
+               stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
+       } else {
+               stv06xx_write_sensor(sd, PB_RSTART, 8);
+               stv06xx_write_sensor(sd, PB_CSTART, 4);
+               stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
+               stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
+       }
+
+       if (mode & PB0100_SUBSAMPLE) {
+               stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */
+               stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
+
+               stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
+       } else {
+               stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
+               stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
+               /* larger -> slower */
+               stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
+       }
+
+       /* set_gain also sets red and blue balance */
+       pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
+       pb0100_set_autogain_target(&sd->gspca_dev,
+                                  sensor_settings[AUTOGAIN_TARGET_IDX]);
+       pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
+
+       err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
+       PDEBUG(D_STREAM, "Started stream, status: %d", err);
+
+       return (err < 0) ? err : 0;
+}
+
+static int pb0100_stop(struct sd *sd)
+{
+       int err;
+
+       err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
+
+       if (err < 0)
+               goto out;
+
+       /* Set bit 1 to zero */
+       err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
+
+       PDEBUG(D_STREAM, "Halting stream");
+out:
+       return (err < 0) ? err : 0;
+}
+
+/* FIXME: Sort the init commands out and put them into tables,
+         this is only for getting the camera to work */
+/* FIXME: No error handling for now,
+         add this once the init has been converted to proper tables */
+static int pb0100_init(struct sd *sd)
+{
+       stv06xx_write_bridge(sd, STV_REG00, 1);
+       stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
+
+       /* Reset sensor */
+       stv06xx_write_sensor(sd, PB_RESET, 1);
+       stv06xx_write_sensor(sd, PB_RESET, 0);
+
+       /* Disable chip */
+       stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
+
+       /* Gain stuff...*/
+       stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
+       stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
+
+       /* Set up auto-exposure */
+       /* ADC VREF_HI new setting for a transition
+         from the Expose1 to the Expose2 setting */
+       stv06xx_write_sensor(sd, PB_R28, 12);
+       /* gain max for autoexposure */
+       stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
+       /* gain min for autoexposure  */
+       stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
+       /* Maximum frame integration time (programmed into R8)
+          allowed for auto-exposure routine */
+       stv06xx_write_sensor(sd, PB_R54, 3);
+       /* Minimum frame integration time (programmed into R8)
+          allowed for auto-exposure routine */
+       stv06xx_write_sensor(sd, PB_R55, 0);
+       stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
+       /* R15  Expose0 (maximum that auto-exposure may use) */
+       stv06xx_write_sensor(sd, PB_R15, 800);
+       /* R17  Expose2 (minimum that auto-exposure may use) */
+       stv06xx_write_sensor(sd, PB_R17, 10);
+
+       stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
+
+       /* 0x14 */
+       stv06xx_write_sensor(sd, PB_VOFFSET, 0);
+       /* 0x0D */
+       stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
+       /* Set black level (important!) */
+       stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
+
+       /* ??? */
+       stv06xx_write_bridge(sd, STV_REG00, 0x11);
+       stv06xx_write_bridge(sd, STV_REG03, 0x45);
+       stv06xx_write_bridge(sd, STV_REG04, 0x07);
+
+       /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
+       stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
+
+       /* Scan/timing for the sensor */
+       stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
+       stv06xx_write_sensor(sd, PB_CFILLIN, 14);
+       stv06xx_write_sensor(sd, PB_VBL, 0);
+       stv06xx_write_sensor(sd, PB_FINTTIME, 0);
+       stv06xx_write_sensor(sd, PB_RINTTIME, 123);
+
+       stv06xx_write_bridge(sd, STV_REG01, 0xc2);
+       stv06xx_write_bridge(sd, STV_REG02, 0xb0);
+       return 0;
+}
+
+static int pb0100_dump(struct sd *sd)
+{
+       return 0;
+}
+
+static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GAIN_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       if (sensor_settings[AUTOGAIN_IDX])
+               return -EBUSY;
+
+       sensor_settings[GAIN_IDX] = val;
+       err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
+       if (!err)
+               err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
+       PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
+
+       if (!err)
+               err = pb0100_set_red_balance(gspca_dev,
+                                            sensor_settings[RED_BALANCE_IDX]);
+       if (!err)
+               err = pb0100_set_blue_balance(gspca_dev,
+                                           sensor_settings[BLUE_BALANCE_IDX]);
+
+       return err;
+}
+
+static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[RED_BALANCE_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       if (sensor_settings[AUTOGAIN_IDX])
+               return -EBUSY;
+
+       sensor_settings[RED_BALANCE_IDX] = val;
+       val += sensor_settings[GAIN_IDX];
+       if (val < 0)
+               val = 0;
+       else if (val > 255)
+               val = 255;
+
+       err = stv06xx_write_sensor(sd, PB_RGAIN, val);
+       PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
+
+       return err;
+}
+
+static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[BLUE_BALANCE_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       if (sensor_settings[AUTOGAIN_IDX])
+               return -EBUSY;
+
+       sensor_settings[BLUE_BALANCE_IDX] = val;
+       val += sensor_settings[GAIN_IDX];
+       if (val < 0)
+               val = 0;
+       else if (val > 255)
+               val = 255;
+
+       err = stv06xx_write_sensor(sd, PB_BGAIN, val);
+       PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
+
+       return err;
+}
+
+static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[EXPOSURE_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       if (sensor_settings[AUTOGAIN_IDX])
+               return -EBUSY;
+
+       sensor_settings[EXPOSURE_IDX] = val;
+       err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
+       PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
+
+       return err;
+}
+
+static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTOGAIN_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[AUTOGAIN_IDX] = val;
+       if (sensor_settings[AUTOGAIN_IDX]) {
+               if (sensor_settings[NATURAL_IDX])
+                       val = BIT(6)|BIT(4)|BIT(0);
+               else
+                       val = BIT(4)|BIT(0);
+       } else
+               val = 0;
+
+       err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
+       PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
+              sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
+              err);
+
+       return err;
+}
+
+static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTOGAIN_TARGET_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err, totalpixels, brightpixels, darkpixels;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[AUTOGAIN_TARGET_IDX] = val;
+
+       /* Number of pixels counted by the sensor when subsampling the pixels.
+        * Slightly larger than the real value to avoid oscillation */
+       totalpixels = gspca_dev->width * gspca_dev->height;
+       totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
+
+       brightpixels = (totalpixels * val) >> 8;
+       darkpixels   = totalpixels - brightpixels;
+       err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
+       if (!err)
+               err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
+
+       PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
+
+       return err;
+}
+
+static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[NATURAL_IDX];
+
+       return 0;
+}
+
+static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[NATURAL_IDX] = val;
+
+       return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
+}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
new file mode 100644 (file)
index 0000000..5ea21a1
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#ifndef STV06XX_PB0100_H_
+#define STV06XX_PB0100_H_
+
+#include "stv06xx_sensor.h"
+
+/* mode priv field flags */
+#define PB0100_CROP_TO_VGA     0x01
+#define PB0100_SUBSAMPLE       0x02
+
+/* I2C Registers */
+#define PB_IDENT               0x00    /* Chip Version */
+#define PB_RSTART              0x01    /* Row Window Start */
+#define PB_CSTART              0x02    /* Column Window Start */
+#define PB_RWSIZE              0x03    /* Row Window Size */
+#define PB_CWSIZE              0x04    /* Column  Window Size */
+#define PB_CFILLIN             0x05    /* Column Fill-In */
+#define PB_VBL                 0x06    /* Vertical Blank Count */
+#define PB_CONTROL             0x07    /* Control Mode */
+#define PB_FINTTIME            0x08    /* Integration Time/Frame Unit Count */
+#define PB_RINTTIME            0x09    /* Integration Time/Row Unit Count */
+#define PB_ROWSPEED            0x0a    /* Row Speed Control */
+#define PB_ABORTFRAME          0x0b    /* Abort Frame */
+#define PB_R12                 0x0c    /* Reserved */
+#define PB_RESET               0x0d    /* Reset */
+#define PB_EXPGAIN             0x0e    /* Exposure Gain Command */
+#define PB_R15                 0x0f    /* Expose0 */
+#define PB_R16                 0x10    /* Expose1 */
+#define PB_R17                 0x11    /* Expose2 */
+#define PB_R18                 0x12    /* Low0_DAC */
+#define PB_R19                 0x13    /* Low1_DAC */
+#define PB_R20                 0x14    /* Low2_DAC */
+#define PB_R21                 0x15    /* Threshold11 */
+#define PB_R22                 0x16    /* Threshold0x */
+#define PB_UPDATEINT           0x17    /* Update Interval */
+#define PB_R24                 0x18    /* High_DAC */
+#define PB_R25                 0x19    /* Trans0H */
+#define PB_R26                 0x1a    /* Trans1L */
+#define PB_R27                 0x1b    /* Trans1H */
+#define PB_R28                 0x1c    /* Trans2L */
+#define PB_R29                 0x1d    /* Reserved */
+#define PB_R30                 0x1e    /* Reserved */
+#define PB_R31                 0x1f    /* Wait to Read */
+#define PB_PREADCTRL           0x20    /* Pixel Read Control Mode */
+#define PB_R33                 0x21    /* IREF_VLN */
+#define PB_R34                 0x22    /* IREF_VLP */
+#define PB_R35                 0x23    /* IREF_VLN_INTEG */
+#define PB_R36                 0x24    /* IREF_MASTER */
+#define PB_R37                 0x25    /* IDACP */
+#define PB_R38                 0x26    /* IDACN */
+#define PB_R39                 0x27    /* DAC_Control_Reg */
+#define PB_R40                 0x28    /* VCL */
+#define PB_R41                 0x29    /* IREF_VLN_ADCIN */
+#define PB_R42                 0x2a    /* Reserved */
+#define PB_G1GAIN              0x2b    /* Green 1 Gain */
+#define PB_BGAIN               0x2c    /* Blue Gain */
+#define PB_RGAIN               0x2d    /* Red Gain */
+#define PB_G2GAIN              0x2e    /* Green 2 Gain */
+#define PB_R47                 0x2f    /* Dark Row Address */
+#define PB_R48                 0x30    /* Dark Row Options */
+#define PB_R49                 0x31    /* Reserved */
+#define PB_R50                 0x32    /* Image Test Data */
+#define PB_ADCMAXGAIN          0x33    /* Maximum Gain */
+#define PB_ADCMINGAIN          0x34    /* Minimum Gain */
+#define PB_ADCGLOBALGAIN       0x35    /* Global Gain */
+#define PB_R54                 0x36    /* Maximum Frame */
+#define PB_R55                 0x37    /* Minimum Frame */
+#define PB_R56                 0x38    /* Reserved */
+#define PB_VOFFSET             0x39    /* VOFFSET */
+#define PB_R58                 0x3a    /* Snap-Shot Sequence Trigger */
+#define PB_ADCGAINH            0x3b    /* VREF_HI */
+#define PB_ADCGAINL            0x3c    /* VREF_LO */
+#define PB_R61                 0x3d    /* Reserved */
+#define PB_R62                 0x3e    /* Reserved */
+#define PB_R63                 0x3f    /* Reserved */
+#define PB_R64                 0x40    /* Red/Blue Gain */
+#define PB_R65                 0x41    /* Green 2/Green 1 Gain */
+#define PB_R66                 0x42    /* VREF_HI/LO */
+#define PB_R67                 0x43    /* Integration Time/Row Unit Count */
+#define PB_R240                        0xf0    /* ADC Test */
+#define PB_R241                        0xf1    /* Chip Enable */
+#define PB_R242                        0xf2    /* Reserved */
+
+static int pb0100_probe(struct sd *sd);
+static int pb0100_start(struct sd *sd);
+static int pb0100_init(struct sd *sd);
+static int pb0100_stop(struct sd *sd);
+static int pb0100_dump(struct sd *sd);
+
+/* V4L2 controls supported by the driver */
+static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val);
+static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val);
+static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val);
+
+const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
+       .name = "PB-0100",
+       .i2c_flush = 1,
+       .i2c_addr = 0xba,
+       .i2c_len = 2,
+
+       .nctrls = 7,
+       .ctrls = {
+#define GAIN_IDX 0
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Gain",
+                       .minimum        = 0,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 128
+               },
+               .set = pb0100_set_gain,
+               .get = pb0100_get_gain
+       },
+#define RED_BALANCE_IDX 1
+       {
+               {
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Red Balance",
+                       .minimum        = -255,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = pb0100_set_red_balance,
+               .get = pb0100_get_red_balance
+       },
+#define BLUE_BALANCE_IDX 2
+       {
+               {
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Blue Balance",
+                       .minimum        = -255,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = pb0100_set_blue_balance,
+               .get = pb0100_get_blue_balance
+       },
+#define EXPOSURE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Exposure",
+                       .minimum        = 0,
+                       .maximum        = 511,
+                       .step           = 1,
+                       .default_value  = 12
+               },
+               .set = pb0100_set_exposure,
+               .get = pb0100_get_exposure
+       },
+#define AUTOGAIN_IDX 4
+       {
+               {
+                       .id             = V4L2_CID_AUTOGAIN,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "Automatic Gain and Exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
+               },
+               .set = pb0100_set_autogain,
+               .get = pb0100_get_autogain
+       },
+#define AUTOGAIN_TARGET_IDX 5
+       {
+               {
+                       .id             = V4L2_CTRL_CLASS_USER + 0x1000,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Automatic Gain Target",
+                       .minimum        = 0,
+                       .maximum        = 255,
+                       .step           = 1,
+                       .default_value  = 128
+               },
+               .set = pb0100_set_autogain_target,
+               .get = pb0100_get_autogain_target
+       },
+#define NATURAL_IDX 6
+       {
+               {
+                       .id             = V4L2_CTRL_CLASS_USER + 0x1001,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "Natural Light Source",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
+               },
+               .set = pb0100_set_natural,
+               .get = pb0100_get_natural
+       },
+       },
+
+       .init = pb0100_init,
+       .probe = pb0100_probe,
+       .start = pb0100_start,
+       .stop = pb0100_stop,
+       .dump = pb0100_dump,
+
+       .nmodes = 2,
+       .modes = {
+/* low res / subsample modes disabled as they are only half res horizontal,
+   halving the vertical resolution does not seem to work */
+       {
+               320,
+               240,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 320 * 240,
+               .bytesperline = 320,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = PB0100_CROP_TO_VGA
+       },
+       {
+               352,
+               288,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage = 352 * 288,
+               .bytesperline = 352,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       },
+       }
+};
+
+#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
new file mode 100644 (file)
index 0000000..c726dac
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#ifndef STV06XX_SENSOR_H_
+#define STV06XX_SENSOR_H_
+
+#include "stv06xx.h"
+
+#define IS_850(sd)     ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850)
+#define IS_870(sd)     ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870)
+#define IS_1020(sd)    ((sd)->sensor == &stv06xx_sensor_hdcs1020)
+
+extern const struct stv06xx_sensor stv06xx_sensor_vv6410;
+extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
+extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
+extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
+
+#define STV06XX_MAX_CTRLS              (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+
+struct stv06xx_sensor {
+       /* Defines the name of a sensor */
+       char name[32];
+
+       /* Sensor i2c address */
+       u8 i2c_addr;
+
+       /* Flush value*/
+       u8 i2c_flush;
+
+       /* length of an i2c word */
+       u8 i2c_len;
+
+       /* Probes if the sensor is connected */
+       int (*probe)(struct sd *sd);
+
+       /* Performs a initialization sequence */
+       int (*init)(struct sd *sd);
+
+       /* Executed at device disconnect */
+       void (*disconnect)(struct sd *sd);
+
+       /* Reads a sensor register */
+       int (*read_sensor)(struct sd *sd, const u8 address,
+             u8 *i2c_data, const u8 len);
+
+       /* Writes to a sensor register */
+       int (*write_sensor)(struct sd *sd, const u8 address,
+             u8 *i2c_data, const u8 len);
+
+       /* Instructs the sensor to start streaming */
+       int (*start)(struct sd *sd);
+
+       /* Instructs the sensor to stop streaming */
+       int (*stop)(struct sd *sd);
+
+       /* Instructs the sensor to dump all its contents */
+       int (*dump)(struct sd *sd);
+
+       int nctrls;
+       struct ctrl ctrls[STV06XX_MAX_CTRLS];
+
+       char nmodes;
+       struct v4l2_pix_format modes[];
+};
+
+#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
new file mode 100644 (file)
index 0000000..1ca91f2
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#include "stv06xx_vv6410.h"
+
+static int vv6410_probe(struct sd *sd)
+{
+       u16 data;
+       int err;
+
+       err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
+
+       if (err < 0)
+               return -ENODEV;
+
+       if (data == 0x19) {
+               info("vv6410 sensor detected");
+
+               sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes;
+               sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes;
+               sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls;
+               sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls;
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static int vv6410_init(struct sd *sd)
+{
+       int err = 0, i;
+
+       for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
+               /* if NULL then len contains single value */
+               if (stv_bridge_init[i].data == NULL) {
+                       err = stv06xx_write_bridge(sd,
+                               stv_bridge_init[i].start,
+                               stv_bridge_init[i].len);
+               } else {
+                       int j;
+                       for (j = 0; j < stv_bridge_init[i].len; j++)
+                               err = stv06xx_write_bridge(sd,
+                                       stv_bridge_init[i].start + j,
+                                       stv_bridge_init[i].data[j]);
+               }
+       }
+
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
+                                        ARRAY_SIZE(vv6410_sensor_init));
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_start(struct sd *sd)
+{
+       int err;
+       struct cam *cam = &sd->gspca_dev.cam;
+       u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+
+       if (priv & VV6410_CROP_TO_QVGA) {
+               PDEBUG(D_CONF, "Cropping to QVGA");
+               stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1);
+               stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1);
+       } else {
+               stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1);
+               stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1);
+       }
+
+       if (priv & VV6410_SUBSAMPLE) {
+               PDEBUG(D_CONF, "Enabling subsampling");
+               stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
+               stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
+
+               stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
+       } else {
+               stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
+               stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
+
+               stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
+       }
+
+       /* Turn on LED */
+       err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_STREAM, "Starting stream");
+
+       return 0;
+}
+
+static int vv6410_stop(struct sd *sd)
+{
+       int err;
+
+       /* Turn off LED */
+       err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
+       if (err < 0)
+               return err;
+
+       err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_STREAM, "Halting stream");
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_dump(struct sd *sd)
+{
+       u8 i;
+       int err = 0;
+
+       info("Dumping all vv6410 sensor registers");
+       for (i = 0; i < 0xff && !err; i++) {
+               u16 data;
+               err = stv06xx_read_sensor(sd, i, &data);
+               info("Register 0x%x contained 0x%x", i, data);
+       }
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u16 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+
+       *val = (i2c_data & VV6410_HFLIP) ? 1 : 0;
+
+       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u16 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+       err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+       if (err < 0)
+               return err;
+
+       if (val)
+               i2c_data |= VV6410_HFLIP;
+       else
+               i2c_data &= ~VV6410_HFLIP;
+
+       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+       err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u16 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+
+       *val = (i2c_data & VV6410_VFLIP) ? 1 : 0;
+
+       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u16 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+       err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
+       if (err < 0)
+               return err;
+
+       if (val)
+               i2c_data |= VV6410_VFLIP;
+       else
+               i2c_data &= ~VV6410_VFLIP;
+
+       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+       err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       int err;
+       u16 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data);
+
+       *val = i2c_data & 0xf;
+
+       PDEBUG(D_V4L2, "Read analog gain %d", *val);
+
+       return (err < 0) ? err : 0;
+}
+
+static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       PDEBUG(D_V4L2, "Set analog gain to %d", val);
+       err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
+
+       return (err < 0) ? err : 0;
+}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
new file mode 100644 (file)
index 0000000..3ff8c4e
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
+ *                   Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
+ * Copyright (c) 2002, 2003 Tuukka Toivonen
+ * Copyright (c) 2008 Erik Andrén
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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
+ *
+ * P/N 861037:      Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
+ * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
+ * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
+ * P/N 861075-0040: Sensor HDCS1000        ASIC
+ * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
+ * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
+ */
+
+#ifndef STV06XX_VV6410_H_
+#define STV06XX_VV6410_H_
+
+#include "stv06xx_sensor.h"
+
+#define VV6410_COLS                    416
+#define VV6410_ROWS                    320
+
+/* Status registers */
+/* Chip identification number including revision indicator */
+#define VV6410_DEVICEH                 0x00
+#define VV6410_DEVICEL                 0x01
+
+/* User can determine whether timed I2C data
+   has been consumed by interrogating flag states */
+#define VV6410_STATUS0                 0x02
+
+/* Current line counter value */
+#define VV6410_LINECOUNTH              0x03
+#define VV6410_LINECOUNTL              0x04
+
+/* End x coordinate of image size */
+#define VV6410_XENDH                   0x05
+#define VV6410_XENDL                   0x06
+
+/* End y coordinate of image size */
+#define VV6410_YENDH                   0x07
+#define VV6410_YENDL                   0x08
+
+/* This is the average pixel value returned from the
+   dark line offset cancellation algorithm */
+#define VV6410_DARKAVGH                        0x09
+#define VV6410_DARKAVGL                        0x0a
+
+/* This is the average pixel value returned from the
+   black line offset cancellation algorithm  */
+#define VV6410_BLACKAVGH               0x0b
+#define VV6410_BLACKAVGL               0x0c
+
+/* Flags to indicate whether the x or y image coordinates have been clipped */
+#define VV6410_STATUS1                 0x0d
+
+/* Setup registers */
+
+/* Low-power/sleep modes & video timing */
+#define VV6410_SETUP0                  0x10
+
+/* Various parameters */
+#define VV6410_SETUP1                  0x11
+
+/* Contains pixel counter reset value used by external sync */
+#define VV6410_SYNCVALUE               0x12
+
+/* Frame grabbing modes (FST, LST and QCK) */
+#define VV6410_FGMODES                 0x14
+
+/* FST and QCK mapping modes. */
+#define VV6410_PINMAPPING              0x15
+
+/* Data resolution */
+#define VV6410_DATAFORMAT              0x16
+
+/* Output coding formats */
+#define VV6410_OPFORMAT                        0x17
+
+/* Various mode select bits */
+#define VV6410_MODESELECT              0x18
+
+/* Exposure registers */
+/* Fine exposure. */
+#define VV6410_FINEH                   0x20
+#define VV6410_FINEL                   0x21
+
+/* Coarse exposure */
+#define VV6410_COARSEH                 0x22
+#define VV6410_COARSEL                 0x23
+
+/* Analog gain setting */
+#define VV6410_ANALOGGAIN              0x24
+
+/* Clock division */
+#define VV6410_CLKDIV                  0x25
+
+/* Dark line offset cancellation value */
+#define VV6410_DARKOFFSETH             0x2c
+#define VV6410_DARKOFFSETL             0x2d
+
+/* Dark line offset cancellation enable */
+#define VV6410_DARKOFFSETSETUP         0x2e
+
+/* Video timing registers */
+/* Line Length (Pixel Clocks) */
+#define VV6410_LINELENGTHH             0x52
+#define VV6410_LINELENGTHL             0x53
+
+/* X-co-ordinate of top left corner of region of interest (x-offset) */
+#define VV6410_XOFFSETH                        0x57
+#define VV6410_XOFFSETL                        0x58
+
+/* Y-coordinate of top left corner of region of interest (y-offset) */
+#define VV6410_YOFFSETH                        0x59
+#define VV6410_YOFFSETL                        0x5a
+
+/* Field length (Lines) */
+#define VV6410_FIELDLENGTHH            0x61
+#define VV6410_FIELDLENGTHL            0x62
+
+/* System registers */
+/* Black offset cancellation default value */
+#define VV6410_BLACKOFFSETH            0x70
+#define VV6410_BLACKOFFSETL            0x71
+
+/* Black offset cancellation setup */
+#define VV6410_BLACKOFFSETSETUP                0x72
+
+/* Analog Control Register 0 */
+#define VV6410_CR0                     0x75
+
+/* Analog Control Register 1 */
+#define VV6410_CR1                     0x76
+
+/* ADC Setup Register */
+#define VV6410_AS0                     0x77
+
+/* Analog Test Register */
+#define VV6410_AT0                     0x78
+
+/* Audio Amplifier Setup Register */
+#define VV6410_AT1                     0x79
+
+#define VV6410_HFLIP                   (1 << 3)
+#define VV6410_VFLIP                   (1 << 4)
+
+#define VV6410_LOW_POWER_MODE          (1 << 0)
+#define VV6410_SOFT_RESET              (1 << 2)
+#define VV6410_PAL_25_FPS              (0 << 3)
+
+#define VV6410_CLK_DIV_2               (1 << 1)
+
+#define VV6410_FINE_EXPOSURE           320
+#define VV6410_COARSE_EXPOSURE         192
+#define VV6410_DEFAULT_GAIN            5
+
+#define VV6410_SUBSAMPLE               0x01
+#define VV6410_CROP_TO_QVGA            0x02
+
+static int vv6410_probe(struct sd *sd);
+static int vv6410_start(struct sd *sd);
+static int vv6410_init(struct sd *sd);
+static int vv6410_stop(struct sd *sd);
+static int vv6410_dump(struct sd *sd);
+
+/* V4L2 controls supported by the driver */
+static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
+       .name = "ST VV6410",
+       .i2c_flush = 5,
+       .i2c_addr = 0x20,
+       .i2c_len = 1,
+       .init = vv6410_init,
+       .probe = vv6410_probe,
+       .start = vv6410_start,
+       .stop = vv6410_stop,
+       .dump = vv6410_dump,
+
+       .nctrls = 3,
+       .ctrls = {
+       {
+               {
+                       .id             = V4L2_CID_HFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "horizontal flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = vv6410_set_hflip,
+               .get = vv6410_get_hflip
+       }, {
+               {
+                       .id             = V4L2_CID_VFLIP,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "vertical flip",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = vv6410_set_vflip,
+               .get = vv6410_get_vflip
+       }, {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "analog gain",
+                       .minimum        = 0,
+                       .maximum        = 15,
+                       .step           = 1,
+                       .default_value  = 0
+               },
+               .set = vv6410_set_analog_gain,
+               .get = vv6410_get_analog_gain
+       }
+       },
+
+       .nmodes = 1,
+       .modes = {
+       {
+               356,
+               292,
+               V4L2_PIX_FMT_SGRBG8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       356 * 292,
+               .bytesperline = 356,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }
+       }
+};
+
+/* If NULL, only single value to write, stored in len */
+struct stv_init {
+       const u8 *data;
+       u16 start;
+       u8 len;
+};
+
+static const u8 x1500[] = {    /* 0x1500 - 0x150f */
+       0x0b, 0xa7, 0xb7, 0x00, 0x00
+};
+
+static const u8 x1536[] = {    /* 0x1536 - 0x153b */
+       0x02, 0x00, 0x60, 0x01, 0x20, 0x01
+};
+
+static const u8 x15c1[] = {    /* 0x15c1 - 0x15c2 */
+       0xff, 0x03 /* Output word 0x03ff = 1023 (ISO size) */
+};
+
+static const struct stv_init stv_bridge_init[] = {
+       /* This reg is written twice. Some kind of reset? */
+       {NULL,  0x1620, 0x80},
+       {NULL,  0x1620, 0x00},
+       {NULL,  0x1423, 0x04},
+       {x1500, 0x1500, ARRAY_SIZE(x1500)},
+       {x1536, 0x1536, ARRAY_SIZE(x1536)},
+       {x15c1, 0x15c1, ARRAY_SIZE(x15c1)}
+};
+
+static const u8 vv6410_sensor_init[][2] = {
+       /* Setup registers */
+       {VV6410_SETUP0,         VV6410_SOFT_RESET},
+       {VV6410_SETUP0,         VV6410_LOW_POWER_MODE},
+       /* Use shuffled read-out mode */
+       {VV6410_SETUP1,         BIT(6)},
+       /* All modes to 1 */
+       {VV6410_FGMODES,        BIT(6) | BIT(4) | BIT(2) | BIT(0)},
+       {VV6410_PINMAPPING,     0x00},
+       /* Pre-clock generator divide off */
+       {VV6410_DATAFORMAT,     BIT(7) | BIT(0)},
+
+       /* Exposure registers */
+       {VV6410_FINEH,          VV6410_FINE_EXPOSURE >> 8},
+       {VV6410_FINEL,          VV6410_FINE_EXPOSURE & 0xff},
+       {VV6410_COARSEH,        VV6410_COARSE_EXPOSURE >> 8},
+       {VV6410_COARSEL,        VV6410_COARSE_EXPOSURE & 0xff},
+       {VV6410_ANALOGGAIN,     0xf0 | VV6410_DEFAULT_GAIN},
+       {VV6410_CLKDIV,         VV6410_CLK_DIV_2},
+
+       /* System registers */
+       /* Enable voltage doubler */
+       {VV6410_AS0,            BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
+       {VV6410_AT0,            0x00},
+       /* Power up audio, differential */
+       {VV6410_AT1,            BIT(4)|BIT(0)},
+};
+
+#endif
index bd9288665a80c26c9e98e8bd451643652c19b023..6d904d5e4c74ef9cd02204e4eabd312652213396 100644 (file)
@@ -123,7 +123,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -136,7 +136,7 @@ static struct v4l2_pix_format vga_mode[] = {
                .priv = 1},
 };
 
-static struct v4l2_pix_format custom_mode[] = {
+static const struct v4l2_pix_format custom_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -149,7 +149,7 @@ static struct v4l2_pix_format custom_mode[] = {
                .priv = 1},
 };
 
-static struct v4l2_pix_format vga_mode2[] = {
+static const struct v4l2_pix_format vga_mode2[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
index eac245d7a7561af56241fb806472eb00d877a9ad..6ee111a3cbd1e5889a3e7c44c6bdcd847be24b1b 100644 (file)
@@ -233,7 +233,7 @@ static char *effects_control[] = {
        "Negative",
 };
 
-static struct v4l2_pix_format vga_mode_t16[] = {
+static const struct v4l2_pix_format vga_mode_t16[] = {
        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120 * 4 / 8 + 590,
@@ -499,7 +499,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
        reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
        msleep(5);
        i = 4;
-       while (--i < 0) {
+       while (--i > 0) {
                byte = reg_r(gspca_dev, 0x0060);
                if (!(byte & 0x01))
                        break;
index 968a5911704fd381c2fe8ac67ead6b49d361b72f..94163cceb28ae0bb6ec051294420288ddbc0816a 100644 (file)
@@ -30,15 +30,10 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       int buflen;                     /* current length of tmpbuf */
-       __u8 tmpbuf[352 * 288 + 10 * 288];      /* no protection... */
-       __u8 tmpbuf2[352 * 288];                /* no protection... */
+       __u16 brightness;
+       __u16 contrast;
 
-       unsigned short brightness;
-       unsigned short contrast;
-
-       char packet;
-       char synchro;
+       __u8 packet;
 };
 
 /* V4L2 controls supported by the driver */
@@ -78,7 +73,7 @@ static struct ctrl sd_ctrls[] = {
         },
 };
 
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144,
@@ -392,6 +387,8 @@ static void setbrightness(struct gspca_dev *gspca_dev)
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
        reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
        reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
        tv_8532ReadRegisters(gspca_dev);
@@ -443,6 +440,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
        /************************************************/
        tv_8532_PollReg(gspca_dev);
        reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);    /* 0x31 */
+
+       gspca_dev->empty_packet = 0;            /* check the empty packets */
+       sd->packet = 0;                         /* ignore the first packets */
+
        return 0;
 }
 
@@ -451,111 +452,36 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
 }
 
-static void tv8532_preprocess(struct gspca_dev *gspca_dev)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-/* we should received a whole frame with header and EOL marker
- * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
- * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
- * Alternate pixels bayer RG 4 bytes EOL */
-       int width = gspca_dev->width;
-       int height = gspca_dev->height;
-       unsigned char *dst = sd->tmpbuf2;
-       unsigned char *data = sd->tmpbuf;
-       int i;
-
-       /* precompute where is the good bayer line */
-       if (((data[3] + data[width + 7]) >> 1)
-           + (data[4] >> 2)
-           + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
-           + (data[3] >> 2)
-           + (data[width + 5] >> 1))
-               data += 3;
-       else
-               data += 2;
-       for (i = 0; i < height / 2; i++) {
-               memcpy(dst, data, width);
-               data += width + 3;
-               dst += width;
-               memcpy(dst, data, width);
-               data += width + 7;
-               dst += width;
-       }
-}
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
 {
        struct sd *sd = (struct sd *) gspca_dev;
-
-       if (data[0] != 0x80) {
-               sd->packet++;
-               if (sd->buflen + len > sizeof sd->tmpbuf) {
-                       if (gspca_dev->last_packet_type != DISCARD_PACKET) {
-                               PDEBUG(D_PACK, "buffer overflow");
-                               gspca_dev->last_packet_type = DISCARD_PACKET;
-                       }
-                       return;
-               }
-               memcpy(&sd->tmpbuf[sd->buflen], data, len);
-               sd->buflen += len;
-               return;
-       }
-
-       /* here we detect 0x80 */
-       /* counter is limited so we need few header for a frame :) */
-
-       /* header 0x80 0x80 0x80 0x80 0x80 */
-       /* packet  00   63  127  145  00   */
-       /* sof     0     1   1    0    0   */
-
-       /* update sequence */
-       if (sd->packet == 63 || sd->packet == 127)
-               sd->synchro = 1;
-
-       /* is there a frame start ? */
-       if (sd->packet >= (gspca_dev->height >> 1) - 1) {
-               PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
-                      sd->packet);
-               if (!sd->synchro) {     /* start of frame */
-                       if (gspca_dev->last_packet_type == FIRST_PACKET) {
-                               tv8532_preprocess(gspca_dev);
-                               frame = gspca_frame_add(gspca_dev,
-                                                       LAST_PACKET,
-                                                       frame, sd->tmpbuf2,
-                                                       gspca_dev->width *
-                                                           gspca_dev->width);
-                       }
-                       gspca_frame_add(gspca_dev, FIRST_PACKET,
-                                       frame, data, 0);
-                       memcpy(sd->tmpbuf, data, len);
-                       sd->buflen = len;
-                       sd->packet = 0;
-                       return;
-               }
-               if (gspca_dev->last_packet_type != DISCARD_PACKET) {
-                       PDEBUG(D_PACK,
-                              "Warning wrong TV8532 frame detection %d",
-                              sd->packet);
-                       gspca_dev->last_packet_type = DISCARD_PACKET;
-               }
-               return;
-       }
-
-       if (!sd->synchro) {
-               /* Drop packet frame corrupt */
-               PDEBUG(D_PACK, "DROP SOF %d packet %d",
-                      sd->synchro, sd->packet);
-               sd->packet = 0;
-               gspca_dev->last_packet_type = DISCARD_PACKET;
-               return;
-       }
-       sd->synchro = 1;
-       sd->packet++;
-       memcpy(&sd->tmpbuf[sd->buflen], data, len);
-       sd->buflen += len;
+       int packet_type0, packet_type1;
+
+       packet_type0 = packet_type1 = INTER_PACKET;
+       if (gspca_dev->empty_packet) {
+               gspca_dev->empty_packet = 0;
+               sd->packet = gspca_dev->height / 2;
+               packet_type0 = FIRST_PACKET;
+       } else if (sd->packet == 0)
+               return;                 /* 2 more lines in 352x288 ! */
+       sd->packet--;
+       if (sd->packet == 0)
+               packet_type1 = LAST_PACKET;
+
+       /* each packet contains:
+        * - header 2 bytes
+        * - RG line
+        * - 4 bytes
+        * - GB line
+        * - 4 bytes
+        */
+       gspca_frame_add(gspca_dev, packet_type0,
+                       frame, data + 2, gspca_dev->width);
+       gspca_frame_add(gspca_dev, packet_type1,
+                       frame, data + gspca_dev->width + 6, gspca_dev->width);
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)
index 17af353ddd1c872226be39550073de968b3d925b..0525ea51a6dea95f54311933616e7f15bd825f8a 100644 (file)
@@ -32,44 +32,68 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       unsigned char autogain;
-       unsigned char lightfreq;
+       __u8 hflip;
+       __u8 vflip;
+       __u8 lightfreq;
+       __u8 sharpness;
 
-       char qindex;
        char bridge;
 #define BRIDGE_VC0321 0
 #define BRIDGE_VC0323 1
        char sensor;
 #define SENSOR_HV7131R 0
-#define SENSOR_MI1320 1
-#define SENSOR_MI1310_SOC 2
-#define SENSOR_OV7660 3
-#define SENSOR_OV7670 4
-#define SENSOR_PO3130NC 5
+#define SENSOR_MI0360 1
+#define SENSOR_MI1320 2
+#define SENSOR_MI1310_SOC 3
+#define SENSOR_OV7660 4
+#define SENSOR_OV7670 5
+#define SENSOR_PO1200 6
+#define SENSOR_PO3130NC 7
 };
 
 /* V4L2 controls supported by the driver */
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+/* next 2 controls work with ov7660 and ov7670 only */
+#define HFLIP_IDX 0
        {
            {
-               .id      = V4L2_CID_AUTOGAIN,
+               .id      = V4L2_CID_HFLIP,
                .type    = V4L2_CTRL_TYPE_BOOLEAN,
-               .name    = "Auto Gain",
+               .name    = "Mirror",
                .minimum = 0,
                .maximum = 1,
                .step    = 1,
-#define AUTOGAIN_DEF 1
-               .default_value = AUTOGAIN_DEF,
+#define HFLIP_DEF 0
+               .default_value = HFLIP_DEF,
            },
-           .set = sd_setautogain,
-           .get = sd_getautogain,
+           .set = sd_sethflip,
+           .get = sd_gethflip,
        },
-#define LIGHTFREQ_IDX 1
+#define VFLIP_IDX 1
+       {
+           {
+               .id      = V4L2_CID_VFLIP,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Vflip",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+#define VFLIP_DEF 0
+               .default_value = VFLIP_DEF,
+           },
+           .set = sd_setvflip,
+           .get = sd_getvflip,
+       },
+#define LIGHTFREQ_IDX 2
        {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -84,9 +108,25 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setfreq,
            .get = sd_getfreq,
        },
+/* po1200 only */
+#define SHARPNESS_IDX 3
+       {
+        {
+         .id = V4L2_CID_SHARPNESS,
+         .type = V4L2_CTRL_TYPE_INTEGER,
+         .name = "Sharpness",
+         .minimum = 0,
+         .maximum = 2,
+         .step = 1,
+#define SHARPNESS_DEF 1
+         .default_value = SHARPNESS_DEF,
+         },
+        .set = sd_setsharpness,
+        .get = sd_getsharpness,
+        },
 };
 
-static struct v4l2_pix_format vc0321_mode[] = {
+static const struct v4l2_pix_format vc0321_mode[] = {
        {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 2,
@@ -98,7 +138,7 @@ static struct v4l2_pix_format vc0321_mode[] = {
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
 };
-static struct v4l2_pix_format vc0323_mode[] = {
+static const struct v4l2_pix_format vc0323_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -111,6 +151,252 @@ static struct v4l2_pix_format vc0323_mode[] = {
                .priv = 0},
 };
 
+static const struct v4l2_pix_format svga_mode[] = {
+       {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 800,
+               .sizeimage = 800 * 600 * 1 / 4 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+
+/* OV7660/7670 registers */
+#define OV7660_REG_MVFP 0x1e
+#define OV7660_MVFP_MIRROR     0x20
+#define OV7660_MVFP_VFLIP      0x10
+
+static const __u8 mi0360_matrix[9] = {
+       0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50
+};
+
+static const __u8 mi0360_initVGA_JPG[][4] = {
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0xb3, 0x00, 0x24, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x03, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},
+       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},
+       {0xbc, 0x00, 0x71, 0xcc},
+       {0xb8, 0x00, 0x13, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x2c, 0x50, 0xcc},
+       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},
+       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x30, 0x50, 0xcc},
+       {0xb8, 0x31, 0xf8, 0xcc},
+       {0xb8, 0x32, 0xf8, 0xcc},
+       {0xb8, 0x33, 0xf8, 0xcc},
+       {0xb8, 0x34, 0x50, 0xcc},
+       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},
+       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb8, 0x01, 0x79, 0xcc},
+       {0xb8, 0x08, 0xe0, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xb8, 0x01, 0x79, 0xcc},
+       {0xb8, 0x14, 0x18, 0xcc},
+       {0xb8, 0xb2, 0x0a, 0xcc},
+       {0xb8, 0xb4, 0x0a, 0xcc},
+       {0xb8, 0xb5, 0x0a, 0xcc},
+       {0xb8, 0xfe, 0x00, 0xcc},
+       {0xb8, 0xff, 0x28, 0xcc},
+       {0xb9, 0x00, 0x28, 0xcc},
+       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},
+       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},
+       {0xb9, 0x05, 0x3c, 0xcc},
+       {0xb9, 0x06, 0x3c, 0xcc},
+       {0xb9, 0x07, 0x3c, 0xcc},
+       {0xb9, 0x08, 0x3c, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb8, 0x81, 0x09, 0xcc},
+       {0x31, 0x00, 0x00, 0xbb},
+       {0x09, 0x01, 0xc7, 0xbb},
+       {0x34, 0x01, 0x00, 0xbb},
+       {0x2b, 0x00, 0x28, 0xbb},
+       {0x2c, 0x00, 0x30, 0xbb},
+       {0x2d, 0x00, 0x30, 0xbb},
+       {0x2e, 0x00, 0x28, 0xbb},
+       {0x62, 0x04, 0x11, 0xbb},
+       {0x03, 0x01, 0xe0, 0xbb},
+       {0x2c, 0x00, 0x2c, 0xbb},
+       {0x20, 0xd0, 0x00, 0xbb},
+       {0x01, 0x00, 0x08, 0xbb},
+       {0x06, 0x00, 0x10, 0xbb},
+       {0x05, 0x00, 0x20, 0xbb},
+       {0x20, 0x00, 0x00, 0xbb},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x02, 0xcc},
+       {0xb6, 0x02, 0x80, 0xcc},
+       {0xb6, 0x05, 0x01, 0xcc},
+       {0xb6, 0x04, 0xe0, 0xcc},
+       {0xb6, 0x12, 0x78, 0xcc},
+       {0xb6, 0x18, 0x02, 0xcc},
+       {0xb6, 0x17, 0x58, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},
+       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},
+       {0xb3, 0x02, 0x02, 0xcc},
+       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},
+       {0xbf, 0xcc, 0x10, 0xcc},
+       {0xb9, 0x12, 0x00, 0xcc},
+       {0xb9, 0x13, 0x0a, 0xcc},
+       {0xb9, 0x14, 0x0a, 0xcc},
+       {0xb9, 0x15, 0x0a, 0xcc},
+       {0xb9, 0x16, 0x0a, 0xcc},
+       {0xb9, 0x18, 0x00, 0xcc},
+       {0xb9, 0x19, 0x0f, 0xcc},
+       {0xb9, 0x1a, 0x0f, 0xcc},
+       {0xb9, 0x1b, 0x0f, 0xcc},
+       {0xb9, 0x1c, 0x0f, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb8, 0x0c, 0x20, 0xcc},
+       {0xb8, 0x0d, 0x70, 0xcc},
+       {0xb6, 0x13, 0x13, 0xcc},
+       {0x35, 0x00, 0x60, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {}
+};
+static const __u8 mi0360_initQVGA_JPG[][4] = {
+       {0xb0, 0x03, 0x19, 0xcc},
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0xb3, 0x00, 0x24, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x03, 0xcc},
+       {0xb3, 0x03, 0x0a, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x01, 0xcc},
+       {0xb3, 0x23, 0xe0, 0xcc},
+       {0xb3, 0x04, 0x05, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x02, 0xcc},
+       {0xb3, 0x17, 0x7f, 0xcc},
+       {0xb3, 0x35, 0xdd, 0xcc},
+       {0xb3, 0x34, 0x02, 0xcc},
+       {0xb3, 0x00, 0x25, 0xcc},
+       {0xbc, 0x00, 0xd1, 0xcc},
+       {0xb8, 0x00, 0x13, 0xcc},
+       {0xb8, 0x27, 0x20, 0xcc},
+       {0xb8, 0x2c, 0x50, 0xcc},
+       {0xb8, 0x2d, 0xf8, 0xcc},
+       {0xb8, 0x2e, 0xf8, 0xcc},
+       {0xb8, 0x2f, 0xf8, 0xcc},
+       {0xb8, 0x30, 0x50, 0xcc},
+       {0xb8, 0x31, 0xf8, 0xcc},
+       {0xb8, 0x32, 0xf8, 0xcc},
+       {0xb8, 0x33, 0xf8, 0xcc},
+       {0xb8, 0x34, 0x50, 0xcc},
+       {0xb8, 0x35, 0x00, 0xcc},
+       {0xb8, 0x36, 0x00, 0xcc},
+       {0xb8, 0x37, 0x00, 0xcc},
+       {0xb8, 0x01, 0x79, 0xcc},
+       {0xb8, 0x08, 0xe0, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0xb8, 0x01, 0x79, 0xcc},
+       {0xb8, 0x14, 0x18, 0xcc},
+       {0xb8, 0xb2, 0x0a, 0xcc},
+       {0xb8, 0xb4, 0x0a, 0xcc},
+       {0xb8, 0xb5, 0x0a, 0xcc},
+       {0xb8, 0xfe, 0x00, 0xcc},
+       {0xb8, 0xff, 0x28, 0xcc},
+       {0xb9, 0x00, 0x28, 0xcc},
+       {0xb9, 0x01, 0x28, 0xcc},
+       {0xb9, 0x02, 0x28, 0xcc},
+       {0xb9, 0x03, 0x00, 0xcc},
+       {0xb9, 0x04, 0x00, 0xcc},
+       {0xb9, 0x05, 0x3c, 0xcc},
+       {0xb9, 0x06, 0x3c, 0xcc},
+       {0xb9, 0x07, 0x3c, 0xcc},
+       {0xb9, 0x08, 0x3c, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb8, 0x81, 0x09, 0xcc},
+       {0x31, 0x00, 0x00, 0xbb},
+       {0x09, 0x01, 0xc7, 0xbb},
+       {0x34, 0x01, 0x00, 0xbb},
+       {0x2b, 0x00, 0x28, 0xbb},
+       {0x2c, 0x00, 0x30, 0xbb},
+       {0x2d, 0x00, 0x30, 0xbb},
+       {0x2e, 0x00, 0x28, 0xbb},
+       {0x62, 0x04, 0x11, 0xbb},
+       {0x03, 0x01, 0xe0, 0xbb},
+       {0x2c, 0x00, 0x2c, 0xbb},
+       {0x20, 0xd0, 0x00, 0xbb},
+       {0x01, 0x00, 0x08, 0xbb},
+       {0x06, 0x00, 0x10, 0xbb},
+       {0x05, 0x00, 0x20, 0xbb},
+       {0x20, 0x00, 0x00, 0xbb},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x01, 0xcc},
+       {0xb6, 0x02, 0x40, 0xcc},
+       {0xb6, 0x05, 0x00, 0xcc},
+       {0xb6, 0x04, 0xf0, 0xcc},
+       {0xb6, 0x12, 0x78, 0xcc},
+       {0xb6, 0x18, 0x00, 0xcc},
+       {0xb6, 0x17, 0x96, 0xcc},
+       {0xb6, 0x16, 0x00, 0xcc},
+       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},
+       {0xb3, 0x02, 0x02, 0xcc},
+       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},
+       {0xbf, 0xcc, 0x10, 0xcc},
+       {0xb9, 0x12, 0x00, 0xcc},
+       {0xb9, 0x13, 0x0a, 0xcc},
+       {0xb9, 0x14, 0x0a, 0xcc},
+       {0xb9, 0x15, 0x0a, 0xcc},
+       {0xb9, 0x16, 0x0a, 0xcc},
+       {0xb9, 0x18, 0x00, 0xcc},
+       {0xb9, 0x19, 0x0f, 0xcc},
+       {0xb9, 0x1a, 0x0f, 0xcc},
+       {0xb9, 0x1b, 0x0f, 0xcc},
+       {0xb9, 0x1c, 0x0f, 0xcc},
+       {0xb8, 0x8e, 0x00, 0xcc},
+       {0xb8, 0x8f, 0xff, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x13, 0xcc},
+       {0xbc, 0x02, 0x18, 0xcc},
+       {0xbc, 0x03, 0x50, 0xcc},
+       {0xbc, 0x04, 0x18, 0xcc},
+       {0xbc, 0x05, 0x00, 0xcc},
+       {0xbc, 0x06, 0x00, 0xcc},
+       {0xbc, 0x08, 0x30, 0xcc},
+       {0xbc, 0x09, 0x40, 0xcc},
+       {0xbc, 0x0a, 0x10, 0xcc},
+       {0xb8, 0x0c, 0x20, 0xcc},
+       {0xb8, 0x0d, 0x70, 0xcc},
+       {0xbc, 0x0b, 0x00, 0xcc},
+       {0xbc, 0x0c, 0x00, 0xcc},
+       {0x35, 0x00, 0xef, 0xbb},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {}
+};
+
 static const __u8 mi1310_socinitVGA_JPG[][4] = {
        {0xb0, 0x03, 0x19, 0xcc},
        {0xb0, 0x04, 0x02, 0xcc},
@@ -823,7 +1109,7 @@ static const __u8 ov7660_initVGA_data[][4] = {
        {0x00, 0x01, 0x80, 0xaa},       {0x00, 0x02, 0x80, 0xaa},
        {0x00, 0x12, 0x80, 0xaa},
        {0x00, 0x12, 0x05, 0xaa},
-       {0x00, 0x1e, 0x01, 0xaa},
+       {0x00, 0x1e, 0x01, 0xaa},       /* MVFP */
        {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
        {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
        {0x00, 0x0d, 0x48, 0xaa},       {0x00, 0x0e, 0x04, 0xaa},
@@ -877,7 +1163,7 @@ static const __u8 ov7660_initQVGA_data[][4] = {
        {0xb8, 0x27, 0x20, 0xcc},       {0xb8, 0x8f, 0x50, 0xcc},
        {0x00, 0x01, 0x80, 0xaa},       {0x00, 0x02, 0x80, 0xaa},
        {0x00, 0x12, 0x80, 0xaa},       {0x00, 0x12, 0x05, 0xaa},
-       {0x00, 0x1e, 0x01, 0xaa},
+       {0x00, 0x1e, 0x01, 0xaa},       /* MVFP */
        {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */
        {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */
        {0x00, 0x0d, 0x48, 0xaa},       {0x00, 0x0e, 0x04, 0xaa},
@@ -983,7 +1269,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
        {0x00, 0xa9, 0x90, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
        {0x00, 0x13, 0xe5, 0xaa},       {0x00, 0x0e, 0x61, 0xaa},
        {0x00, 0x0f, 0x4b, 0xaa},       {0x00, 0x16, 0x02, 0xaa},
-       {0x00, 0x1e, 0x07, 0xaa},       {0x00, 0x21, 0x02, 0xaa},
+       {0x00, 0x1e, 0x07, 0xaa},       /* MVFP */
+       {0x00, 0x21, 0x02, 0xaa},
        {0x00, 0x22, 0x91, 0xaa},       {0x00, 0x29, 0x07, 0xaa},
        {0x00, 0x33, 0x0b, 0xaa},       {0x00, 0x35, 0x0b, 0xaa},
        {0x00, 0x37, 0x1d, 0xaa},       {0x00, 0x38, 0x71, 0xaa},
@@ -1048,7 +1335,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = {
        {0x00, 0x71, 0x35, 0xaa},       {0x00, 0x72, 0x11, 0xaa},
        {0x00, 0x73, 0xf0, 0xaa},       {0x00, 0xa2, 0x02, 0xaa},
        {0x00, 0xb1, 0x00, 0xaa},       {0x00, 0xb1, 0x0c, 0xaa},
-       {0x00, 0x1e, 0x37, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
+       {0x00, 0x1e, 0x37, 0xaa},       /* MVFP */
+       {0x00, 0xaa, 0x14, 0xaa},
        {0x00, 0x24, 0x80, 0xaa},       {0x00, 0x25, 0x74, 0xaa},
        {0x00, 0x26, 0xd3, 0xaa},       {0x00, 0x0d, 0x00, 0xaa},
        {0x00, 0x14, 0x18, 0xaa},       {0x00, 0x9d, 0x99, 0xaa},
@@ -1110,7 +1398,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
        {0x00, 0xa9, 0x90, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
        {0x00, 0x13, 0xe5, 0xaa},       {0x00, 0x0e, 0x61, 0xaa},
        {0x00, 0x0f, 0x4b, 0xaa},       {0x00, 0x16, 0x02, 0xaa},
-       {0x00, 0x1e, 0x07, 0xaa},       {0x00, 0x21, 0x02, 0xaa},
+       {0x00, 0x1e, 0x07, 0xaa},       /* MVFP */
+       {0x00, 0x21, 0x02, 0xaa},
        {0x00, 0x22, 0x91, 0xaa},       {0x00, 0x29, 0x07, 0xaa},
        {0x00, 0x33, 0x0b, 0xaa},       {0x00, 0x35, 0x0b, 0xaa},
        {0x00, 0x37, 0x1d, 0xaa},       {0x00, 0x38, 0x71, 0xaa},
@@ -1175,7 +1464,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
        {0x00, 0x71, 0x35, 0xaa},       {0x00, 0x72, 0x11, 0xaa},
        {0x00, 0x73, 0xf0, 0xaa},       {0x00, 0xa2, 0x02, 0xaa},
        {0x00, 0xb1, 0x00, 0xaa},       {0x00, 0xb1, 0x0c, 0xaa},
-       {0x00, 0x1e, 0x37, 0xaa},       {0x00, 0xaa, 0x14, 0xaa},
+       {0x00, 0x1e, 0x37, 0xaa},       /* MVFP */
+       {0x00, 0xaa, 0x14, 0xaa},
        {0x00, 0x24, 0x80, 0xaa},       {0x00, 0x25, 0x74, 0xaa},
        {0x00, 0x26, 0xd3, 0xaa},       {0x00, 0x0d, 0x00, 0xaa},
        {0x00, 0x14, 0x18, 0xaa},       {0x00, 0x9d, 0x99, 0xaa},
@@ -1204,6 +1494,275 @@ static const __u8 ov7670_initQVGA_JPG[][4] = {
        {},
 };
 
+/* PO1200 - values from usbvm326.inf and ms-win trace */
+static const __u8 po1200_gamma[17] = {
+       0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
+       0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
+};
+static const __u8 po1200_matrix[9] = {
+       0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e
+};
+static const __u8 po1200_initVGA_data[][4] = {
+       {0xb0, 0x03, 0x19, 0xcc},       /* reset? */
+       {0xb0, 0x03, 0x19, 0xcc},
+/*     {0x00, 0x00, 0x33, 0xdd}, */
+       {0xb0, 0x04, 0x02, 0xcc},
+       {0xb0, 0x02, 0x02, 0xcc},
+       {0xb3, 0x5d, 0x00, 0xcc},
+       {0xb3, 0x01, 0x01, 0xcc},
+       {0xb3, 0x00, 0x64, 0xcc},
+       {0xb3, 0x00, 0x65, 0xcc},
+       {0xb3, 0x05, 0x01, 0xcc},
+       {0xb3, 0x06, 0x01, 0xcc},
+       {0xb3, 0x5c, 0x01, 0xcc},
+       {0xb3, 0x08, 0x01, 0xcc},
+       {0xb3, 0x09, 0x0c, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x02, 0xb2, 0xcc},
+       {0xb3, 0x03, 0x18, 0xcc},
+       {0xb3, 0x04, 0x15, 0xcc},
+       {0xb3, 0x20, 0x00, 0xcc},
+       {0xb3, 0x21, 0x00, 0xcc},
+       {0xb3, 0x22, 0x02, 0xcc},
+       {0xb3, 0x23, 0x58, 0xcc},
+       {0xb3, 0x14, 0x00, 0xcc},
+       {0xb3, 0x15, 0x00, 0xcc},
+       {0xb3, 0x16, 0x03, 0xcc},
+       {0xb3, 0x17, 0x1f, 0xcc},
+       {0xbc, 0x00, 0x71, 0xcc},
+       {0xbc, 0x01, 0x01, 0xcc},
+       {0xb0, 0x54, 0x13, 0xcc},
+       {0xb3, 0x00, 0x67, 0xcc},
+       {0xb3, 0x34, 0x01, 0xcc},
+       {0xb3, 0x35, 0xdc, 0xcc},
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x12, 0x05, 0xaa},
+       {0x00, 0x13, 0x02, 0xaa},
+       {0x00, 0x1e, 0xc6, 0xaa},       /* h/v flip */
+       {0x00, 0x21, 0x00, 0xaa},
+       {0x00, 0x25, 0x02, 0xaa},
+       {0x00, 0x3c, 0x4f, 0xaa},
+       {0x00, 0x3f, 0xe0, 0xaa},
+       {0x00, 0x42, 0xff, 0xaa},
+       {0x00, 0x45, 0x34, 0xaa},
+       {0x00, 0x55, 0xfe, 0xaa},
+       {0x00, 0x59, 0xd3, 0xaa},
+       {0x00, 0x5e, 0x04, 0xaa},
+       {0x00, 0x61, 0xb8, 0xaa},       /* sharpness */
+       {0x00, 0x62, 0x02, 0xaa},
+       {0x00, 0xa7, 0x31, 0xaa},
+       {0x00, 0xa9, 0x66, 0xaa},
+       {0x00, 0xb0, 0x00, 0xaa},
+       {0x00, 0xb1, 0x00, 0xaa},
+       {0x00, 0xb3, 0x11, 0xaa},
+       {0x00, 0xb6, 0x26, 0xaa},
+       {0x00, 0xb7, 0x20, 0xaa},
+       {0x00, 0xba, 0x04, 0xaa},
+       {0x00, 0x88, 0x42, 0xaa},
+       {0x00, 0x89, 0x9a, 0xaa},
+       {0x00, 0x8a, 0x88, 0xaa},
+       {0x00, 0x8b, 0x8e, 0xaa},
+       {0x00, 0x8c, 0x3e, 0xaa},
+       {0x00, 0x8d, 0x90, 0xaa},
+       {0x00, 0x8e, 0x87, 0xaa},
+       {0x00, 0x8f, 0x96, 0xaa},
+       {0x00, 0x90, 0x3d, 0xaa},
+       {0x00, 0x64, 0x00, 0xaa},
+       {0x00, 0x65, 0x10, 0xaa},
+       {0x00, 0x66, 0x20, 0xaa},
+       {0x00, 0x67, 0x2b, 0xaa},
+       {0x00, 0x68, 0x36, 0xaa},
+       {0x00, 0x69, 0x49, 0xaa},
+       {0x00, 0x6a, 0x5a, 0xaa},
+       {0x00, 0x6b, 0x7f, 0xaa},
+       {0x00, 0x6c, 0x9b, 0xaa},
+       {0x00, 0x6d, 0xba, 0xaa},
+       {0x00, 0x6e, 0xd4, 0xaa},
+       {0x00, 0x6f, 0xea, 0xaa},
+       {0x00, 0x70, 0x00, 0xaa},
+       {0x00, 0x71, 0x10, 0xaa},
+       {0x00, 0x72, 0x20, 0xaa},
+       {0x00, 0x73, 0x2b, 0xaa},
+       {0x00, 0x74, 0x36, 0xaa},
+       {0x00, 0x75, 0x49, 0xaa},
+       {0x00, 0x76, 0x5a, 0xaa},
+       {0x00, 0x77, 0x7f, 0xaa},
+       {0x00, 0x78, 0x9b, 0xaa},
+       {0x00, 0x79, 0xba, 0xaa},
+       {0x00, 0x7a, 0xd4, 0xaa},
+       {0x00, 0x7b, 0xea, 0xaa},
+       {0x00, 0x7c, 0x00, 0xaa},
+       {0x00, 0x7d, 0x10, 0xaa},
+       {0x00, 0x7e, 0x20, 0xaa},
+       {0x00, 0x7f, 0x2b, 0xaa},
+       {0x00, 0x80, 0x36, 0xaa},
+       {0x00, 0x81, 0x49, 0xaa},
+       {0x00, 0x82, 0x5a, 0xaa},
+       {0x00, 0x83, 0x7f, 0xaa},
+       {0x00, 0x84, 0x9b, 0xaa},
+       {0x00, 0x85, 0xba, 0xaa},
+       {0x00, 0x86, 0xd4, 0xaa},
+       {0x00, 0x87, 0xea, 0xaa},
+       {0x00, 0x57, 0x2a, 0xaa},
+       {0x00, 0x03, 0x01, 0xaa},
+       {0x00, 0x04, 0x10, 0xaa},
+       {0x00, 0x05, 0x10, 0xaa},
+       {0x00, 0x06, 0x10, 0xaa},
+       {0x00, 0x07, 0x10, 0xaa},
+       {0x00, 0x08, 0x13, 0xaa},
+       {0x00, 0x0a, 0x00, 0xaa},
+       {0x00, 0x0b, 0x10, 0xaa},
+       {0x00, 0x0c, 0x20, 0xaa},
+       {0x00, 0x0d, 0x18, 0xaa},
+       {0x00, 0x22, 0x01, 0xaa},
+       {0x00, 0x23, 0x60, 0xaa},
+       {0x00, 0x25, 0x08, 0xaa},
+       {0x00, 0x26, 0x82, 0xaa},
+       {0x00, 0x2e, 0x0f, 0xaa},
+       {0x00, 0x2f, 0x1e, 0xaa},
+       {0x00, 0x30, 0x2d, 0xaa},
+       {0x00, 0x31, 0x3c, 0xaa},
+       {0x00, 0x32, 0x4b, 0xaa},
+       {0x00, 0x33, 0x5a, 0xaa},
+       {0x00, 0x34, 0x69, 0xaa},
+       {0x00, 0x35, 0x78, 0xaa},
+       {0x00, 0x36, 0x87, 0xaa},
+       {0x00, 0x37, 0x96, 0xaa},
+       {0x00, 0x38, 0xa5, 0xaa},
+       {0x00, 0x39, 0xb4, 0xaa},
+       {0x00, 0x3a, 0xc3, 0xaa},
+       {0x00, 0x3b, 0xd2, 0xaa},
+       {0x00, 0x3c, 0xe1, 0xaa},
+       {0x00, 0x3e, 0xff, 0xaa},
+       {0x00, 0x3f, 0xff, 0xaa},
+       {0x00, 0x40, 0xff, 0xaa},
+       {0x00, 0x41, 0xff, 0xaa},
+       {0x00, 0x42, 0xff, 0xaa},
+       {0x00, 0x43, 0xff, 0xaa},
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x20, 0xc4, 0xaa},
+       {0x00, 0x13, 0x03, 0xaa},
+       {0x00, 0x3c, 0x50, 0xaa},
+       {0x00, 0x61, 0x6a, 0xaa},       /* sharpness? */
+       {0x00, 0x51, 0x5b, 0xaa},
+       {0x00, 0x52, 0x91, 0xaa},
+       {0x00, 0x53, 0x4c, 0xaa},
+       {0x00, 0x54, 0x50, 0xaa},
+       {0x00, 0x56, 0x02, 0xaa},
+       {0xb6, 0x00, 0x00, 0xcc},
+       {0xb6, 0x03, 0x03, 0xcc},
+       {0xb6, 0x02, 0x20, 0xcc},
+       {0xb6, 0x05, 0x02, 0xcc},
+       {0xb6, 0x04, 0x58, 0xcc},
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x21, 0xcc},
+       {0xb6, 0x18, 0x03, 0xcc},
+       {0xb6, 0x17, 0xa9, 0xcc},
+       {0xb6, 0x16, 0x80, 0xcc},
+       {0xb6, 0x22, 0x12, 0xcc},
+       {0xb6, 0x23, 0x0b, 0xcc},
+       {0xbf, 0xc0, 0x39, 0xcc},
+       {0xbf, 0xc1, 0x04, 0xcc},
+       {0xbf, 0xcc, 0x00, 0xcc},
+       {0xb8, 0x06, 0x20, 0xcc},
+       {0xb8, 0x07, 0x03, 0xcc},
+       {0xb8, 0x08, 0x58, 0xcc},
+       {0xb8, 0x09, 0x02, 0xcc},
+       {0xb3, 0x01, 0x41, 0xcc},
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0xd9, 0x0f, 0xaa},
+       {0x00, 0xda, 0xaa, 0xaa},
+       {0x00, 0xd9, 0x10, 0xaa},
+       {0x00, 0xda, 0xaa, 0xaa},
+       {0x00, 0xd9, 0x11, 0xaa},
+       {0x00, 0xda, 0x00, 0xaa},
+       {0x00, 0xd9, 0x12, 0xaa},
+       {0x00, 0xda, 0xff, 0xaa},
+       {0x00, 0xd9, 0x13, 0xaa},
+       {0x00, 0xda, 0xff, 0xaa},
+       {0x00, 0xe8, 0x11, 0xaa},
+       {0x00, 0xe9, 0x12, 0xaa},
+       {0x00, 0xea, 0x5c, 0xaa},
+       {0x00, 0xeb, 0xff, 0xaa},
+       {0x00, 0xd8, 0x80, 0xaa},
+       {0x00, 0xe6, 0x02, 0xaa},
+       {0x00, 0xd6, 0x40, 0xaa},
+       {0x00, 0xe3, 0x05, 0xaa},
+       {0x00, 0xe0, 0x40, 0xaa},
+       {0x00, 0xde, 0x03, 0xaa},
+       {0x00, 0xdf, 0x03, 0xaa},
+       {0x00, 0xdb, 0x02, 0xaa},
+       {0x00, 0xdc, 0x00, 0xaa},
+       {0x00, 0xdd, 0x03, 0xaa},
+       {0x00, 0xe1, 0x08, 0xaa},
+       {0x00, 0xe2, 0x01, 0xaa},
+       {0x00, 0xd6, 0x40, 0xaa},
+       {0x00, 0xe4, 0x40, 0xaa},
+       {0x00, 0xa8, 0x8f, 0xaa},
+       {0x00, 0xb4, 0x16, 0xaa},
+       {0xb0, 0x02, 0x06, 0xcc},
+       {0xb0, 0x18, 0x06, 0xcc},
+       {0xb0, 0x19, 0x06, 0xcc},
+       {0xb3, 0x5d, 0x18, 0xcc},
+       {0xb3, 0x05, 0x00, 0xcc},
+       {0xb3, 0x06, 0x00, 0xcc},
+       {0x00, 0xb4, 0x0e, 0xaa},
+       {0x00, 0xb5, 0x49, 0xaa},
+       {0x00, 0xb6, 0x1c, 0xaa},
+       {0x00, 0xb7, 0x96, 0xaa},
+/* end of usbvm326.inf - start of ms-win trace */
+       {0xb6, 0x12, 0xf8, 0xcc},
+       {0xb6, 0x13, 0x3d, 0xcc},
+/*read b306*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x1a, 0x09, 0xaa},
+       {0x00, 0x1b, 0x8a, 0xaa},
+/*read b827*/
+       {0xb8, 0x27, 0x00, 0xcc},
+       {0xb8, 0x26, 0x60, 0xcc},
+       {0xb8, 0x26, 0x60, 0xcc},
+/*gamma - to do?*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0xae, 0x84, 0xaa},
+/*gamma again*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x96, 0xa0, 0xaa},
+/*matrix*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x91, 0x35, 0xaa},
+       {0x00, 0x92, 0x22, 0xaa},
+/*gamma*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x95, 0x85, 0xaa},
+/*matrix*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x4d, 0x20, 0xaa},
+       {0xb8, 0x22, 0x40, 0xcc},
+       {0xb8, 0x23, 0x40, 0xcc},
+       {0xb8, 0x24, 0x40, 0xcc},
+       {0xb8, 0x81, 0x09, 0xcc},
+       {0x00, 0x00, 0x64, 0xdd},
+       {0x00, 0x03, 0x01, 0xaa},
+/*read 46*/
+       {0x00, 0x46, 0x3c, 0xaa},
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0x16, 0x40, 0xaa},
+       {0x00, 0x17, 0x40, 0xaa},
+       {0x00, 0x18, 0x40, 0xaa},
+       {0x00, 0x19, 0x41, 0xaa},
+       {0x00, 0x03, 0x01, 0xaa},
+       {0x00, 0x46, 0x3c, 0xaa},
+       {0x00, 0x00, 0x18, 0xdd},
+/*read bfff*/
+       {0x00, 0x03, 0x00, 0xaa},
+       {0x00, 0xb4, 0x1c, 0xaa},
+       {0x00, 0xb5, 0x92, 0xaa},
+       {0x00, 0xb6, 0x39, 0xaa},
+       {0x00, 0xb7, 0x24, 0xaa},
+/*write 89 0400 1415*/
+};
+
 struct sensor_info {
        int sensorId;
        __u8 I2cAdd;
@@ -1222,6 +1781,9 @@ static const struct sensor_info sensor_info_data[] = {
        {SENSOR_MI1320,     0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
        {SENSOR_OV7670,     0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
        {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/*     {SENSOR_MI0360,     0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */
+       {SENSOR_PO1200,     0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
 };
 
 /* read 'len' bytes in gspca_dev->usb_buf */
@@ -1278,18 +1840,18 @@ static void read_sensor_register(struct gspca_dev *gspca_dev,
                msleep(1);
        }
        reg_r(gspca_dev, 0xa1, 0xb33e, 1);
-       hdata = gspca_dev->usb_buf[0];
+       ldata = gspca_dev->usb_buf[0];
        reg_r(gspca_dev, 0xa1, 0xb33d, 1);
        mdata = gspca_dev->usb_buf[0];
        reg_r(gspca_dev, 0xa1, 0xb33c, 1);
-       ldata = gspca_dev->usb_buf[0];
-       PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)",
+       hdata = gspca_dev->usb_buf[0];
+       PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x",
                hdata, mdata, ldata);
        reg_r(gspca_dev, 0xa1, 0xb334, 1);
        if (gspca_dev->usb_buf[0] == 0x02)
-               *value = (ldata << 8) + mdata;
+               *value = (hdata << 8) + mdata;
        else
-               *value = ldata;
+               *value = hdata;
 }
 
 static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
@@ -1300,7 +1862,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
        const struct sensor_info *ptsensor_info;
 
        reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
-       PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]);
+       PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]);
        for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) {
                ptsensor_info = &sensor_info_data[i];
                reg_w(dev, 0xa0, 0x02, 0xb334);
@@ -1309,16 +1871,15 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
                reg_w(dev, 0xa0, 0x01, 0xb308);
                reg_w(dev, 0xa0, 0x0c, 0xb309);
                reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
-/*             PDEBUG(D_PROBE,
-                       "check sensor VC032X -> %d Add -> ox%02X!",
-                       i, ptsensor_info->I2cAdd); */
                reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
                read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value);
-               if (value == ptsensor_info->VpId) {
-/*                     PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!",
-                               ptsensor_info->VpId); */
+               if (value == ptsensor_info->VpId)
                        return ptsensor_info->sensorId;
-               }
+
+               /* special case for MI0360 */
+               if (ptsensor_info->sensorId == SENSOR_MI1310_SOC
+                   && value == 0x8243)
+                       return SENSOR_MI0360;
        }
        return -1;
 }
@@ -1420,13 +1981,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam = &gspca_dev->cam;
        cam->epaddr = 0x02;
        sd->bridge = id->driver_info;
-       if (sd->bridge == BRIDGE_VC0321) {
-               cam->cam_mode = vc0321_mode;
-               cam->nmodes = ARRAY_SIZE(vc0321_mode);
-       } else {
-               cam->cam_mode = vc0323_mode;
-               cam->nmodes = ARRAY_SIZE(vc0323_mode);
-       }
 
        vc0321_reset(gspca_dev);
        sensor = vc032x_probe_sensor(gspca_dev);
@@ -1436,35 +1990,66 @@ static int sd_config(struct gspca_dev *gspca_dev,
                return -EINVAL;
        case SENSOR_HV7131R:
                PDEBUG(D_PROBE, "Find Sensor HV7131R");
-               sd->sensor = SENSOR_HV7131R;
+               break;
+       case SENSOR_MI0360:
+               PDEBUG(D_PROBE, "Find Sensor MI0360");
+               sd->bridge = BRIDGE_VC0323;
                break;
        case SENSOR_MI1310_SOC:
                PDEBUG(D_PROBE, "Find Sensor MI1310_SOC");
-               sd->sensor = SENSOR_MI1310_SOC;
                break;
        case SENSOR_MI1320:
                PDEBUG(D_PROBE, "Find Sensor MI1320");
-               sd->sensor = SENSOR_MI1320;
                break;
        case SENSOR_OV7660:
                PDEBUG(D_PROBE, "Find Sensor OV7660");
-               sd->sensor = SENSOR_OV7660;
                break;
        case SENSOR_OV7670:
                PDEBUG(D_PROBE, "Find Sensor OV7670");
-               sd->sensor = SENSOR_OV7670;
+               break;
+       case SENSOR_PO1200:
+               PDEBUG(D_PROBE, "Find Sensor PO1200");
                break;
        case SENSOR_PO3130NC:
                PDEBUG(D_PROBE, "Find Sensor PO3130NC");
-               sd->sensor = SENSOR_PO3130NC;
                break;
        }
+       sd->sensor = sensor;
 
-       sd->qindex = 7;
-       sd->autogain = AUTOGAIN_DEF;
+       if (sd->bridge == BRIDGE_VC0321) {
+               cam->cam_mode = vc0321_mode;
+               cam->nmodes = ARRAY_SIZE(vc0321_mode);
+       } else {
+               if (sensor != SENSOR_PO1200) {
+                       cam->cam_mode = vc0323_mode;
+                       cam->nmodes = ARRAY_SIZE(vc0323_mode);
+               } else {
+                       cam->cam_mode = svga_mode;
+                       cam->nmodes = ARRAY_SIZE(svga_mode);
+               }
+       }
+
+       sd->hflip = HFLIP_DEF;
+       sd->vflip = VFLIP_DEF;
+       if (sd->sensor == SENSOR_OV7670) {
+               sd->hflip = 1;
+               sd->vflip = 1;
+       }
        sd->lightfreq = FREQ_DEF;
        if (sd->sensor != SENSOR_OV7670)
                gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+       switch (sd->sensor) {
+       case SENSOR_OV7660:
+       case SENSOR_OV7670:
+       case SENSOR_PO1200:
+               break;
+       default:
+               gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
+                                       | (1 << VFLIP_IDX);
+               break;
+       }
+
+       sd->sharpness = SHARPNESS_DEF;
 
        if (sd->bridge == BRIDGE_VC0321) {
                reg_r(gspca_dev, 0x8a, 0, 3);
@@ -1482,12 +2067,33 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
-static void setquality(struct gspca_dev *gspca_dev)
+/* for OV7660 and OV7670 only */
+static void sethvflip(struct gspca_dev *gspca_dev)
 {
-}
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 data;
 
-static void setautogain(struct gspca_dev *gspca_dev)
-{
+       switch (sd->sensor) {
+       case SENSOR_OV7660:
+               data = 1;
+               break;
+       case SENSOR_OV7670:
+               data = 7;
+               break;
+       case SENSOR_PO1200:
+               data = 0;
+               i2c_write(gspca_dev, 0x03, &data, 1);
+               data = 0x80 * sd->hflip
+                       | 0x40 * sd->vflip
+                       | 0x06;
+               i2c_write(gspca_dev, 0x1e, &data, 1);
+               return;
+       default:
+               return;
+       }
+       data |= OV7660_MVFP_MIRROR * sd->hflip
+               | OV7660_MVFP_VFLIP * sd->vflip;
+       i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1);
 }
 
 static void setlightfreq(struct gspca_dev *gspca_dev)
@@ -1501,6 +2107,20 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
        usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]);
 }
 
+/* po1200 only */
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       __u8 data;
+
+       if (sd->sensor != SENSOR_PO1200)
+               return;
+       data = 0;
+       i2c_write(gspca_dev, 0x03, &data, 1);
+       data = 0xb5 + sd->sharpness * 3;
+       i2c_write(gspca_dev, 0x61, &data, 1);
+}
+
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -1551,6 +2171,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
                        usb_exchange(gspca_dev, ov7670_initVGA_JPG);
                }
                break;
+       case SENSOR_MI0360:
+               GammaT = mi1320_gamma;
+               MatrixT = mi0360_matrix;
+               if (mode) {
+                       /* 320x240 */
+                       usb_exchange(gspca_dev, mi0360_initQVGA_JPG);
+               } else {
+                       /* 640x480 */
+                       usb_exchange(gspca_dev, mi0360_initVGA_JPG);
+               }
+               break;
        case SENSOR_MI1310_SOC:
                if (mode) {
                        /* 320x240 */
@@ -1583,6 +2214,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
                }
                usb_exchange(gspca_dev, po3130_rundata);
                break;
+       case SENSOR_PO1200:
+               GammaT = po1200_gamma;
+               MatrixT = po1200_matrix;
+               usb_exchange(gspca_dev, po1200_initVGA_data);
+               break;
        default:
                PDEBUG(D_PROBE, "Damned !! no sensor found Bye");
                return -EMEDIUMTYPE;
@@ -1615,11 +2251,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS
                */
                /* set the led on 0x0892 0x0896 */
-               reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
-               msleep(100);
-               setquality(gspca_dev);
-               setautogain(gspca_dev);
-               setlightfreq(gspca_dev);
+               if (sd->sensor != SENSOR_PO1200) {
+                       reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
+                       msleep(100);
+                       sethvflip(gspca_dev);
+                       setlightfreq(gspca_dev);
+               } else {
+                       setsharpness(gspca_dev);
+                       sethvflip(gspca_dev);
+                       reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+               }
        }
        return 0;
 }
@@ -1665,24 +2306,48 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                data, len);
                return;
        }
+
+       /* The vc0321 sends some additional data after sending the complete
+        * frame, we ignore this. */
+       if (sd->bridge == BRIDGE_VC0321
+           && len > frame->v4l2_buf.length - (frame->data_end - frame->data))
+               len = frame->v4l2_buf.length - (frame->data_end - frame->data);
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->hflip = val;
+       if (gspca_dev->streaming)
+               sethvflip(gspca_dev);
+       return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->hflip;
+       return 0;
+}
+
+static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->autogain = val;
+       sd->vflip = val;
        if (gspca_dev->streaming)
-               setautogain(gspca_dev);
+               sethvflip(gspca_dev);
        return 0;
 }
 
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->autogain;
+       *val = sd->vflip;
        return 0;
 }
 
@@ -1704,6 +2369,24 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming)
+               setsharpness(gspca_dev);
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
 static int sd_querymenu(struct gspca_dev *gspca_dev,
                        struct v4l2_querymenu *menu)
 {
@@ -1743,11 +2426,13 @@ static const struct sd_desc sd_desc = {
 static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321},
        {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321},
+       {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321},
        {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321},
        {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323},
        {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321},
        {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321},
        {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321},
+       {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323},
        {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323},
        {}
 };
index f52e09c2cc1912e7942d95b7875096ac2e60f769..bfb559c3b71383bde525291fa5b9b31ccab70b24 100644 (file)
 #define ZC3XX_R1CA_SHARPNESS04         0x01ca
 #define ZC3XX_R1CB_SHARPNESS05         0x01cb
 
-/* Synchronization */
-#define ZC3XX_R190_SYNC00LOW           0x0190
-#define ZC3XX_R191_SYNC00MID           0x0191
-#define ZC3XX_R192_SYNC00HIGH          0x0192
-#define ZC3XX_R195_SYNC01LOW           0x0195
-#define ZC3XX_R196_SYNC01MID           0x0196
-#define ZC3XX_R197_SYNC01HIGH          0x0197
-
 /* Dead pixels */
 #define ZC3XX_R250_DEADPIXELSMODE      0x0250
 
index 0befacf4985541b833e230c5544ce2fff2ff51db..ec2a53d53fe269c3886a0ad3bad92a693777f36a 100644 (file)
@@ -51,16 +51,16 @@ struct sd {
 #define SENSOR_CS2102 0
 #define SENSOR_CS2102K 1
 #define SENSOR_GC0305 2
-#define SENSOR_HDCS2020 3
-#define SENSOR_HDCS2020b 4
-#define SENSOR_HV7131B 5
-#define SENSOR_HV7131C 6
-#define SENSOR_ICM105A 7
-#define SENSOR_MC501CB 8
-#define SENSOR_OV7620 9
-/*#define SENSOR_OV7648 9 - same values */
-#define SENSOR_OV7630C 10
-#define SENSOR_PAS106 11
+#define SENSOR_HDCS2020b 3
+#define SENSOR_HV7131B 4
+#define SENSOR_HV7131C 5
+#define SENSOR_ICM105A 6
+#define SENSOR_MC501CB 7
+#define SENSOR_OV7620 8
+/*#define SENSOR_OV7648 8 - same values */
+#define SENSOR_OV7630C 9
+#define SENSOR_PAS106 10
+#define SENSOR_PAS202B 11
 #define SENSOR_PB0330 12
 #define SENSOR_PO2030 13
 #define SENSOR_TAS5130CK 14
@@ -173,7 +173,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -186,7 +186,7 @@ static struct v4l2_pix_format vga_mode[] = {
                .priv = 0},
 };
 
-static struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -1653,295 +1653,6 @@ static const struct usb_action gc0305_NoFliker[] = {
        {}
 };
 
-/* play poker with registers at your own risk !! */
-static const struct usb_action hdcs2020xx_Initial[] = {
-       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-       {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
-       {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
-       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
-       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
-       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
-       {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW},
-                                               /* D0 ?? E0 did not start */
-       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
-       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
-       {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW},
-       {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},
-       {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW},
-       {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},
-       {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
-       {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},
-       {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
-       {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
-       {0xaa, 0x02, 0x0002},
-       {0xaa, 0x07, 0x0006},
-       {0xaa, 0x08, 0x0002},
-       {0xaa, 0x09, 0x0006},
-       {0xaa, 0x0a, 0x0001},
-       {0xaa, 0x0b, 0x0001},
-       {0xaa, 0x0c, 0x0008},
-       {0xaa, 0x0d, 0x0000},
-       {0xaa, 0x10, 0x0000},
-       {0xaa, 0x12, 0x0005},
-       {0xaa, 0x13, 0x0063},
-       {0xaa, 0x15, 0x0070},
-       {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
-       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
-       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-       {0xa0, 0x00, 0x01ad},
-       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
-       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
-       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
-       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
-       {0xa0, 0x70, ZC3XX_R18D_YTARGET},
-       {0xa1, 0x01, 0x0002},
-       {0xa1, 0x01, 0x0008},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},  /* clock ? */
-       {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00},   /* sharpness+ */
-       {0xa1, 0x01, 0x01c8},
-       {0xa1, 0x01, 0x01c9},
-       {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05},   /* sharpness- */
-       {0xa0, 0x11, ZC3XX_R120_GAMMA00},       /* gamma ~4 */
-       {0xa0, 0x37, ZC3XX_R121_GAMMA01},
-       {0xa0, 0x58, ZC3XX_R122_GAMMA02},
-       {0xa0, 0x79, ZC3XX_R123_GAMMA03},
-       {0xa0, 0x91, ZC3XX_R124_GAMMA04},
-       {0xa0, 0xa6, ZC3XX_R125_GAMMA05},
-       {0xa0, 0xb8, ZC3XX_R126_GAMMA06},
-       {0xa0, 0xc7, ZC3XX_R127_GAMMA07},
-       {0xa0, 0xd3, ZC3XX_R128_GAMMA08},
-       {0xa0, 0xde, ZC3XX_R129_GAMMA09},
-       {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
-       {0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
-       {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
-       {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
-       {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
-       {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
-       {0xa0, 0x26, ZC3XX_R130_GAMMA10},
-       {0xa0, 0x23, ZC3XX_R131_GAMMA11},
-       {0xa0, 0x20, ZC3XX_R132_GAMMA12},
-       {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
-       {0xa0, 0x16, ZC3XX_R134_GAMMA14},
-       {0xa0, 0x13, ZC3XX_R135_GAMMA15},
-       {0xa0, 0x10, ZC3XX_R136_GAMMA16},
-       {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
-       {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
-       {0xa0, 0x09, ZC3XX_R139_GAMMA19},
-       {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
-       {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
-       {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
-       {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
-       {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
-       {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
-
-       {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
-       {0xa0, 0xf5, ZC3XX_R10B_RGB01},
-       {0xa0, 0xff, ZC3XX_R10C_RGB02},
-       {0xa0, 0xf9, ZC3XX_R10D_RGB10},
-       {0xa0, 0x51, ZC3XX_R10E_RGB11},
-       {0xa0, 0xf5, ZC3XX_R10F_RGB12},
-       {0xa0, 0xfb, ZC3XX_R110_RGB20},
-       {0xa0, 0xed, ZC3XX_R111_RGB21},
-       {0xa0, 0x5f, ZC3XX_R112_RGB22},
-
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
-       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
-       {0xaa, 0x20, 0x0004},
-       {0xaa, 0x21, 0x003d},
-       {0xaa, 0x03, 0x0041},
-       {0xaa, 0x04, 0x0010},
-       {0xaa, 0x05, 0x003d},
-       {0xaa, 0x0e, 0x0001},
-       {0xaa, 0x0f, 0x0000},
-       {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
-       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-       {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
-       {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
-       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-       {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW},
-       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
-       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
-       {0xa0, 0x41, ZC3XX_R01D_HSYNC_0},
-       {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
-       {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
-       {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
-       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
-       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
-       {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa1, 0x01, 0x0195},
-       {0xa1, 0x01, 0x0196},
-       {0xa1, 0x01, 0x0197},
-       {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW},
-       {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},
-       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-       {0xa0, 0x1d, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x85, ZC3XX_R118_BGAIN},
-       {0xa1, 0x01, 0x0116},
-       {0xa1, 0x01, 0x0118},
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x1d, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x85, ZC3XX_R118_BGAIN},
-       {0xa1, 0x01, 0x0116},
-       {0xa1, 0x01, 0x0118},
-/*     {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
-       {0xa0, 0x00, 0x0007},
-       {}
-};
-
-static const struct usb_action hdcs2020xx_InitialScale[] = {
-       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-       {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},
-       {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
-       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
-       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
-       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
-       {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
-       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
-       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
-       {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},
-       {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
-       {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},
-       {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
-       {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},
-       {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
-       {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
-       {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
-       {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
-       {0xaa, 0x02, 0x0002},
-       {0xaa, 0x07, 0x0006},
-       {0xaa, 0x08, 0x0002},
-       {0xaa, 0x09, 0x0006},
-       {0xaa, 0x0a, 0x0001},
-       {0xaa, 0x0b, 0x0001},
-       {0xaa, 0x0c, 0x0008},
-       {0xaa, 0x0d, 0x0000},
-       {0xaa, 0x10, 0x0000},
-       {0xaa, 0x12, 0x0005},
-       {0xaa, 0x13, 0x0063},
-       {0xaa, 0x15, 0x0070},
-       {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
-       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
-       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
-       {0xa0, 0x00, 0x01ad},
-       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
-       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
-       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
-       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
-       {0xa0, 0x70, ZC3XX_R18D_YTARGET},
-       {0xa1, 0x01, 0x0002},
-       {0xa1, 0x01, 0x0008},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},  /* clock ? */
-       {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00},   /* sharpness+ */
-       {0xa1, 0x01, 0x01c8},
-       {0xa1, 0x01, 0x01c9},
-       {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05},   /* sharpness- */
-       {0xa0, 0x11, ZC3XX_R120_GAMMA00},       /* gamma ~4*/
-       {0xa0, 0x37, ZC3XX_R121_GAMMA01},
-       {0xa0, 0x58, ZC3XX_R122_GAMMA02},
-       {0xa0, 0x79, ZC3XX_R123_GAMMA03},
-       {0xa0, 0x91, ZC3XX_R124_GAMMA04},
-       {0xa0, 0xa6, ZC3XX_R125_GAMMA05},
-       {0xa0, 0xb8, ZC3XX_R126_GAMMA06},
-       {0xa0, 0xc7, ZC3XX_R127_GAMMA07},
-       {0xa0, 0xd3, ZC3XX_R128_GAMMA08},
-       {0xa0, 0xde, ZC3XX_R129_GAMMA09},
-       {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A},
-       {0xa0, 0xed, ZC3XX_R12B_GAMMA0B},
-       {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C},
-       {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D},
-       {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E},
-       {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
-       {0xa0, 0x26, ZC3XX_R130_GAMMA10},
-       {0xa0, 0x23, ZC3XX_R131_GAMMA11},
-       {0xa0, 0x20, ZC3XX_R132_GAMMA12},
-       {0xa0, 0x1c, ZC3XX_R133_GAMMA13},
-       {0xa0, 0x16, ZC3XX_R134_GAMMA14},
-       {0xa0, 0x13, ZC3XX_R135_GAMMA15},
-       {0xa0, 0x10, ZC3XX_R136_GAMMA16},
-       {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
-       {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
-       {0xa0, 0x09, ZC3XX_R139_GAMMA19},
-       {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
-       {0xa0, 0x06, ZC3XX_R13B_GAMMA1B},
-       {0xa0, 0x05, ZC3XX_R13C_GAMMA1C},
-       {0xa0, 0x04, ZC3XX_R13D_GAMMA1D},
-       {0xa0, 0x03, ZC3XX_R13E_GAMMA1E},
-       {0xa0, 0x02, ZC3XX_R13F_GAMMA1F},
-       {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
-       {0xa0, 0xff, ZC3XX_R10B_RGB01},
-       {0xa0, 0xff, ZC3XX_R10C_RGB02},
-       {0xa0, 0xff, ZC3XX_R10D_RGB10},
-       {0xa0, 0x60, ZC3XX_R10E_RGB11},
-       {0xa0, 0xff, ZC3XX_R10F_RGB12},
-       {0xa0, 0xff, ZC3XX_R110_RGB20},
-       {0xa0, 0xff, ZC3XX_R111_RGB21},
-       {0xa0, 0x60, ZC3XX_R112_RGB22},
-
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},
-       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},
-       {0xaa, 0x20, 0x0002},
-       {0xaa, 0x21, 0x001b},
-       {0xaa, 0x03, 0x0044},
-       {0xaa, 0x04, 0x0008},
-       {0xaa, 0x05, 0x001b},
-       {0xaa, 0x0e, 0x0001},
-       {0xaa, 0x0f, 0x0000},
-       {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
-       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-       {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
-       {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
-       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
-       {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW},
-       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
-       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
-       {0xa0, 0x44, ZC3XX_R01D_HSYNC_0},
-       {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},
-       {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},
-       {0xa0, 0xeb, ZC3XX_R020_HSYNC_3},
-       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},
-       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},
-       {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa1, 0x01, 0x0195},
-       {0xa1, 0x01, 0x0196},
-       {0xa1, 0x01, 0x0197},
-       {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW},
-       {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID},
-       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
-       {0xa0, 0x1d, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x99, ZC3XX_R118_BGAIN},
-       {0xa1, 0x01, 0x0116},
-       {0xa1, 0x01, 0x0118},
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x1d, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x99, ZC3XX_R118_BGAIN},
-/*     {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
-       {0xa0, 0x00, 0x0007},
-/*     {0xa0, 0x18, 0x00fe}, */
-       {}
-};
 static const struct usb_action hdcs2020xb_Initial[] = {
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
        {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT},
@@ -2310,67 +2021,6 @@ static const struct usb_action hv7131bxx_Initial[] = {           /* 320x240 */
        {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
        {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
        {0xaa, 0x02, 0x0090},                   /* 00,02,80,aa */
-       {0xa1, 0x01, 0x0002},
-       {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
-       {0xa1, 0x01, 0x0091},
-       {0xa1, 0x01, 0x0095},
-       {0xa1, 0x01, 0x0096},
-
-       {0xa1, 0x01, 0x0008},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},  /* clock ? */
-       {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},   /* sharpness+ */
-       {0xa1, 0x01, 0x01c8},
-       {0xa1, 0x01, 0x01c9},
-       {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},   /* sharpness- */
-
-       {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
-       {0xa0, 0xf8, ZC3XX_R10B_RGB01},
-       {0xa0, 0xf8, ZC3XX_R10C_RGB02},
-       {0xa0, 0xf8, ZC3XX_R10D_RGB10},
-       {0xa0, 0x50, ZC3XX_R10E_RGB11},
-       {0xa0, 0xf8, ZC3XX_R10F_RGB12},
-       {0xa0, 0xf8, ZC3XX_R110_RGB20},
-       {0xa0, 0xf8, ZC3XX_R111_RGB21},
-       {0xa0, 0x50, ZC3XX_R112_RGB22},
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-       {0xaa, 0x25, 0x0007},
-       {0xaa, 0x26, 0x00a1},
-       {0xaa, 0x27, 0x0020},
-       {0xaa, 0x20, 0x0000},
-       {0xaa, 0x21, 0x00a0},
-       {0xaa, 0x22, 0x0016},
-       {0xaa, 0x23, 0x0040},
-
-       {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 2F */
-       {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},      /* 4d */
-       {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},
-       {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
-       {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID},
-       {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW},
-       {0xa0, 0x07, ZC3XX_R18C_AEFREEZE},
-       {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE},
-       {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},
-       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
-       {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1},
-       {0xa0, 0x16, ZC3XX_R01F_HSYNC_2},
-       {0xa0, 0x40, ZC3XX_R020_HSYNC_3},
-       {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
-       {0xa1, 0x01, 0x001d},
-       {0xa1, 0x01, 0x001e},
-       {0xa1, 0x01, 0x001f},
-       {0xa1, 0x01, 0x0020},
-       {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x40, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x40, ZC3XX_R118_BGAIN},
-/*     {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
        {}
 };
 
@@ -2418,65 +2068,156 @@ static const struct usb_action hv7131bxx_InitialScale[] = {    /* 640x480*/
        {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
        {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
        {0xaa, 0x02, 0x0090},   /* {0xaa, 0x02, 0x0080}, */
-       {0xa1, 0x01, 0x0002},
-       {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
-       {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
-       {0xa1, 0x01, 0x0091},
-       {0xa1, 0x01, 0x0095},
-       {0xa1, 0x01, 0x0096},
-       {0xa1, 0x01, 0x0008},
-       {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},  /* clock ? */
-       {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00},   /* sharpness+ */
-       {0xa1, 0x01, 0x01c8},
-       {0xa1, 0x01, 0x01c9},
-       {0xa1, 0x01, 0x01ca},
-       {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05},   /* sharpness- */
-
-       {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */
-       {0xa0, 0xf8, ZC3XX_R10B_RGB01},
-       {0xa0, 0xf8, ZC3XX_R10C_RGB02},
-       {0xa0, 0xf8, ZC3XX_R10D_RGB10},
-       {0xa0, 0x50, ZC3XX_R10E_RGB11},
-       {0xa0, 0xf8, ZC3XX_R10F_RGB12},
-       {0xa0, 0xf8, ZC3XX_R110_RGB20},
-       {0xa0, 0xf8, ZC3XX_R111_RGB21},
-       {0xa0, 0x50, ZC3XX_R112_RGB22},
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
-       {0xaa, 0x25, 0x0007},
-       {0xaa, 0x26, 0x00a1},
-       {0xaa, 0x27, 0x0020},
-       {0xaa, 0x20, 0x0000},
-       {0xaa, 0x21, 0x0040},
-       {0xaa, 0x22, 0x0013},
-       {0xaa, 0x23, 0x004c},
-       {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 2f */
-       {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID},      /* 4d */
-       {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},      /* 60 */
-       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
-       {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID},
-       {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW},
-       {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
-       {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
-       {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},
-       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
-       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
-       {0xa0, 0x40, ZC3XX_R01E_HSYNC_1},
-       {0xa0, 0x13, ZC3XX_R01F_HSYNC_2},
-       {0xa0, 0x4c, ZC3XX_R020_HSYNC_3},
-       {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
-       {0xa1, 0x01, 0x001d},
-       {0xa1, 0x01, 0x001e},
-       {0xa1, 0x01, 0x001f},
-       {0xa1, 0x01, 0x0020},
-       {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa1, 0x01, 0x0180},
-       {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
-       {0xa0, 0x40, ZC3XX_R116_RGAIN},
-       {0xa0, 0x40, ZC3XX_R117_GGAIN},
-       {0xa0, 0x40, ZC3XX_R118_BGAIN},
-/*     {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */
+       {}
+};
+static const struct usb_action hv7131b_50HZ[] = {      /* 640x480*/
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+       {0xaa, 0x25, 0x0007},                   /* 00,25,07,aa */
+       {0xaa, 0x26, 0x0053},                   /* 00,26,53,aa */
+       {0xaa, 0x27, 0x0000},                   /* 00,27,00,aa */
+       {0xaa, 0x20, 0x0000},                   /* 00,20,00,aa */
+       {0xaa, 0x21, 0x0050},                   /* 00,21,50,aa */
+       {0xaa, 0x22, 0x001b},                   /* 00,22,1b,aa */
+       {0xaa, 0x23, 0x00fc},                   /* 00,23,fc,aa */
+       {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,2f,cc */
+       {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,9b,cc */
+       {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,80,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,ea,cc */
+       {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,60,cc */
+       {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},      /* 01,8c,0c,cc */
+       {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},    /* 01,8f,18,cc */
+       {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,18,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},       /* 00,1d,00,cc */
+       {0xa0, 0x50, ZC3XX_R01E_HSYNC_1},       /* 00,1e,50,cc */
+       {0xa0, 0x1b, ZC3XX_R01F_HSYNC_2},       /* 00,1f,1b,cc */
+       {0xa0, 0xfc, ZC3XX_R020_HSYNC_3},       /* 00,20,fc,cc */
+       {}
+};
+static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+       {0xaa, 0x25, 0x0007},                   /* 00,25,07,aa */
+       {0xaa, 0x26, 0x0053},                   /* 00,26,53,aa */
+       {0xaa, 0x27, 0x0000},                   /* 00,27,00,aa */
+       {0xaa, 0x20, 0x0000},                   /* 00,20,00,aa */
+       {0xaa, 0x21, 0x0050},                   /* 00,21,50,aa */
+       {0xaa, 0x22, 0x0012},                   /* 00,22,12,aa */
+       {0xaa, 0x23, 0x0080},                   /* 00,23,80,aa */
+       {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,2f,cc */
+       {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,9b,cc */
+       {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,80,cc */
+       {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,01,cc */
+       {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,d4,cc */
+       {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,c0,cc */
+       {0xa0, 0x07, ZC3XX_R18C_AEFREEZE},      /* 01,8c,07,cc */
+       {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE},    /* 01,8f,0f,cc */
+       {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,18,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},       /* 00,1d,00,cc */
+       {0xa0, 0x50, ZC3XX_R01E_HSYNC_1},       /* 00,1e,50,cc */
+       {0xa0, 0x12, ZC3XX_R01F_HSYNC_2},       /* 00,1f,12,cc */
+       {0xa0, 0x80, ZC3XX_R020_HSYNC_3},       /* 00,20,80,cc */
+       {}
+};
+static const struct usb_action hv7131b_60HZ[] = {      /* 640x480*/
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+       {0xaa, 0x25, 0x0007},                   /* 00,25,07,aa */
+       {0xaa, 0x26, 0x00a1},                   /* 00,26,a1,aa */
+       {0xaa, 0x27, 0x0020},                   /* 00,27,20,aa */
+       {0xaa, 0x20, 0x0000},                   /* 00,20,00,aa */
+       {0xaa, 0x21, 0x0040},                   /* 00,21,40,aa */
+       {0xaa, 0x22, 0x0013},                   /* 00,22,13,aa */
+       {0xaa, 0x23, 0x004c},                   /* 00,23,4c,aa */
+       {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,2f,cc */
+       {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,4d,cc */
+       {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,60,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,c3,cc */
+       {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,50,cc */
+       {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},      /* 01,8c,0c,cc */
+       {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},    /* 01,8f,18,cc */
+       {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,18,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},       /* 00,1d,00,cc */
+       {0xa0, 0x40, ZC3XX_R01E_HSYNC_1},       /* 00,1e,40,cc */
+       {0xa0, 0x13, ZC3XX_R01F_HSYNC_2},       /* 00,1f,13,cc */
+       {0xa0, 0x4c, ZC3XX_R020_HSYNC_3},       /* 00,20,4c,cc */
+       {}
+};
+static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+       {0xaa, 0x25, 0x0007},                   /* 00,25,07,aa */
+       {0xaa, 0x26, 0x00a1},                   /* 00,26,a1,aa */
+       {0xaa, 0x27, 0x0020},                   /* 00,27,20,aa */
+       {0xaa, 0x20, 0x0000},                   /* 00,20,00,aa */
+       {0xaa, 0x21, 0x00a0},                   /* 00,21,a0,aa */
+       {0xaa, 0x22, 0x0016},                   /* 00,22,16,aa */
+       {0xaa, 0x23, 0x0040},                   /* 00,23,40,aa */
+       {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,2f,cc */
+       {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,4d,cc */
+       {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,60,cc */
+       {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,01,cc */
+       {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,86,cc */
+       {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,a0,cc */
+       {0xa0, 0x07, ZC3XX_R18C_AEFREEZE},      /* 01,8c,07,cc */
+       {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE},    /* 01,8f,0f,cc */
+       {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,18,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},       /* 00,1d,00,cc */
+       {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1},       /* 00,1e,a0,cc */
+       {0xa0, 0x16, ZC3XX_R01F_HSYNC_2},       /* 00,1f,16,cc */
+       {0xa0, 0x40, ZC3XX_R020_HSYNC_3},       /* 00,20,40,cc */
+       {}
+};
+static const struct usb_action hv7131b_NoFliker[] = {  /* 640x480*/
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+       {0xaa, 0x25, 0x0003},                   /* 00,25,03,aa */
+       {0xaa, 0x26, 0x0000},                   /* 00,26,00,aa */
+       {0xaa, 0x27, 0x0000},                   /* 00,27,00,aa */
+       {0xaa, 0x20, 0x0000},                   /* 00,20,00,aa */
+       {0xaa, 0x21, 0x0010},                   /* 00,21,10,aa */
+       {0xaa, 0x22, 0x0000},                   /* 00,22,00,aa */
+       {0xaa, 0x23, 0x0003},                   /* 00,23,03,aa */
+       {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,2f,cc */
+       {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,f8,cc */
+       {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,00,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,02,cc */
+       {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,00,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},      /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},    /* 01,8f,20,cc */
+       {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,00,cc */
+       {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,00,cc */
+       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},       /* 00,1d,00,cc */
+       {0xa0, 0x10, ZC3XX_R01E_HSYNC_1},       /* 00,1e,10,cc */
+       {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},       /* 00,1f,00,cc */
+       {0xa0, 0x03, ZC3XX_R020_HSYNC_3},       /* 00,20,03,cc */
+       {}
+};
+static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
+       {0xaa, 0x25, 0x0003},                   /* 00,25,03,aa */
+       {0xaa, 0x26, 0x0000},                   /* 00,26,00,aa */
+       {0xaa, 0x27, 0x0000},                   /* 00,27,00,aa */
+       {0xaa, 0x20, 0x0000},                   /* 00,20,00,aa */
+       {0xaa, 0x21, 0x00a0},                   /* 00,21,a0,aa */
+       {0xaa, 0x22, 0x0016},                   /* 00,22,16,aa */
+       {0xaa, 0x23, 0x0040},                   /* 00,23,40,aa */
+       {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,2f,cc */
+       {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,f8,cc */
+       {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,00,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,02,cc */
+       {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,00,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},      /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},    /* 01,8f,20,cc */
+       {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,00,cc */
+       {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,00,cc */
+       {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},       /* 00,1d,00,cc */
+       {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1},       /* 00,1e,a0,cc */
+       {0xa0, 0x16, ZC3XX_R01F_HSYNC_2},       /* 00,1f,16,cc */
+       {0xa0, 0x40, ZC3XX_R020_HSYNC_3},       /* 00,20,40,cc */
        {}
 };
 
@@ -4389,6 +4130,270 @@ static const struct usb_action pas106b_NoFliker[] = {
        {}
 };
 
+/* from usbvm31b.inf */
+static const struct usb_action pas202b_Initial[] = {   /* 640x480 */
+       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},         /* 00,00,01,cc */
+       {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING},          /* 00,08,00,cc */
+       {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0e,cc */
+       {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},           /* 00,02,00,cc */
+       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},        /* 00,03,02,cc */
+       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},         /* 00,04,80,cc */
+       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},       /* 00,05,01,cc */
+       {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},        /* 00,06,e0,cc */
+       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},       /* 00,01,01,cc */
+       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,03,cc */
+       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,01,cc */
+       {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},       /* 00,8d,08,cc */
+       {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},          /* 00,98,00,cc */
+       {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW},          /* 00,9a,03,cc */
+       {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},             /* 01,1a,00,cc */
+       {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW},             /* 01,1c,03,cc */
+       {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},         /* 00,9b,01,cc */
+       {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},          /* 00,9c,e6,cc */
+       {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},          /* 00,9d,02,cc */
+       {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},           /* 00,9e,86,cc */
+       {0xaa, 0x02, 0x0002},                   /* 00,02,04,aa --> 02 */
+       {0xaa, 0x07, 0x0006},                           /* 00,07,06,aa */
+       {0xaa, 0x08, 0x0002},                           /* 00,08,02,aa */
+       {0xaa, 0x09, 0x0006},                           /* 00,09,06,aa */
+       {0xaa, 0x0a, 0x0001},                           /* 00,0a,01,aa */
+       {0xaa, 0x0b, 0x0001},                           /* 00,0b,01,aa */
+       {0xaa, 0x0c, 0x0008},                           /* 00,0c,08,aa */
+       {0xaa, 0x0d, 0x0000},                           /* 00,0d,00,aa */
+       {0xaa, 0x10, 0x0000},                           /* 00,10,00,aa */
+       {0xaa, 0x12, 0x0005},                           /* 00,12,05,aa */
+       {0xaa, 0x13, 0x0063},                           /* 00,13,63,aa */
+       {0xaa, 0x15, 0x0070},                           /* 00,15,70,aa */
+       {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},      /* 01,01,b7,cc */
+       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0d,cc */
+       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},             /* 01,89,06,cc */
+       {0xa0, 0x00, 0x01ad},                           /* 01,ad,00,cc */
+       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},         /* 01,c5,03,cc */
+       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},           /* 01,cb,13,cc */
+       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},        /* 02,50,08,cc */
+       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},          /* 03,01,08,cc */
+       {0xa0, 0x70, ZC3XX_R18D_YTARGET},               /* 01,8d,70,cc */
+       {}
+};
+static const struct usb_action pas202b_InitialScale[] = {      /* 320x240 */
+       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},         /* 00,00,01,cc */
+       {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING},          /* 00,08,00,cc */
+       {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT},      /* 00,10,0e,cc */
+       {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},           /* 00,02,10,cc */
+       {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},        /* 00,03,02,cc */
+       {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},         /* 00,04,80,cc */
+       {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},       /* 00,05,01,cc */
+       {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW},        /* 00,06,d0,cc */
+       {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},       /* 00,01,01,cc */
+       {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,03,cc */
+       {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},      /* 00,12,01,cc */
+       {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE},       /* 00,8d,08,cc */
+       {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW},          /* 00,98,08,cc */
+       {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW},          /* 00,9a,02,cc */
+       {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW},             /* 01,1a,08,cc */
+       {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW},             /* 01,1c,02,cc */
+       {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},         /* 00,9b,01,cc */
+       {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW},          /* 00,9c,d8,cc */
+       {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},          /* 00,9d,02,cc */
+       {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},           /* 00,9e,88,cc */
+       {0xaa, 0x02, 0x0002},                           /* 00,02,02,aa */
+       {0xaa, 0x07, 0x0006},                           /* 00,07,06,aa */
+       {0xaa, 0x08, 0x0002},                           /* 00,08,02,aa */
+       {0xaa, 0x09, 0x0006},                           /* 00,09,06,aa */
+       {0xaa, 0x0a, 0x0001},                           /* 00,0a,01,aa */
+       {0xaa, 0x0b, 0x0001},                           /* 00,0b,01,aa */
+       {0xaa, 0x0c, 0x0008},                           /* 00,0c,08,aa */
+       {0xaa, 0x0d, 0x0000},                           /* 00,0d,00,aa */
+       {0xaa, 0x10, 0x0000},                           /* 00,10,00,aa */
+       {0xaa, 0x12, 0x0005},                           /* 00,12,05,aa */
+       {0xaa, 0x13, 0x0063},                           /* 00,13,63,aa */
+       {0xaa, 0x15, 0x0070},                           /* 00,15,70,aa */
+       {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},      /* 01,01,37,cc */
+       {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},         /* 01,00,0d,cc */
+       {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},             /* 01,89,06,cc */
+       {0xa0, 0x00, 0x01ad},                           /* 01,ad,00,cc */
+       {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},         /* 01,c5,03,cc */
+       {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},           /* 01,cb,13,cc */
+       {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},        /* 02,50,08,cc */
+       {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},          /* 03,01,08,cc */
+       {0xa0, 0x70, ZC3XX_R18D_YTARGET},               /* 01,8d,70,cc */
+       {}
+};
+static const struct usb_action pas202b_50HZ[] = {
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},         /* 00,19,00,cc */
+       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},            /* 00,87,20,cc */
+       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},            /* 00,88,21,cc */
+       {0xaa, 0x20, 0x0002},                           /* 00,20,02,aa */
+       {0xaa, 0x21, 0x0068},                           /* 00,21,68,aa */
+       {0xaa, 0x03, 0x0044},                           /* 00,03,44,aa */
+       {0xaa, 0x04, 0x0009},                           /* 00,04,09,aa */
+       {0xaa, 0x05, 0x0028},                           /* 00,05,28,aa */
+       {0xaa, 0x0e, 0x0001},                           /* 00,0e,01,aa */
+       {0xaa, 0x0f, 0x0000},                           /* 00,0f,00,aa */
+       {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,14,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc */
+       {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,07,cc */
+       {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,d2,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc */
+       {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,4d,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},              /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,20,cc */
+       {0xa0, 0x44, ZC3XX_R01D_HSYNC_0},               /* 00,1d,44,cc */
+       {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},               /* 00,1e,6f,cc */
+       {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},               /* 00,1f,ad,cc */
+       {0xa0, 0xeb, ZC3XX_R020_HSYNC_3},               /* 00,20,eb,cc */
+       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},            /* 00,87,0f,cc */
+       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},            /* 00,88,0e,cc */
+       {}
+};
+static const struct usb_action pas202b_50HZScale[] = {
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},         /* 00,19,00,cc */
+       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},            /* 00,87,20,cc */
+       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},            /* 00,88,21,cc */
+       {0xaa, 0x20, 0x0002},                           /* 00,20,02,aa */
+       {0xaa, 0x21, 0x006c},                           /* 00,21,6c,aa */
+       {0xaa, 0x03, 0x0041},                           /* 00,03,41,aa */
+       {0xaa, 0x04, 0x0009},                           /* 00,04,09,aa */
+       {0xaa, 0x05, 0x002c},                           /* 00,05,2c,aa */
+       {0xaa, 0x0e, 0x0001},                           /* 00,0e,01,aa */
+       {0xaa, 0x0f, 0x0000},                           /* 00,0f,00,aa */
+       {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,14,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc */
+       {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,0f,cc */
+       {0xa0, 0xbe, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,be,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc */
+       {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,9b,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},              /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,20,cc */
+       {0xa0, 0x41, ZC3XX_R01D_HSYNC_0},               /* 00,1d,41,cc */
+       {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},               /* 00,1e,6f,cc */
+       {0xa0, 0xad, ZC3XX_R01F_HSYNC_2},               /* 00,1f,ad,cc */
+       {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc */
+       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},            /* 00,87,0f,cc */
+       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},            /* 00,88,0e,cc */
+       {}
+};
+static const struct usb_action pas202b_60HZ[] = {
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},         /* 00,19,00,cc */
+       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},            /* 00,87,20,cc */
+       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},            /* 00,88,21,cc */
+       {0xaa, 0x20, 0x0002},                           /* 00,20,02,aa */
+       {0xaa, 0x21, 0x0000},                           /* 00,21,00,aa */
+       {0xaa, 0x03, 0x0045},                           /* 00,03,45,aa */
+       {0xaa, 0x04, 0x0008},                           /* 00,04,08,aa */
+       {0xaa, 0x05, 0x0000},                           /* 00,05,00,aa */
+       {0xaa, 0x0e, 0x0001},                           /* 00,0e,01,aa */
+       {0xaa, 0x0f, 0x0000},                           /* 00,0f,00,aa */
+       {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,14,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc */
+       {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,07,cc */
+       {0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,c0,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc */
+       {0xa0, 0x40, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,40,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},              /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,20,cc */
+       {0xa0, 0x45, ZC3XX_R01D_HSYNC_0},               /* 00,1d,45,cc */
+       {0xa0, 0x8e, ZC3XX_R01E_HSYNC_1},               /* 00,1e,8e,cc */
+       {0xa0, 0xc1, ZC3XX_R01F_HSYNC_2},               /* 00,1f,c1,cc */
+       {0xa0, 0xf5, ZC3XX_R020_HSYNC_3},               /* 00,20,f5,cc */
+       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},            /* 00,87,0f,cc */
+       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},            /* 00,88,0e,cc */
+       {}
+};
+static const struct usb_action pas202b_60HZScale[] = {
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},         /* 00,19,00,cc */
+       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},            /* 00,87,20,cc */
+       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},            /* 00,88,21,cc */
+       {0xaa, 0x20, 0x0002},                           /* 00,20,02,aa */
+       {0xaa, 0x21, 0x0004},                           /* 00,21,04,aa */
+       {0xaa, 0x03, 0x0042},                           /* 00,03,42,aa */
+       {0xaa, 0x04, 0x0008},                           /* 00,04,08,aa */
+       {0xaa, 0x05, 0x0004},                           /* 00,05,04,aa */
+       {0xaa, 0x0e, 0x0001},                           /* 00,0e,01,aa */
+       {0xaa, 0x0f, 0x0000},                           /* 00,0f,00,aa */
+       {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,14,cc */
+       {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,24,cc */
+       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc */
+       {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,0f,cc */
+       {0xa0, 0x9f, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,9f,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc */
+       {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,81,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},              /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,20,cc */
+       {0xa0, 0x42, ZC3XX_R01D_HSYNC_0},               /* 00,1d,42,cc */
+       {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1},               /* 00,1e,6f,cc */
+       {0xa0, 0xaf, ZC3XX_R01F_HSYNC_2},               /* 00,1f,af,cc */
+       {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc */
+       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},            /* 00,87,0f,cc */
+       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},            /* 00,88,0e,cc */
+       {}
+};
+static const struct usb_action pas202b_NoFliker[] = {
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},         /* 00,19,00,cc */
+       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},            /* 00,87,20,cc */
+       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},            /* 00,88,21,cc */
+       {0xaa, 0x20, 0x0002},                           /* 00,20,02,aa */
+       {0xaa, 0x21, 0x0020},                           /* 00,21,20,aa */
+       {0xaa, 0x03, 0x0040},                           /* 00,03,40,aa */
+       {0xaa, 0x04, 0x0008},                           /* 00,04,08,aa */
+       {0xaa, 0x05, 0x0020},                           /* 00,05,20,aa */
+       {0xaa, 0x0e, 0x0001},                           /* 00,0e,01,aa */
+       {0xaa, 0x0f, 0x0000},                           /* 00,0f,00,aa */
+       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc */
+       {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,07,cc */
+       {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,f0,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc */
+       {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,02,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},              /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,20,cc */
+       {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,00,cc */
+       {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,00,cc */
+       {0xa0, 0x40, ZC3XX_R01D_HSYNC_0},               /* 00,1d,40,cc */
+       {0xa0, 0x60, ZC3XX_R01E_HSYNC_1},               /* 00,1e,60,cc */
+       {0xa0, 0x90, ZC3XX_R01F_HSYNC_2},               /* 00,1f,90,cc */
+       {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc */
+       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},            /* 00,87,0f,cc */
+       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},            /* 00,88,0e,cc */
+       {}
+};
+static const struct usb_action pas202b_NoFlikerScale[] = {
+       {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},         /* 00,19,00,cc */
+       {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID},            /* 00,87,20,cc */
+       {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW},            /* 00,88,21,cc */
+       {0xaa, 0x20, 0x0002},                           /* 00,20,02,aa */
+       {0xaa, 0x21, 0x0010},                           /* 00,21,10,aa */
+       {0xaa, 0x03, 0x0040},                           /* 00,03,40,aa */
+       {0xaa, 0x04, 0x0008},                           /* 00,04,08,aa */
+       {0xaa, 0x05, 0x0010},                           /* 00,05,10,aa */
+       {0xaa, 0x0e, 0x0001},                           /* 00,0e,01,aa */
+       {0xaa, 0x0f, 0x0000},                           /* 00,0f,00,aa */
+       {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},     /* 01,90,00,cc */
+       {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID},      /* 01,91,0f,cc */
+       {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},      /* 01,92,f0,cc */
+       {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},       /* 01,95,00,cc */
+       {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},        /* 01,96,00,cc */
+       {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW},        /* 01,97,02,cc */
+       {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},              /* 01,8c,10,cc */
+       {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},            /* 01,8f,20,cc */
+       {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},      /* 01,a9,00,cc */
+       {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},       /* 01,aa,00,cc */
+       {0xa0, 0x40, ZC3XX_R01D_HSYNC_0},               /* 00,1d,40,cc */
+       {0xa0, 0x60, ZC3XX_R01E_HSYNC_1},               /* 00,1e,60,cc */
+       {0xa0, 0x90, ZC3XX_R01F_HSYNC_2},               /* 00,1f,90,cc */
+       {0xa0, 0xff, ZC3XX_R020_HSYNC_3},               /* 00,20,ff,cc */
+       {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID},            /* 00,87,0f,cc */
+       {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW},            /* 00,88,0e,cc */
+       {}
+};
+
 static const struct usb_action pb03303x_Initial[] = {
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
        {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -5725,7 +5730,7 @@ static const struct usb_action tas5130cxx_Initial[] = {
        {}
 };
 static const struct usb_action tas5130cxx_InitialScale[] = {
-       {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+/*??   {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, */
        {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
        {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},
 
@@ -6049,7 +6054,7 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
        {0xaa, 0x1b, 0x0000},           /* 00,1b,00,aa, */
        {0xaa, 0x13, 0x0002},           /* 00,13,02,aa, */
        {0xaa, 0x15, 0x0004},           /* 00,15,04,aa */
-       {0xaa, 0x01, 0x0000},
+/*??   {0xaa, 0x01, 0x0000}, */
        {0xaa, 0x01, 0x0000},
        {0xaa, 0x1a, 0x0000},           /* 00,1a,00,aa, */
        {0xaa, 0x1c, 0x0017},           /* 00,1c,17,aa, */
@@ -6065,8 +6070,8 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
        {0xaa, 0x0f, 0x00a0},           /* 00,0f,a0,aa, */
        {0xaa, 0x10, 0x0000},           /* 00,10,00,aa, */
        {0xaa, 0x11, 0x00a0},           /* 00,11,a0,aa, */
-       {0xa0, 0x00, 0x0039},
-       {0xa1, 0x01, 0x0037},
+/*??   {0xa0, 0x00, 0x0039},
+       {0xa1, 0x01, 0x0037}, */
        {0xaa, 0x16, 0x0001},           /* 00,16,01,aa, */
        {0xaa, 0x17, 0x00e8},           /* 00,17,e6,aa (e6 -> e8) */
        {0xaa, 0x18, 0x0002},           /* 00,18,02,aa, */
@@ -6303,7 +6308,7 @@ static __u8 i2c_write(struct gspca_dev *gspca_dev,
        reg_w_i(gspca_dev->dev, valL, 0x93);
        reg_w_i(gspca_dev->dev, valH, 0x94);
        reg_w_i(gspca_dev->dev, 0x01, 0x90);            /* <- write command */
-       msleep(5);
+       msleep(15);
        retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
        PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
                        reg, valH, valL, retbyte);
@@ -6346,30 +6351,35 @@ static void setmatrix(struct gspca_dev *gspca_dev)
                {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50};
        static const __u8 ov7620_matrix[9] =
                {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58};
+       static const __u8 pas202b_matrix[9] =
+               {0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f};
        static const __u8 po2030_matrix[9] =
                {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
        static const __u8 vf0250_matrix[9] =
                {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
+       static const __u8 *matrix_tb[SENSOR_MAX] = {
+               NULL,           /* SENSOR_CS2102 0 */
+               NULL,           /* SENSOR_CS2102K 1 */
+               gc0305_matrix,  /* SENSOR_GC0305 2 */
+               NULL,           /* SENSOR_HDCS2020b 3 */
+               NULL,           /* SENSOR_HV7131B 4 */
+               NULL,           /* SENSOR_HV7131C 5 */
+               NULL,           /* SENSOR_ICM105A 6 */
+               NULL,           /* SENSOR_MC501CB 7 */
+               ov7620_matrix,  /* SENSOR_OV7620 8 */
+               NULL,           /* SENSOR_OV7630C 9 */
+               NULL,           /* SENSOR_PAS106 10 */
+               pas202b_matrix, /* SENSOR_PAS202B 11 */
+               NULL,           /* SENSOR_PB0330 12 */
+               po2030_matrix,  /* SENSOR_PO2030 13 */
+               NULL,           /* SENSOR_TAS5130CK 14 */
+               NULL,           /* SENSOR_TAS5130CXX 15 */
+               vf0250_matrix,  /* SENSOR_TAS5130C_VF0250 16 */
+       };
 
-       switch (sd->sensor) {
-       case SENSOR_GC0305:
-               matrix = gc0305_matrix;
-               break;
-       case SENSOR_MC501CB:
-               return;         /* no matrix? */
-       case SENSOR_OV7620:
-/*     case SENSOR_OV7648: */
-               matrix = ov7620_matrix;
-               break;
-       case SENSOR_PO2030:
-               matrix = po2030_matrix;
-               break;
-       case SENSOR_TAS5130C_VF0250:
-               matrix = vf0250_matrix;
-               break;
-       default:                /* matrix already loaded */
-               return;
-       }
+       matrix = matrix_tb[sd->sensor];
+       if (matrix == NULL)
+               return;         /* matrix already loaded */
        for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++)
                reg_w(gspca_dev->dev, matrix[i], 0x010a + i);
 }
@@ -6585,42 +6595,42 @@ static int setlightfreq(struct gspca_dev *gspca_dev)
                {gc0305_NoFliker, gc0305_NoFliker,
                 gc0305_50HZ, gc0305_50HZ,
                 gc0305_60HZ, gc0305_60HZ},
-/* SENSOR_HDCS2020 3 */
-               {NULL, NULL,
-                NULL, NULL,
-                NULL, NULL},
-/* SENSOR_HDCS2020b 4 */
+/* SENSOR_HDCS2020b 3 */
                {hdcs2020b_NoFliker, hdcs2020b_NoFliker,
                 hdcs2020b_50HZ, hdcs2020b_50HZ,
                 hdcs2020b_60HZ, hdcs2020b_60HZ},
-/* SENSOR_HV7131B 5 */
+/* SENSOR_HV7131B 4 */
+               {hv7131b_NoFlikerScale, hv7131b_NoFliker,
+                hv7131b_50HZScale, hv7131b_50HZ,
+                hv7131b_60HZScale, hv7131b_60HZ},
+/* SENSOR_HV7131C 5 */
                {NULL, NULL,
                 NULL, NULL,
                 NULL, NULL},
-/* SENSOR_HV7131C 6 */
-               {NULL, NULL,
-                NULL, NULL,
-                NULL, NULL},
-/* SENSOR_ICM105A 7 */
+/* SENSOR_ICM105A 6 */
                {icm105a_NoFliker, icm105a_NoFlikerScale,
                 icm105a_50HZ, icm105a_50HZScale,
                 icm105a_60HZ, icm105a_60HZScale},
-/* SENSOR_MC501CB 8 */
+/* SENSOR_MC501CB 7 */
                {MC501CB_NoFliker, MC501CB_NoFlikerScale,
                 MC501CB_50HZ, MC501CB_50HZScale,
                 MC501CB_60HZ, MC501CB_60HZScale},
-/* SENSOR_OV7620 9 */
+/* SENSOR_OV7620 8 */
                {OV7620_NoFliker, OV7620_NoFliker,
                 OV7620_50HZ, OV7620_50HZ,
                 OV7620_60HZ, OV7620_60HZ},
-/* SENSOR_OV7630C 10 */
+/* SENSOR_OV7630C 9 */
                {NULL, NULL,
                 NULL, NULL,
                 NULL, NULL},
-/* SENSOR_PAS106 11 */
+/* SENSOR_PAS106 10 */
                {pas106b_NoFliker, pas106b_NoFliker,
                 pas106b_50HZ, pas106b_50HZ,
                 pas106b_60HZ, pas106b_60HZ},
+/* SENSOR_PAS202B 11 */
+               {pas202b_NoFlikerScale, pas202b_NoFliker,
+                pas202b_50HZScale, pas202b_50HZ,
+                pas202b_60HZScale, pas202b_60HZ},
 /* SENSOR_PB0330 12 */
                {pb0330_NoFliker, pb0330_NoFlikerScale,
                 pb0330_50HZ, pb0330_50HZScale,
@@ -7002,15 +7012,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
                5,      /* SENSOR_CS2102 0 */
                5,      /* SENSOR_CS2102K 1 */
                4,      /* SENSOR_GC0305 2 */
-               4,      /* SENSOR_HDCS2020 3 */
-               4,      /* SENSOR_HDCS2020b 4 */
-               4,      /* SENSOR_HV7131B 5 */
-               4,      /* SENSOR_HV7131C 6 */
-               4,      /* SENSOR_ICM105A 7 */
-               4,      /* SENSOR_MC501CB 8 */
-               3,      /* SENSOR_OV7620 9 */
-               4,      /* SENSOR_OV7630C 10 */
-               4,      /* SENSOR_PAS106 11 */
+               4,      /* SENSOR_HDCS2020b 3 */
+               4,      /* SENSOR_HV7131B 4 */
+               4,      /* SENSOR_HV7131C 5 */
+               4,      /* SENSOR_ICM105A 6 */
+               4,      /* SENSOR_MC501CB 7 */
+               3,      /* SENSOR_OV7620 8 */
+               4,      /* SENSOR_OV7630C 9 */
+               4,      /* SENSOR_PAS106 10 */
+               4,      /* SENSOR_PAS202B 11 */
                4,      /* SENSOR_PB0330 12 */
                4,      /* SENSOR_PO2030 13 */
                4,      /* SENSOR_TAS5130CK 14 */
@@ -7066,8 +7076,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        sd->sensor = SENSOR_ICM105A;
                        break;
                case 0x0e:
-                       PDEBUG(D_PROBE, "Find Sensor HDCS2020");
-                       sd->sensor = SENSOR_HDCS2020;
+                       PDEBUG(D_PROBE, "Find Sensor PAS202B");
+                       sd->sensor = SENSOR_PAS202B;
                        sd->sharpness = 1;
                        break;
                case 0x0f:
@@ -7153,7 +7163,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->gamma = gamma[(int) sd->sensor];
        sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
        sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
-       sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value;
 
        switch (sd->sensor) {
        case SENSOR_GC0305:
@@ -7161,7 +7170,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
        case SENSOR_PO2030:
                gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX);
                break;
-       case SENSOR_HDCS2020:
        case SENSOR_HV7131B:
        case SENSOR_HV7131C:
        case SENSOR_OV7630C:
@@ -7191,15 +7199,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
                {cs2102_InitialScale, cs2102_Initial},          /* 0 */
                {cs2102K_InitialScale, cs2102K_Initial},        /* 1 */
                {gc0305_Initial, gc0305_InitialScale},          /* 2 */
-               {hdcs2020xx_InitialScale, hdcs2020xx_Initial},  /* 3 */
-               {hdcs2020xb_InitialScale, hdcs2020xb_Initial},  /* 4 */
-               {hv7131bxx_InitialScale, hv7131bxx_Initial},    /* 5 */
-               {hv7131cxx_InitialScale, hv7131cxx_Initial},    /* 6 */
-               {icm105axx_InitialScale, icm105axx_Initial},    /* 7 */
-               {MC501CB_InitialScale, MC501CB_Initial},        /* 9 */
-               {OV7620_mode0, OV7620_mode1},                   /* 9 */
-               {ov7630c_InitialScale, ov7630c_Initial},        /* 10 */
-               {pas106b_InitialScale, pas106b_Initial},        /* 11 */
+               {hdcs2020xb_InitialScale, hdcs2020xb_Initial},  /* 3 */
+               {hv7131bxx_InitialScale, hv7131bxx_Initial},    /* 4 */
+               {hv7131cxx_InitialScale, hv7131cxx_Initial},    /* 5 */
+               {icm105axx_InitialScale, icm105axx_Initial},    /* 6 */
+               {MC501CB_InitialScale, MC501CB_Initial},        /* 7 */
+               {OV7620_mode0, OV7620_mode1},                   /* 8 */
+               {ov7630c_InitialScale, ov7630c_Initial},        /* 9 */
+               {pas106b_InitialScale, pas106b_Initial},        /* 10 */
+               {pas202b_Initial, pas202b_InitialScale},        /* 11 */
                {pb0330xx_InitialScale, pb0330xx_Initial},      /* 12 */
 /* or          {pb03303x_InitialScale, pb03303x_Initial}, */
                {PO2030_mode0, PO2030_mode1},                   /* 13 */
@@ -7256,6 +7264,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_r(gspca_dev, 0x0008);
                reg_w(dev, 0x00, 0x0008);
                break;
+       case SENSOR_PAS202B:
        case SENSOR_GC0305:
                reg_r(gspca_dev, 0x0008);
                /* fall thru */
@@ -7269,7 +7278,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
        switch (sd->sensor) {
        case SENSOR_CS2102:             /* gamma set in xxx_Initial */
        case SENSOR_CS2102K:
-       case SENSOR_HDCS2020:
        case SENSOR_HDCS2020b:
        case SENSOR_PB0330:             /* pb with chip_revision - see above */
        case SENSOR_OV7630C:
@@ -7282,6 +7290,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        setmatrix(gspca_dev);                   /* one more time? */
        switch (sd->sensor) {
        case SENSOR_OV7620:
+       case SENSOR_PAS202B:
                reg_r(gspca_dev, 0x0180);       /* from win */
                reg_w(dev, 0x00, 0x0180);
                break;
@@ -7293,37 +7302,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        switch (sd->sensor) {
        case SENSOR_GC0305:
-       case SENSOR_OV7620:
                reg_w(dev, 0x09, 0x01ad);       /* (from win traces) */
                reg_w(dev, 0x15, 0x01ae);
-               sd->autogain = 0;
-               break;
+               /* fall thru */
+       case SENSOR_PAS202B:
        case SENSOR_PO2030:
-               reg_w(dev, 0x40, 0x0117);       /* (from win traces) */
+/*             reg_w(dev, 0x40, ZC3XX_R117_GGAIN);  * (from win traces) */
                reg_r(gspca_dev, 0x0180);
                break;
-       }
-
-       setautogain(gspca_dev);
-       switch (sd->sensor) {
-       case SENSOR_GC0305:
-/*             setlightfreq(gspca_dev);        ?? (end: 80 -> [18d]) */
-               reg_w(dev, 0x09, 0x01ad);       /* (from win traces) */
-               reg_w(dev, 0x15, 0x01ae);
-               reg_w(dev, 0x40, 0x0180);
-               reg_w(dev, 0x40, 0x0117);
-               reg_r(gspca_dev, 0x0180);
-               sd->autogain = 1;
-               setautogain(gspca_dev);
-               break;
        case SENSOR_OV7620:
+               reg_w(dev, 0x09, 0x01ad);
+               reg_w(dev, 0x15, 0x01ae);
                i2c_read(gspca_dev, 0x13);      /*fixme: returns 0xa3 */
                i2c_write(gspca_dev, 0x13, 0xa3, 0x00);
                                         /*fixme: returned value to send? */
-               reg_w(dev, 0x40, 0x0117);       /* (from win traces) */
+               reg_w(dev, 0x40, 0x0117);
                reg_r(gspca_dev, 0x0180);
-               setautogain(gspca_dev);
-               msleep(500);
+               break;
+       }
+
+       setautogain(gspca_dev);
+       switch (sd->sensor) {
+       case SENSOR_PAS202B:
+               reg_w(dev, 0x00, 0x0007);       /* (from win traces) */
                break;
        case SENSOR_PO2030:
                msleep(500);
@@ -7333,6 +7334,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w(dev, 0x02, 0x0008);
                break;
        }
+       if (sd->sensor == SENSOR_PAS202B)
+               reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
        return 0;
 }
 
@@ -7530,6 +7533,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0458, 0x700c)},
        {USB_DEVICE(0x0458, 0x700f)},
        {USB_DEVICE(0x0461, 0x0a00)},
+       {USB_DEVICE(0x046d, 0x089d), .driver_info = SENSOR_MC501CB},
        {USB_DEVICE(0x046d, 0x08a0)},
        {USB_DEVICE(0x046d, 0x08a1)},
        {USB_DEVICE(0x046d, 0x08a2)},
index efe849981ab7c3766bb61efe78e437ebc1bb6ff1..d4658c56eddc53974a7e96e59833f25a6af00e45 100644 (file)
@@ -385,10 +385,10 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                goto err_out_detach;
        }
 
-       /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
+       /* Phys addr can only be set after attaching (for ir->c.dev) */
        snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
-                ir->c.adapter->dev.bus_id,
-                ir->c.dev.bus_id);
+                dev_name(&ir->c.adapter->dev),
+                dev_name(&ir->c.dev));
 
        /* init + register input device */
        ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
index 4e05f91a9100522a0bc8801fed81aa00be41e631..2883c8780760f28a327bab83594cfc77d13f4dd4 100644 (file)
@@ -877,20 +877,28 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
 static const struct ivtv_card ivtv_card_pg600v2 = {
        .type = IVTV_CARD_PG600V2,
        .name = "Yuan PG600-2, GotView PCI DVD Lite",
-       .comment = "only Composite and S-Video inputs are supported, not the tuner\n",
        .v4l2_capabilities = IVTV_CAP_ENCODER,
        .hw_video = IVTV_HW_CX25840,
        .hw_audio = IVTV_HW_CX25840,
        .hw_audio_ctrl = IVTV_HW_CX25840,
-       .hw_all = IVTV_HW_CX25840,
+       .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+       /* XC2028 support apparently works for the Yuan, it's still
+          uncertain whether it also works with the GotView. */
        .video_inputs = {
-               { IVTV_CARD_INPUT_SVIDEO1,    0,
+               { IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+               { IVTV_CARD_INPUT_SVIDEO1,    1,
                  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
-               { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+               { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
        },
        .audio_inputs = {
+               { IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
                { IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
        },
+       .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+       .xceive_pin = 12,
+       .tuners = {
+               { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+       },
        .pci_list = ivtv_pci_pg600v2,
        .i2c = &ivtv_i2c_std,
 };
index 48e103be718340fe0db30394d5b2b989912c8697..62aa06f5d168529d4b946418005222edfbfa74da 100644 (file)
@@ -63,7 +63,7 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
        case V4L2_CID_CONTRAST:
-               if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl))
+               if (v4l2_subdev_call(itv->sd_video, core, queryctrl, qctrl))
                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
                return 0;
 
@@ -73,7 +73,7 @@ int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_LOUDNESS:
-               if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+               if (v4l2_subdev_call(itv->sd_audio, core, queryctrl, qctrl))
                        qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
                return 0;
 
@@ -122,7 +122,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
        case V4L2_CID_CONTRAST:
-               return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl);
+               return v4l2_subdev_call(itv->sd_video, core, s_ctrl, vctrl);
 
        case V4L2_CID_AUDIO_VOLUME:
        case V4L2_CID_AUDIO_MUTE:
@@ -130,7 +130,7 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_LOUDNESS:
-               return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+               return v4l2_subdev_call(itv->sd_audio, core, s_ctrl, vctrl);
 
        default:
                IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
@@ -147,7 +147,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
        case V4L2_CID_HUE:
        case V4L2_CID_SATURATION:
        case V4L2_CID_CONTRAST:
-               return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl);
+               return v4l2_subdev_call(itv->sd_video, core, g_ctrl, vctrl);
 
        case V4L2_CID_AUDIO_VOLUME:
        case V4L2_CID_AUDIO_MUTE:
@@ -155,7 +155,7 @@ static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
        case V4L2_CID_AUDIO_BASS:
        case V4L2_CID_AUDIO_TREBLE:
        case V4L2_CID_AUDIO_LOUDNESS:
-               return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+               return v4l2_subdev_call(itv->sd_audio, core, g_ctrl, vctrl);
        default:
                IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
                return -EINVAL;
@@ -268,7 +268,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
                        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                        fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
                        fmt.fmt.pix.height = itv->params.height;
-                       itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
+                       v4l2_subdev_call(itv->sd_video, video, s_fmt, &fmt);
                }
                err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
                if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
@@ -279,7 +279,7 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
                /* The audio clock of the digitizer must match the codec sample
                   rate otherwise you get some very strange effects. */
                if (idx < sizeof(freqs))
-                       ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
+                       ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
                return err;
        }
        return -EINVAL;
index b69cc1d55e5ba93028da8389dc54e61b64b7d13d..08b762951759eab53949ea35c13b40f77f2eca95 100644 (file)
@@ -60,9 +60,6 @@
 #include <media/v4l2-chip-ident.h>
 #include "tuner-xc2028.h"
 
-/* var to keep track of the number of array elements in use */
-int ivtv_cards_active;
-
 /* If you have already X v4l cards, then set this to X. This way
    the device numbers stay matched. Example: you have a WinTV card
    without radio and a PVR-350 with. Normally this would give a
@@ -70,12 +67,6 @@ int ivtv_cards_active;
    setting this to 1 you ensure that radio0 is now also radio1. */
 int ivtv_first_minor;
 
-/* Master variable for all ivtv info */
-struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
-
-/* Protects ivtv_cards_active */
-DEFINE_SPINLOCK(ivtv_cards_lock);
-
 /* add your revision and whatnot here */
 static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
        {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
@@ -87,6 +78,9 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
 
+/* ivtv instance counter */
+static atomic_t ivtv_instance = ATOMIC_INIT(0);
+
 /* Parameter declarations */
 static int cardtype[IVTV_MAX_CARDS];
 static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
@@ -599,9 +593,9 @@ static void ivtv_process_options(struct ivtv *itv)
        itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
        itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
        itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
-       itv->options.cardtype = cardtype[itv->num];
-       itv->options.tuner = tuner[itv->num];
-       itv->options.radio = radio[itv->num];
+       itv->options.cardtype = cardtype[itv->instance];
+       itv->options.tuner = tuner[itv->instance];
+       itv->options.radio = radio[itv->instance];
        itv->options.newi2c = newi2c;
        if (tunertype < -1 || tunertype > 1) {
                IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
@@ -688,7 +682,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
        spin_lock_init(&itv->lock);
        spin_lock_init(&itv->dma_reg_lock);
 
-       itv->irq_work_queues = create_singlethread_workqueue(itv->name);
+       itv->irq_work_queues = create_singlethread_workqueue(itv->device.name);
        if (itv->irq_work_queues == NULL) {
                IVTV_ERR("Could not create ivtv workqueue\n");
                return -1;
@@ -770,12 +764,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
                i = 0;
        itv->active_input = i;
        itv->audio_input = itv->card->video_inputs[i].audio_index;
-       if (itv->card->hw_all & IVTV_HW_CX25840)
-               itv->video_dec_func = ivtv_cx25840;
-       else if (itv->card->hw_all & IVTV_HW_SAA717X)
-               itv->video_dec_func = ivtv_saa717x;
-       else
-               itv->video_dec_func = ivtv_saa7115;
 }
 
 static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
@@ -788,21 +776,21 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
        IVTV_DEBUG_INFO("Enabling pci device\n");
 
        if (pci_enable_device(dev)) {
-               IVTV_ERR("Can't enable device %d!\n", itv->num);
+               IVTV_ERR("Can't enable device!\n");
                return -EIO;
        }
        if (pci_set_dma_mask(dev, 0xffffffff)) {
-               IVTV_ERR("No suitable DMA available on card %d.\n", itv->num);
+               IVTV_ERR("No suitable DMA available.\n");
                return -EIO;
        }
        if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
-               IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num);
+               IVTV_ERR("Cannot request encoder memory region.\n");
                return -EIO;
        }
 
        if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
                                IVTV_REG_SIZE, "ivtv registers")) {
-               IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num);
+               IVTV_ERR("Cannot request register memory region.\n");
                release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
                return -EIO;
        }
@@ -810,7 +798,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
        if (itv->has_cx23415 &&
            !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
                                IVTV_DECODER_SIZE, "ivtv decoder")) {
-               IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num);
+               IVTV_ERR("Cannot request decoder memory region.\n");
                release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
                release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
                return -EIO;
@@ -853,69 +841,11 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
        return 0;
 }
 
-#ifdef MODULE
-static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
-               const char *name, u32 id)
-{
-       if ((hw & id) == 0)
-               return hw;
-       if (request_module(name) != 0) {
-               IVTV_ERR("Failed to load module %s\n", name);
-               return hw & ~id;
-       }
-       IVTV_DEBUG_INFO("Loaded module %s\n", name);
-       return hw;
-}
-#endif
-
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
        u32 hw = itv->card->hw_all;
        unsigned i;
 
-#ifdef MODULE
-       /* load modules */
-#ifdef CONFIG_MEDIA_TUNER_MODULE
-       hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
-#endif
-#ifdef CONFIG_VIDEO_CX25840_MODULE
-       hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
-#endif
-#ifdef CONFIG_VIDEO_SAA711X_MODULE
-       hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
-#endif
-#ifdef CONFIG_VIDEO_SAA7127_MODULE
-       hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
-#endif
-#ifdef CONFIG_VIDEO_SAA717X_MODULE
-       hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
-#endif
-#ifdef CONFIG_VIDEO_UPD64031A_MODULE
-       hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
-#endif
-#ifdef CONFIG_VIDEO_UPD64083_MODULE
-       hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
-#endif
-#ifdef CONFIG_VIDEO_MSP3400_MODULE
-       hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
-#endif
-#ifdef CONFIG_VIDEO_VP27SMPX_MODULE
-       hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
-#endif
-#ifdef CONFIG_VIDEO_WM8775_MODULE
-       hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
-#endif
-#ifdef CONFIG_VIDEO_WM8739_MODULE
-       hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
-#endif
-#ifdef CONFIG_VIDEO_CS53L32A_MODULE
-       hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
-#endif
-#ifdef CONFIG_VIDEO_M52790_MODULE
-       hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
-#endif
-#endif
-
        /* check which i2c devices are actually found */
        for (i = 0; i < 32; i++) {
                u32 device = 1 << i;
@@ -927,11 +857,21 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
                        itv->hw_flags |= device;
                        continue;
                }
-               ivtv_i2c_register(itv, i);
-               if (ivtv_i2c_hw_addr(itv, device) > 0)
+               if (ivtv_i2c_register(itv, i) == 0)
                        itv->hw_flags |= device;
        }
 
+       if (itv->card->hw_all & IVTV_HW_CX25840)
+               itv->sd_video = ivtv_find_hw(itv, IVTV_HW_CX25840);
+       else if (itv->card->hw_all & IVTV_HW_SAA717X)
+               itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA717X);
+       else if (itv->card->hw_all & IVTV_HW_SAA7114)
+               itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7114);
+       else
+               itv->sd_video = ivtv_find_hw(itv, IVTV_HW_SAA7115);
+       itv->sd_audio = ivtv_find_hw(itv, itv->card->hw_audio_ctrl);
+       itv->sd_muxer = ivtv_find_hw(itv, itv->card->hw_muxer);
+
        hw = itv->hw_flags;
 
        if (itv->card->type == IVTV_CARD_CX23416GYC) {
@@ -949,7 +889,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
                /* The crystal frequency of GVMVPRX is 24.576MHz */
                crystal_freq.freq = SAA7115_FREQ_24_576_MHZ;
                crystal_freq.flags = SAA7115_FREQ_FL_UCGC;
-               itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+               v4l2_subdev_call(itv->sd_video, video, s_crystal_freq, &crystal_freq);
        }
 
        if (hw & IVTV_HW_CX25840) {
@@ -967,7 +907,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
                /* determine the exact saa711x model */
                itv->hw_flags &= ~IVTV_HW_SAA711X;
 
-               ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v);
+               ivtv_call_hw(itv, IVTV_HW_SAA711X, core, g_chip_ident, &v);
                if (v.ident == V4L2_IDENT_SAA7114) {
                        itv->hw_flags |= IVTV_HW_SAA7114;
                        /* VBI is not yet supported by the saa7114 driver. */
@@ -1001,28 +941,20 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        int vbi_buf_size;
        struct ivtv *itv;
 
-       spin_lock(&ivtv_cards_lock);
-
-       /* Make sure we've got a place for this card */
-       if (ivtv_cards_active == IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d)\n",
-                             ivtv_cards_active);
-               spin_unlock(&ivtv_cards_lock);
-               return -ENOMEM;
-       }
-
        itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
-       if (itv == NULL) {
-               spin_unlock(&ivtv_cards_lock);
+       if (itv == NULL)
                return -ENOMEM;
-       }
-       ivtv_cards[ivtv_cards_active] = itv;
        itv->dev = dev;
-       itv->num = ivtv_cards_active++;
-       snprintf(itv->name, sizeof(itv->name), "ivtv%d", itv->num);
-       IVTV_INFO("Initializing card #%d\n", itv->num);
+       itv->instance = atomic_inc_return(&ivtv_instance) - 1;
 
-       spin_unlock(&ivtv_cards_lock);
+       retval = v4l2_device_register(&dev->dev, &itv->device);
+       if (retval)
+               return retval;
+       /* "ivtv + PCI ID" is a bit of a mouthful, so use
+          "ivtv + instance" instead. */
+       snprintf(itv->device.name, sizeof(itv->device.name),
+                       "ivtv%d", itv->instance);
+       IVTV_INFO("Initializing card %d\n", itv->instance);
 
        ivtv_process_options(itv);
        if (itv->options.cardtype == -1) {
@@ -1043,8 +975,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                else if (retval == -ENXIO)
                        goto free_mem;
        }
-       /* save itv in the pci struct for later use */
-       pci_set_drvdata(dev, itv);
 
        /* map io memory */
        IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -1086,7 +1016,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                goto free_io;
        }
 
-       ivtv_gpio_init(itv);
+       retval = ivtv_gpio_init(itv);
+       if (retval)
+               goto free_io;
 
        /* active i2c  */
        IVTV_DEBUG_INFO("activating i2c...\n");
@@ -1095,8 +1027,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                goto free_io;
        }
 
-       IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
-
        if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
                /* Based on the model number the cardtype may be changed.
                   The PCI IDs are not always reliable. */
@@ -1191,7 +1121,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
                setup.tuner_callback = (setup.type == TUNER_XC2028) ?
                        ivtv_reset_tuner_gpio : NULL;
-               ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
+               ivtv_call_all(itv, tuner, s_type_addr, &setup);
                if (setup.type == TUNER_XC2028) {
                        static struct xc2028_ctrl ctrl = {
                                .fname = XC2028_DEFAULT_FIRMWARE,
@@ -1201,7 +1131,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                                .tuner = itv->options.tuner,
                                .priv = &ctrl,
                        };
-                       ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
+                       ivtv_call_all(itv, tuner, s_config, &cfg);
                }
        }
 
@@ -1210,11 +1140,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        itv->tuner_std = itv->std;
 
        if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
-               ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+               ivtv_call_all(itv, video, s_std_output, itv->std);
                /* Turn off the output signal. The mpeg decoder is not yet
                   active so without this you would get a green image until the
                   mpeg decoder becomes active. */
-               ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
        }
 
        /* clear interrupt mask, effectively disabling interrupts */
@@ -1222,7 +1152,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 
        /* Register IRQ */
        retval = request_irq(itv->dev->irq, ivtv_irq_handler,
-                            IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
+            IRQF_SHARED | IRQF_DISABLED, itv->device.name, (void *)itv);
        if (retval) {
                IVTV_ERR("Failed to register irq %d\n", retval);
                goto free_i2c;
@@ -1238,7 +1168,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                IVTV_ERR("Error %d registering devices\n", retval);
                goto free_streams;
        }
-       IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
+       IVTV_INFO("Initialized card: %s\n", itv->card_name);
        return 0;
 
 free_streams:
@@ -1261,10 +1191,8 @@ err:
                retval = -ENODEV;
        IVTV_ERR("Error %d on initialization\n", retval);
 
-       spin_lock(&ivtv_cards_lock);
-       kfree(ivtv_cards[ivtv_cards_active]);
-       ivtv_cards[ivtv_cards_active] = NULL;
-       spin_unlock(&ivtv_cards_lock);
+       v4l2_device_unregister(&itv->device);
+       kfree(itv);
        return retval;
 }
 
@@ -1304,10 +1232,11 @@ int ivtv_init_on_first_open(struct ivtv *itv)
        if (itv->card->hw_all & IVTV_HW_CX25840) {
                struct v4l2_control ctrl;
 
+               v4l2_subdev_call(itv->sd_video, core, init, 0);
                /* CX25840_CID_ENABLE_PVR150_WORKAROUND */
                ctrl.id = V4L2_CID_PRIVATE_BASE;
                ctrl.value = itv->pvr150_workaround;
-               itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+               v4l2_subdev_call(itv->sd_video, core, s_ctrl, &ctrl);
        }
 
        vf.tuner = 0;
@@ -1337,7 +1266,7 @@ int ivtv_init_on_first_open(struct ivtv *itv)
                /* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes
                   the mpeg decoder so now the saa7127 receives a proper
                   signal. */
-               ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
                ivtv_init_mpeg_decoder(itv);
        }
        ivtv_s_std(NULL, &fh, &itv->tuner_std);
@@ -1362,9 +1291,11 @@ int ivtv_init_on_first_open(struct ivtv *itv)
 
 static void ivtv_remove(struct pci_dev *pci_dev)
 {
-       struct ivtv *itv = pci_get_drvdata(pci_dev);
+       struct v4l2_device *dev = dev_get_drvdata(&pci_dev->dev);
+       struct ivtv *itv = to_ivtv(dev);
+       int i;
 
-       IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
+       IVTV_DEBUG_INFO("Removing card\n");
 
        if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
                /* Stop all captures */
@@ -1377,7 +1308,7 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 
                /* Turn off the TV-out */
                if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
-                       ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+                       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
                if (atomic_read(&itv->decoding) > 0) {
                        int type;
 
@@ -1402,6 +1333,8 @@ static void ivtv_remove(struct pci_dev *pci_dev)
        ivtv_streams_cleanup(itv, 1);
        ivtv_udma_free(itv);
 
+       v4l2_device_unregister(&itv->device);
+
        exit_ivtv_i2c(itv);
 
        free_irq(itv->dev->irq, (void *)itv);
@@ -1413,8 +1346,11 @@ static void ivtv_remove(struct pci_dev *pci_dev)
                release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
 
        pci_disable_device(itv->dev);
+       for (i = 0; i < IVTV_VBI_FRAMES; i++)
+               kfree(itv->vbi.sliced_mpeg_data[i]);
 
-       IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num);
+       printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);
+       kfree(itv);
 }
 
 /* define a pci_driver for card detection */
@@ -1427,54 +1363,36 @@ static struct pci_driver ivtv_pci_driver = {
 
 static int module_start(void)
 {
-       printk(KERN_INFO "ivtv:  Start initialization, version %s\n", IVTV_VERSION);
-
-       memset(ivtv_cards, 0, sizeof(ivtv_cards));
+       printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
 
        /* Validate parameters */
        if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv:  Exiting, ivtv_first_minor must be between 0 and %d\n",
+               printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
                     IVTV_MAX_CARDS - 1);
                return -1;
        }
 
        if (ivtv_debug < 0 || ivtv_debug > 2047) {
                ivtv_debug = 0;
-               printk(KERN_INFO "ivtv:  Debug value must be >= 0 and <= 2047\n");
+               printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
        }
 
        if (pci_register_driver(&ivtv_pci_driver)) {
-               printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
+               printk(KERN_ERR "ivtv: Error detecting PCI card\n");
                return -ENODEV;
        }
-       printk(KERN_INFO "ivtv:  End initialization\n");
+       printk(KERN_INFO "ivtv: End initialization\n");
        return 0;
 }
 
 static void module_cleanup(void)
 {
-       int i, j;
-
        pci_unregister_driver(&ivtv_pci_driver);
-
-       spin_lock(&ivtv_cards_lock);
-       for (i = 0; i < ivtv_cards_active; i++) {
-               if (ivtv_cards[i] == NULL)
-                       continue;
-               for (j = 0; j < IVTV_VBI_FRAMES; j++) {
-                       kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]);
-               }
-               kfree(ivtv_cards[i]);
-       }
-       spin_unlock(&ivtv_cards_lock);
 }
 
 /* Note: These symbols are exported because they are used by the ivtvfb
    framebuffer module and an infrared module for the IR-blaster. */
 EXPORT_SYMBOL(ivtv_set_irq_mask);
-EXPORT_SYMBOL(ivtv_cards_active);
-EXPORT_SYMBOL(ivtv_cards);
-EXPORT_SYMBOL(ivtv_cards_lock);
 EXPORT_SYMBOL(ivtv_api);
 EXPORT_SYMBOL(ivtv_vapi);
 EXPORT_SYMBOL(ivtv_vapi_result);
index 3733b2afec5f5f92b6c30f4f1c32cbce2cfd327a..ce8d9b74357ef2e6ad42cd5c6261103ed8c82d1b 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/dvb/audio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <media/tuner.h>
 #include <media/cx2341x.h>
 
 #define IVTV_REG_VPU                   (0x9058)
 #define IVTV_REG_APU                   (0xA064)
 
-/* i2c stuff */
-#define I2C_CLIENTS_MAX 16
-
 /* debugging */
 extern int ivtv_debug;
 
@@ -132,12 +130,10 @@ extern int ivtv_debug;
 /* Flag to turn on high volume debugging */
 #define IVTV_DBGFLG_HIGHVOL (1 << 10)
 
-/* NOTE: extra space before comma in 'itv->num , ## args' is required for
-   gcc-2.95, otherwise it won't compile. */
 #define IVTV_DEBUG(x, type, fmt, args...) \
        do { \
                if ((x) & ivtv_debug) \
-                       printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+                       v4l2_info(&itv->device, " " type ": " fmt , ##args);    \
        } while (0)
 #define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
 #define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
@@ -152,8 +148,8 @@ extern int ivtv_debug;
 
 #define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
        do { \
-               if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
-                       printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+               if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL))   \
+                       v4l2_info(&itv->device, " " type ": " fmt , ##args);    \
        } while (0)
 #define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
 #define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
@@ -167,9 +163,9 @@ extern int ivtv_debug;
 #define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
 
 /* Standard kernel messages */
-#define IVTV_ERR(fmt, args...)      printk(KERN_ERR  "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_WARN(fmt, args...)     printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_INFO(fmt, args...)     printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
+#define IVTV_ERR(fmt, args...)      v4l2_err(&itv->device, fmt , ## args)
+#define IVTV_WARN(fmt, args...)     v4l2_warn(&itv->device, fmt , ## args)
+#define IVTV_INFO(fmt, args...)     v4l2_info(&itv->device, fmt , ## args)
 
 /* output modes (cx23415 only) */
 #define OUT_NONE        0
@@ -596,8 +592,6 @@ struct ivtv_card;
 /* Struct to hold info about ivtv cards */
 struct ivtv {
        /* General fixed card data */
-       int num;                        /* board number, -1 during init! */
-       char name[8];                   /* board name for printk and interrupts (e.g. 'ivtv0') */
        struct pci_dev *dev;            /* PCI device */
        const struct ivtv_card *card;   /* card information */
        const char *card_name;          /* full name of the card */
@@ -609,14 +603,18 @@ struct ivtv {
        u32 v4l2_cap;                   /* V4L2 capabilities of card */
        u32 hw_flags;                   /* hardware description of the board */
        v4l2_std_id tuner_std;          /* the norm of the card's tuner (fixed) */
-                                       /* controlling video decoder function */
-       int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+       struct v4l2_subdev *sd_video;   /* controlling video decoder subdev */
+       struct v4l2_subdev *sd_audio;   /* controlling audio subdev */
+       struct v4l2_subdev *sd_muxer;   /* controlling audio muxer subdev */
        u32 base_addr;                  /* PCI resource base address */
        volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
        volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
        volatile void __iomem *reg_mem; /* pointer to mapped registers */
        struct ivtv_options options;    /* user options */
 
+       struct v4l2_device device;
+       struct v4l2_subdev sd_gpio;     /* GPIO sub-device */
+       u16 instance;
 
        /* High-level state info */
        unsigned long i_flags;          /* global ivtv flags */
@@ -676,7 +674,6 @@ struct ivtv {
        struct i2c_adapter i2c_adap;
        struct i2c_algo_bit_data i2c_algo;
        struct i2c_client i2c_client;
-       struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */
        int i2c_state;                  /* i2c bit state */
        struct mutex i2c_bus_lock;      /* lock i2c bus */
 
@@ -722,11 +719,13 @@ struct ivtv {
        struct osd_info *osd_info;      /* ivtvfb private OSD info */
 };
 
+static inline struct ivtv *to_ivtv(struct v4l2_device *dev)
+{
+       return container_of(dev, struct ivtv, device);
+}
+
 /* Globals */
-extern struct ivtv *ivtv_cards[];
-extern int ivtv_cards_active;
 extern int ivtv_first_minor;
-extern spinlock_t ivtv_cards_lock;
 
 /*==============Prototypes==================*/
 
@@ -786,4 +785,19 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
 #define write_dec_sync(val, addr) \
        do { write_dec(val, addr); read_dec(addr); } while (0)
 
+/* Call the specified callback for all subdevs matching hw (if 0, then
+   match them all). Ignore any errors. */
+#define ivtv_call_hw(itv, hw, o, f, args...)                           \
+       __v4l2_device_call_subdevs(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
+
+/* Call the specified callback for all subdevs matching hw (if 0, then
+   match them all). If the callback returns an error other than 0 or
+   -ENOIOCTLCMD, then return with that error code. */
+#define ivtv_call_hw_err(itv, hw, o, f, args...)               \
+       __v4l2_device_call_subdevs_until_err(&(itv)->device, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+
+#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
+
 #endif
index 1c404e454a36f6c601550fd261e2cc65e42805ec..5eb587592e9dbdfc27a6c2d0e18c0a4e082f85b1 100644 (file)
@@ -155,7 +155,7 @@ static void ivtv_dualwatch(struct ivtv *itv)
 
        new_stereo_mode = itv->params.audio_properties & stereo_mask;
        memset(&vt, 0, sizeof(vt));
-       ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt);
+       ivtv_call_all(itv, tuner, g_tuner, &vt);
        if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
                new_stereo_mode = dual;
 
@@ -857,7 +857,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
                /* Mark that the radio is no longer in use */
                clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
                /* Switch tuner to TV */
-               ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+               ivtv_call_all(itv, tuner, s_std, itv->std);
                /* Select correct audio input (i.e. TV tuner or Line in) */
                ivtv_audio_set_io(itv);
                if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -865,7 +865,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
                        struct v4l2_crystal_freq crystal_freq;
                        crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
                        crystal_freq.flags = 0;
-                       ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+                       ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, &crystal_freq);
                }
                if (atomic_read(&itv->capturing) > 0) {
                        /* Undo video mute */
@@ -952,15 +952,14 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
                /* We have the radio */
                ivtv_mute(itv);
                /* Switch tuner to radio */
-               ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
+               ivtv_call_all(itv, tuner, s_radio);
                /* Select the correct audio input (i.e. radio tuner) */
                ivtv_audio_set_io(itv);
-               if (itv->hw_flags & IVTV_HW_SAA711X)
-               {
+               if (itv->hw_flags & IVTV_HW_SAA711X) {
                        struct v4l2_crystal_freq crystal_freq;
                        crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
                        crystal_freq.flags = SAA7115_FREQ_FL_APLL;
-                       ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+                       ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, &crystal_freq);
                }
                /* Done! Unmute and continue. */
                ivtv_unmute(itv);
@@ -981,37 +980,18 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 
 int ivtv_v4l2_open(struct inode *inode, struct file *filp)
 {
-       int res, x, y = 0;
+       int res;
        struct ivtv *itv = NULL;
        struct ivtv_stream *s = NULL;
-       int minor = iminor(inode);
-
-       /* Find which card this open was on */
-       spin_lock(&ivtv_cards_lock);
-       for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
-               if (ivtv_cards[x] == NULL)
-                       continue;
-               /* find out which stream this open was on */
-               for (y = 0; y < IVTV_MAX_STREAMS; y++) {
-                       s = &ivtv_cards[x]->streams[y];
-                       if (s->v4l2dev && s->v4l2dev->minor == minor) {
-                               itv = ivtv_cards[x];
-                               break;
-                       }
-               }
-       }
-       spin_unlock(&ivtv_cards_lock);
+       struct video_device *vdev = video_devdata(filp);
 
-       if (itv == NULL) {
-               /* Couldn't find a device registered
-                  on that minor, shouldn't happen! */
-               printk(KERN_WARNING "No ivtv device found on minor %d\n", minor);
-               return -ENXIO;
-       }
+       s = video_get_drvdata(vdev);
+       itv = s->itv;
 
        mutex_lock(&itv->serialize_lock);
        if (ivtv_init_on_first_open(itv)) {
-               IVTV_ERR("Failed to initialize on minor %d\n", minor);
+               IVTV_ERR("Failed to initialize on minor %d\n",
+                               s->v4l2dev->minor);
                mutex_unlock(&itv->serialize_lock);
                return -ENXIO;
        }
index 74a44844ccaf346a1a46c05941178f728b261fbf..dc2850e87a7e1b1106b8da0a8eac50b9363c0ce6 100644 (file)
@@ -144,22 +144,9 @@ int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value)
        return 0;
 }
 
-void ivtv_gpio_init(struct ivtv *itv)
+static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd)
 {
-       u16 pin = 0;
-
-       if (itv->card->xceive_pin)
-               pin = 1 << itv->card->xceive_pin;
-
-       if ((itv->card->gpio_init.direction | pin) == 0)
-               return;
-
-       IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
-                  read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
-
-       /* init output data then direction */
-       write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
-       write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+       return container_of(sd, struct ivtv, sd_gpio);
 }
 
 static struct v4l2_queryctrl gpio_ctrl_mute = {
@@ -173,134 +160,231 @@ static struct v4l2_queryctrl gpio_ctrl_mute = {
        .flags         = 0,
 };
 
-int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg)
+static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 {
-       struct v4l2_tuner *tuner = arg;
-       struct v4l2_control *ctrl = arg;
-       struct v4l2_routing *route = arg;
+       struct ivtv *itv = sd_to_ivtv(sd);
        u16 mask, data;
 
-       switch (command) {
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               mask = itv->card->gpio_audio_freq.mask;
-               switch (*(u32 *)arg) {
-               case 32000:
-                       data = itv->card->gpio_audio_freq.f32000;
-                       break;
-               case 44100:
-                       data = itv->card->gpio_audio_freq.f44100;
-                       break;
-               case 48000:
-               default:
-                       data = itv->card->gpio_audio_freq.f48000;
-                       break;
-               }
+       mask = itv->card->gpio_audio_freq.mask;
+       switch (freq) {
+       case 32000:
+               data = itv->card->gpio_audio_freq.f32000;
+               break;
+       case 44100:
+               data = itv->card->gpio_audio_freq.f44100;
+               break;
+       case 48000:
+       default:
+               data = itv->card->gpio_audio_freq.f48000;
                break;
+       }
+       if (mask)
+               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+       return 0;
+}
 
-       case VIDIOC_G_TUNER:
-               mask = itv->card->gpio_audio_detect.mask;
-               if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
-                       tuner->rxsubchans = V4L2_TUNER_MODE_STEREO |
-                              V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-               else
-                       tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
-               return 0;
+static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask;
+
+       mask = itv->card->gpio_audio_detect.mask;
+       if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask))
+               vt->rxsubchans = V4L2_TUNER_MODE_STEREO |
+                       V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+       else
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       return 0;
+}
 
-       case VIDIOC_S_TUNER:
-               mask = itv->card->gpio_audio_mode.mask;
-               switch (tuner->audmode) {
-               case V4L2_TUNER_MODE_LANG1:
-                       data = itv->card->gpio_audio_mode.lang1;
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       data = itv->card->gpio_audio_mode.lang2;
-                       break;
-               case V4L2_TUNER_MODE_MONO:
-                       data = itv->card->gpio_audio_mode.mono;
-                       break;
-               case V4L2_TUNER_MODE_STEREO:
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-               default:
-                       data = itv->card->gpio_audio_mode.stereo;
-                       break;
-               }
-               break;
+static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
 
-       case AUDC_SET_RADIO:
-               mask = itv->card->gpio_audio_input.mask;
-               data = itv->card->gpio_audio_input.radio;
+       mask = itv->card->gpio_audio_mode.mask;
+       switch (vt->audmode) {
+       case V4L2_TUNER_MODE_LANG1:
+               data = itv->card->gpio_audio_mode.lang1;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               data = itv->card->gpio_audio_mode.lang2;
+               break;
+       case V4L2_TUNER_MODE_MONO:
+               data = itv->card->gpio_audio_mode.mono;
                break;
+       case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+       default:
+               data = itv->card->gpio_audio_mode.stereo;
+               break;
+       }
+       if (mask)
+               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+       return 0;
+}
+
+static int subdev_s_radio(struct v4l2_subdev *sd)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
+
+       mask = itv->card->gpio_audio_input.mask;
+       data = itv->card->gpio_audio_input.radio;
+       if (mask)
+               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+       return 0;
+}
 
-       case VIDIOC_S_STD:
-               mask = itv->card->gpio_audio_input.mask;
+static int subdev_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
+
+       mask = itv->card->gpio_audio_input.mask;
+       data = itv->card->gpio_audio_input.tuner;
+       if (mask)
+               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+       return 0;
+}
+
+static int subdev_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
+
+       if (route->input > 2)
+               return -EINVAL;
+       mask = itv->card->gpio_audio_input.mask;
+       switch (route->input) {
+       case 0:
                data = itv->card->gpio_audio_input.tuner;
                break;
-
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               if (route->input > 2)
-                       return -EINVAL;
-               mask = itv->card->gpio_audio_input.mask;
-               switch (route->input) {
-                       case 0:
-                               data = itv->card->gpio_audio_input.tuner;
-                               break;
-                       case 1:
-                               data = itv->card->gpio_audio_input.linein;
-                               break;
-                       case 2:
-                       default:
-                               data = itv->card->gpio_audio_input.radio;
-                               break;
-               }
+       case 1:
+               data = itv->card->gpio_audio_input.linein;
+               break;
+       case 2:
+       default:
+               data = itv->card->gpio_audio_input.radio;
                break;
+       }
+       if (mask)
+               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               mask = itv->card->gpio_audio_mute.mask;
-               data = itv->card->gpio_audio_mute.mute;
-               ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
-               return 0;
+static int subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
 
-       case VIDIOC_S_CTRL:
-               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               mask = itv->card->gpio_audio_mute.mask;
-               data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
-               break;
+       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       mask = itv->card->gpio_audio_mute.mask;
+       data = itv->card->gpio_audio_mute.mute;
+       ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data;
+       return 0;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
+static int subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
 
-               if (qc->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               *qc = gpio_ctrl_mute;
-               return 0;
-       }
+       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       mask = itv->card->gpio_audio_mute.mask;
+       data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0;
+       if (mask)
+               write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
+       return 0;
+}
+
+static int subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       if (qc->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       *qc = gpio_ctrl_mute;
+       return 0;
+}
+
+static int subdev_log_status(struct v4l2_subdev *sd)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
 
-       case VIDIOC_LOG_STATUS:
-               IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
+       IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n",
                        read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT),
                        read_reg(IVTV_REG_GPIO_IN));
-               return 0;
+       return 0;
+}
 
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-               if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
-                       return -EINVAL;
-               mask = itv->card->gpio_video_input.mask;
-               if  (route->input == 0)
-                       data = itv->card->gpio_video_input.tuner;
-               else if  (route->input == 1)
-                       data = itv->card->gpio_video_input.composite;
-               else
-                       data = itv->card->gpio_video_input.svideo;
-               break;
+static int subdev_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct ivtv *itv = sd_to_ivtv(sd);
+       u16 mask, data;
 
-       default:
+       if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */
                return -EINVAL;
-       }
+       mask = itv->card->gpio_video_input.mask;
+       if  (route->input == 0)
+               data = itv->card->gpio_video_input.tuner;
+       else if  (route->input == 1)
+               data = itv->card->gpio_video_input.composite;
+       else
+               data = itv->card->gpio_video_input.svideo;
        if (mask)
                write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT);
        return 0;
 }
+
+static const struct v4l2_subdev_core_ops subdev_core_ops = {
+       .log_status = subdev_log_status,
+       .g_ctrl = subdev_g_ctrl,
+       .s_ctrl = subdev_s_ctrl,
+       .queryctrl = subdev_queryctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
+       .s_std = subdev_s_std,
+       .s_radio = subdev_s_radio,
+       .g_tuner = subdev_g_tuner,
+       .s_tuner = subdev_s_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops subdev_audio_ops = {
+       .s_clock_freq = subdev_s_clock_freq,
+       .s_routing = subdev_s_audio_routing,
+};
+
+static const struct v4l2_subdev_video_ops subdev_video_ops = {
+       .s_routing = subdev_s_video_routing,
+};
+
+static const struct v4l2_subdev_ops subdev_ops = {
+       .core = &subdev_core_ops,
+       .tuner = &subdev_tuner_ops,
+       .audio = &subdev_audio_ops,
+       .video = &subdev_video_ops,
+};
+
+int ivtv_gpio_init(struct ivtv *itv)
+{
+       u16 pin = 0;
+
+       if (itv->card->xceive_pin)
+               pin = 1 << itv->card->xceive_pin;
+
+       if ((itv->card->gpio_init.direction | pin) == 0)
+               return 0;
+
+       IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
+                  read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT));
+
+       /* init output data then direction */
+       write_reg(itv->card->gpio_init.initial_value | pin, IVTV_REG_GPIO_OUT);
+       write_reg(itv->card->gpio_init.direction | pin, IVTV_REG_GPIO_DIR);
+       v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
+       snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->device.name);
+       itv->sd_gpio.grp_id = IVTV_HW_GPIO;
+       return v4l2_device_register_subdev(&itv->device, &itv->sd_gpio);
+}
index 48b6291613a23397065bae0699f3809aef1093e4..0b5d19c8ecb42f364f27859b2b60b91b1866ad5e 100644 (file)
@@ -22,9 +22,8 @@
 #define IVTV_GPIO_H
 
 /* GPIO stuff */
-void ivtv_gpio_init(struct ivtv *itv);
+int ivtv_gpio_init(struct ivtv *itv);
 void ivtv_reset_ir_gpio(struct ivtv *itv);
 int ivtv_reset_tuner_gpio(void *dev, int component, int cmd, int value);
-int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
 
 #endif
index 41dbbe9621a1fa34d95379444e60a0f5b01df9c1..ca1d9557945eef807310b8dbaad09bab69d9a674 100644 (file)
 #define IVTV_VP27SMPX_I2C_ADDR         0x5b
 #define IVTV_M52790_I2C_ADDR           0x48
 
-/* This array should match the IVTV_HW_ defines */
-static const u8 hw_driverids[] = {
-       I2C_DRIVERID_CX25840,
-       I2C_DRIVERID_SAA711X,
-       I2C_DRIVERID_SAA7127,
-       I2C_DRIVERID_MSP3400,
-       I2C_DRIVERID_TUNER,
-       I2C_DRIVERID_WM8775,
-       I2C_DRIVERID_CS53L32A,
-       I2C_DRIVERID_TVEEPROM,
-       I2C_DRIVERID_SAA711X,
-       I2C_DRIVERID_UPD64031A,
-       I2C_DRIVERID_UPD64083,
-       I2C_DRIVERID_SAA717X,
-       I2C_DRIVERID_WM8739,
-       I2C_DRIVERID_VP27SMPX,
-       I2C_DRIVERID_M52790,
-       0               /* IVTV_HW_GPIO dummy driver ID */
-};
-
 /* This array should match the IVTV_HW_ defines */
 static const u8 hw_addrs[] = {
        IVTV_CX25840_I2C_ADDR,
@@ -129,6 +109,26 @@ static const u8 hw_addrs[] = {
        0               /* IVTV_HW_GPIO dummy driver ID */
 };
 
+/* This array should match the IVTV_HW_ defines */
+static const char *hw_modules[] = {
+       "cx25840",
+       "saa7115",
+       "saa7127",
+       "msp3400",
+       "tuner",
+       "wm8775",
+       "cs53l32a",
+       NULL,
+       "saa7115",
+       "upd64031a",
+       "upd64083",
+       "saa717x",
+       "wm8739",
+       "vp27smpx",
+       "m52790",
+       NULL
+};
+
 /* This array should match the IVTV_HW_ defines */
 static const char * const hw_devicenames[] = {
        "cx25840",
@@ -151,80 +151,58 @@ static const char * const hw_devicenames[] = {
 
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
-       struct i2c_board_info info;
-       struct i2c_client *c;
-       u8 id;
-       int i;
+       struct v4l2_subdev *sd;
+       struct i2c_adapter *adap = &itv->i2c_adap;
+       const char *mod = hw_modules[idx];
+       const char *type = hw_devicenames[idx];
+       u32 hw = 1 << idx;
 
-       IVTV_DEBUG_I2C("i2c client register\n");
-       if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+       if (idx >= ARRAY_SIZE(hw_addrs))
                return -1;
-       id = hw_driverids[idx];
-       memset(&info, 0, sizeof(info));
-       strlcpy(info.type, hw_devicenames[idx], sizeof(info.type));
-       info.addr = hw_addrs[idx];
-       for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
-
-       if (i == I2C_CLIENTS_MAX) {
-               IVTV_ERR("insufficient room for new I2C client!\n");
-               return -ENOMEM;
+       if (hw == IVTV_HW_TUNER) {
+               /* special tuner handling */
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+                               itv->card_i2c->radio);
+               if (sd)
+                       sd->grp_id = 1 << idx;
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+                               itv->card_i2c->demod);
+               if (sd)
+                       sd->grp_id = 1 << idx;
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type,
+                               itv->card_i2c->tv);
+               if (sd)
+                       sd->grp_id = 1 << idx;
+               return sd ? 0 : -1;
        }
+       if (!hw_addrs[idx])
+               return -1;
+       if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
+               unsigned short addrs[2] = { hw_addrs[idx], I2C_CLIENT_END };
 
-       if (id != I2C_DRIVERID_TUNER) {
-               if (id == I2C_DRIVERID_UPD64031A ||
-                   id == I2C_DRIVERID_UPD64083) {
-                       unsigned short addrs[2] = { info.addr, I2C_CLIENT_END };
-
-                       c = i2c_new_probed_device(&itv->i2c_adap, &info, addrs);
-               } else
-                       c = i2c_new_device(&itv->i2c_adap, &info);
-               if (c && c->driver == NULL)
-                       i2c_unregister_device(c);
-               else if (c)
-                       itv->i2c_clients[i] = c;
-               return itv->i2c_clients[i] ? 0 : -ENODEV;
+               sd = v4l2_i2c_new_probed_subdev(adap, mod, type, addrs);
+       } else {
+               sd = v4l2_i2c_new_subdev(adap, mod, type, hw_addrs[idx]);
        }
-
-       /* special tuner handling */
-       c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
-       if (c && c->driver == NULL)
-               i2c_unregister_device(c);
-       else if (c)
-               itv->i2c_clients[i++] = c;
-       c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
-       if (c && c->driver == NULL)
-               i2c_unregister_device(c);
-       else if (c)
-               itv->i2c_clients[i++] = c;
-       c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
-       if (c && c->driver == NULL)
-               i2c_unregister_device(c);
-       else if (c)
-               itv->i2c_clients[i++] = c;
-       return 0;
-}
-
-static int attach_inform(struct i2c_client *client)
-{
-       return 0;
+       if (sd)
+               sd->grp_id = 1 << idx;
+       return sd ? 0 : -1;
 }
 
-static int detach_inform(struct i2c_client *client)
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw)
 {
-       int i;
-       struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+       struct v4l2_subdev *result = NULL;
+       struct v4l2_subdev *sd;
 
-       IVTV_DEBUG_I2C("i2c client detach\n");
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               if (itv->i2c_clients[i] == client) {
-                       itv->i2c_clients[i] = NULL;
+       spin_lock(&itv->device.lock);
+       v4l2_device_for_each_subdev(sd, &itv->device) {
+               if (sd->grp_id == hw) {
+                       result = sd;
                        break;
                }
        }
-       IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n",
-                  client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
-
-       return 0;
+       spin_unlock(&itv->device.lock);
+       return result;
 }
 
 /* Set the serial clock line to the desired state */
@@ -494,7 +472,8 @@ static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data,
    intervening stop condition */
 static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 {
-       struct ivtv *itv = i2c_get_adapdata(i2c_adap);
+       struct v4l2_device *drv = i2c_get_adapdata(i2c_adap);
+       struct ivtv *itv = to_ivtv(drv);
        int retval;
        int i;
 
@@ -530,8 +509,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
        .id = I2C_HW_B_CX2341X,
        .algo = &ivtv_algo,
        .algo_data = NULL,                      /* filled from template */
-       .client_register = attach_inform,
-       .client_unregister = detach_inform,
        .owner = THIS_MODULE,
 };
 
@@ -583,8 +560,6 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
        .id = I2C_HW_B_CX2341X,
        .algo = NULL,                   /* set by i2c-algo-bit */
        .algo_data = NULL,              /* filled from template */
-       .client_register = attach_inform,
-       .client_unregister = detach_inform,
        .owner = THIS_MODULE,
 };
 
@@ -601,160 +576,6 @@ static struct i2c_client ivtv_i2c_client_template = {
        .name = "ivtv internal",
 };
 
-int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg)
-{
-       struct i2c_client *client;
-       int retval;
-       int i;
-
-       IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               client = itv->i2c_clients[i];
-               if (client == NULL || client->driver == NULL ||
-                   client->driver->command == NULL)
-                       continue;
-               if (addr == client->addr) {
-                       retval = client->driver->command(client, cmd, arg);
-                       return retval;
-               }
-       }
-       if (cmd != VIDIOC_G_CHIP_IDENT)
-               IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
-       return -ENODEV;
-}
-
-/* Find the i2c device based on the driver ID and return
-   its i2c address or -ENODEV if no matching device was found. */
-static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
-{
-       struct i2c_client *client;
-       int retval = -ENODEV;
-       int i;
-
-       for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-               client = itv->i2c_clients[i];
-               if (client == NULL || client->driver == NULL)
-                       continue;
-               if (id == client->driver->id) {
-                       retval = client->addr;
-                       break;
-               }
-       }
-       return retval;
-}
-
-/* Find the i2c device name matching the DRIVERID */
-static const char *ivtv_i2c_id_name(u32 id)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-               if (hw_driverids[i] == id)
-                       return hw_devicenames[i];
-       return "unknown device";
-}
-
-/* Find the i2c device name matching the IVTV_HW_ flag */
-static const char *ivtv_i2c_hw_name(u32 hw)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-               if (1 << i == hw)
-                       return hw_devicenames[i];
-       return "unknown device";
-}
-
-/* Find the i2c device matching the IVTV_HW_ flag and return
-   its i2c address or -ENODEV if no matching device was found. */
-int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
-               if (1 << i == hw)
-                       return ivtv_i2c_id_addr(itv, hw_driverids[i]);
-       return -ENODEV;
-}
-
-/* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing.
-   If hw == IVTV_HW_GPIO then call the gpio handler. */
-int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
-{
-       int addr;
-
-       if (hw == IVTV_HW_GPIO)
-               return ivtv_gpio(itv, cmd, arg);
-       if (hw == 0)
-               return 0;
-
-       addr = ivtv_i2c_hw_addr(itv, hw);
-       if (addr < 0) {
-               IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
-                              hw, ivtv_i2c_hw_name(hw), cmd);
-               return addr;
-       }
-       return ivtv_call_i2c_client(itv, addr, cmd, arg);
-}
-
-/* Calls i2c device based on I2C driver ID. */
-int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
-{
-       int addr;
-
-       addr = ivtv_i2c_id_addr(itv, id);
-       if (addr < 0) {
-               if (cmd != VIDIOC_G_CHIP_IDENT)
-                       IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
-                               id, ivtv_i2c_id_name(id), cmd);
-               return addr;
-       }
-       return ivtv_call_i2c_client(itv, addr, cmd, arg);
-}
-
-int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg);
-}
-EXPORT_SYMBOL(ivtv_saa7127);
-
-int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg);
-}
-
-int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg);
-}
-
-/* broadcast cmd for all I2C clients and for the gpio subsystem */
-void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
-{
-       if (itv->i2c_adap.algo == NULL) {
-               IVTV_ERR("Adapter is not set");
-               return;
-       }
-       i2c_clients_command(&itv->i2c_adap, cmd, arg);
-       if (itv->hw_flags & IVTV_HW_GPIO)
-               ivtv_gpio(itv, cmd, arg);
-}
-
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv)
 {
@@ -763,10 +584,9 @@ int init_ivtv_i2c(struct ivtv *itv)
        /* Sanity checks for the I2C hardware arrays. They must be the
         * same size and GPIO must be the last entry.
         */
-       if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
-           ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
-           IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
-           hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+       if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
+           ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules) ||
+           IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1))) {
                IVTV_ERR("Mismatched I2C hardware arrays\n");
                return -ENODEV;
        }
@@ -783,8 +603,8 @@ int init_ivtv_i2c(struct ivtv *itv)
        itv->i2c_adap.algo_data = &itv->i2c_algo;
 
        sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
-               itv->num);
-       i2c_set_adapdata(&itv->i2c_adap, itv);
+               itv->instance);
+       i2c_set_adapdata(&itv->i2c_adap, &itv->device);
 
        memcpy(&itv->i2c_client, &ivtv_i2c_client_template,
               sizeof(struct i2c_client));
index 022978cf533db15f0b7f81f7ac8b9c9a3aea041f..396928a06a54d1b4bd467b387df499a8a95149c5 100644 (file)
 #ifndef IVTV_I2C_H
 #define IVTV_I2C_H
 
-int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg);
-int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg);
-
-int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw);
-int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
-int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
-int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
-void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
+struct v4l2_subdev *ivtv_find_hw(struct ivtv *itv, u32 hw);
 
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv);
index 4bae38d21ef6099cd24cc21edfc3d7d3a4a56f44..cd990a4b81a9e338ba97219f824113cd6c833169 100644 (file)
@@ -393,7 +393,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
                return 0;
        }
 
-       itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
        vbifmt->service_set = ivtv_get_service_set(vbifmt);
        return 0;
 }
@@ -581,7 +581,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
        p->height = h;
        if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
                fmt->fmt.pix.width /= 2;
-       itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
        return ivtv_g_fmt_vid_cap(file, fh, fmt);
 }
 
@@ -593,7 +593,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f
                return -EBUSY;
        itv->vbi.sliced_in->service_set = 0;
        itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
-       itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
        return ivtv_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -611,7 +611,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
        if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
                return -EBUSY;
        itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
-       itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
        memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
        return 0;
 }
@@ -685,18 +685,17 @@ static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident
                        chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
                return 0;
        }
-       if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-               return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
-       if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
-               return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
-       return -EINVAL;
+       if (chip->match_type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+           chip->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+       /* TODO: is this correct? */
+       return ivtv_call_all_err(itv, core, g_chip_ident, chip);
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
 {
        struct v4l2_register *regs = arg;
-       unsigned long flags;
        volatile u8 __iomem *reg_start;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -711,12 +710,10 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
        else
                return -EINVAL;
 
-       spin_lock_irqsave(&ivtv_cards_lock, flags);
        if (cmd == VIDIOC_DBG_G_REGISTER)
                regs->val = readl(regs->reg + reg_start);
        else
                writel(regs->val, regs->reg + reg_start);
-       spin_unlock_irqrestore(&ivtv_cards_lock, flags);
        return 0;
 }
 
@@ -726,9 +723,10 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *re
 
        if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
                return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
-       if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-               return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
-       return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
+       /* TODO: subdev errors should not be ignored, this should become a
+          subdev helper function. */
+       ivtv_call_all(itv, core, g_register, reg);
+       return 0;
 }
 
 static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg)
@@ -737,9 +735,10 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *re
 
        if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
                return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
-       if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
-               return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
-       return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
+       /* TODO: subdev errors should not be ignored, this should become a
+          subdev helper function. */
+       ivtv_call_all(itv, core, s_register, reg);
+       return 0;
 }
 #endif
 
@@ -884,12 +883,6 @@ static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
 
        streamtype = id->type;
 
-       if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
-               printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
-               /* Should be replaced */
-               /* v4l_printk_ioctl(VIDIOC_S_CROP); */
-       }
-
        if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
            (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
                if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
@@ -1050,7 +1043,7 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
        itv->active_output = outp;
        route.input = SAA7127_INPUT_TYPE_NORMAL;
        route.output = itv->card->video_outputs[outp].video_output;
-       ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, &route);
 
        return 0;
 }
@@ -1062,7 +1055,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *
        if (vf->tuner != 0)
                return -EINVAL;
 
-       ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf);
+       ivtv_call_all(itv, tuner, g_frequency, vf);
        return 0;
 }
 
@@ -1075,7 +1068,7 @@ int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
 
        ivtv_mute(itv);
        IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
-       ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf);
+       ivtv_call_all(itv, tuner, s_frequency, vf);
        ivtv_unmute(itv);
        return 0;
 }
@@ -1123,14 +1116,14 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
        IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
 
        /* Tuner */
-       ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
+       ivtv_call_all(itv, tuner, s_std, itv->std);
 
        if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
                /* set display standard */
                itv->std_out = *std;
                itv->is_out_60hz = itv->is_60hz;
                itv->is_out_50hz = itv->is_50hz;
-               ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
+               ivtv_call_all(itv, video, s_std_output, itv->std_out);
                ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
                itv->main_rect.left = itv->main_rect.top = 0;
                itv->main_rect.width = 720;
@@ -1154,7 +1147,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
        if (vt->index != 0)
                return -EINVAL;
 
-       ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
+       ivtv_call_all(itv, tuner, s_tuner, vt);
 
        return 0;
 }
@@ -1166,7 +1159,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
        if (vt->index != 0)
                return -EINVAL;
 
-       ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
+       ivtv_call_all(itv, tuner, g_tuner, vt);
 
        if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
                strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
@@ -1444,14 +1437,15 @@ static int ivtv_log_status(struct file *file, void *fh)
        struct v4l2_audio audin;
        int i;
 
-       IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
+       IVTV_INFO("=================  START STATUS CARD #%d  =================\n",
+                      itv->instance);
        IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
        if (itv->hw_flags & IVTV_HW_TVEEPROM) {
                struct tveeprom tv;
 
                ivtv_read_eeprom(itv, &tv);
        }
-       ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
+       ivtv_call_all(itv, core, log_status);
        ivtv_get_input(itv, itv->active_input, &vidin);
        ivtv_get_audio_input(itv, itv->audio_input, &audin);
        IVTV_INFO("Video Input:  %s\n", vidin.name);
@@ -1518,7 +1512,7 @@ static int ivtv_log_status(struct file *file, void *fh)
        }
        IVTV_INFO("Tuner:  %s\n",
                test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
-       cx2341x_log_status(&itv->params, itv->name);
+       cx2341x_log_status(&itv->params, itv->device.name);
        IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
        for (i = 0; i < IVTV_MAX_STREAMS; i++) {
                struct ivtv_stream *s = &itv->streams[i];
@@ -1530,8 +1524,11 @@ static int ivtv_log_status(struct file *file, void *fh)
                                (s->buffers * s->buf_size) / 1024, s->buffers);
        }
 
-       IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
-       IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
+       IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n",
+                       (long long)itv->mpg_data_received,
+                       (long long)itv->vbi_data_inserted);
+       IVTV_INFO("==================  END STATUS CARD #%d  ==================\n",
+                       itv->instance);
 
        return 0;
 }
@@ -1736,7 +1733,7 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
        case VIDIOC_INT_S_AUDIO_ROUTING: {
                struct v4l2_routing *route = arg;
 
-               ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
+               ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, route);
                break;
        }
 
@@ -1746,7 +1743,7 @@ static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
                if ((val == 0 && itv->options.newi2c) || (val & 0x01))
                        ivtv_reset_ir_gpio(itv);
                if (val & 0x02)
-                       itv->video_dec_func(itv, cmd, NULL);
+                       v4l2_subdev_call(itv->sd_video, core, reset, 0);
                break;
        }
 
index 05564919b57f680c9afc227a95447beabe38ecc7..3fd302294497d430677109e121f68f70e1454aee 100644 (file)
@@ -47,13 +47,13 @@ void ivtv_audio_set_io(struct ivtv *itv)
        route.output = 0;
        if (itv->card->hw_muxer & IVTV_HW_M52790)
                route.output = M52790_OUT_STEREO;
-       ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       v4l2_subdev_call(itv->sd_muxer, audio, s_routing, &route);
 
        route.input = in->audio_input;
        route.output = 0;
        if (itv->card->hw_audio & IVTV_HW_MSP34XX)
                route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-       ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+       ivtv_call_hw(itv, itv->card->hw_audio, audio, s_routing, &route);
 }
 
 /* Selects the video input and output according to the current
@@ -66,7 +66,7 @@ void ivtv_video_set_io(struct ivtv *itv)
 
        route.input = itv->card->video_inputs[inp].video_input;
        route.output = 0;
-       itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+       v4l2_subdev_call(itv->sd_video, video, s_routing, &route);
 
        type = itv->card->video_inputs[inp].video_type;
 
@@ -79,7 +79,7 @@ void ivtv_video_set_io(struct ivtv *itv)
        }
 
        if (itv->card->hw_video & IVTV_HW_GPIO)
-               ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+               ivtv_call_hw(itv, IVTV_HW_GPIO, video, s_routing, &route);
 
        if (itv->card->hw_video & IVTV_HW_UPD64031A) {
                if (type == IVTV_CARD_INPUT_VID_TUNER ||
@@ -92,7 +92,7 @@ void ivtv_video_set_io(struct ivtv *itv)
                }
                route.input |= itv->card->gr_config;
 
-               ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+               ivtv_call_hw(itv, IVTV_HW_UPD64031A, video, s_routing, &route);
        }
 
        if (itv->card->hw_video & IVTV_HW_UPD6408X) {
@@ -110,6 +110,6 @@ void ivtv_video_set_io(struct ivtv *itv)
                    route.input |= UPD64083_EXT_Y_ADC;
                  }
                }
-               ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+               ivtv_call_hw(itv, IVTV_HW_UPD6408X, video, s_routing, &route);
        }
 }
index 9b7aa79eb2677d49ddd3da33c1f95fc2f6429283..f77d764707b2a1f81b7bef2953de5c920918e3d7 100644 (file)
@@ -172,7 +172,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
 {
        struct ivtv_stream *s = &itv->streams[type];
        int num_offset = ivtv_stream_info[type].num_offset;
-       int num = itv->num + ivtv_first_minor + num_offset;
+       int num = itv->instance + ivtv_first_minor + num_offset;
 
        /* These four fields are always initialized. If v4l2dev == NULL, then
           this stream is not in use. In that case no other fields but these
@@ -205,11 +205,11 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
                return -ENOMEM;
        }
 
-       snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
-                       itv->num, s->name);
+       snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "%s %s",
+                       itv->device.name, s->name);
 
        s->v4l2dev->num = num;
-       s->v4l2dev->parent = &itv->dev->dev;
+       s->v4l2dev->v4l2_dev = &itv->device;
        s->v4l2dev->fops = ivtv_stream_info[type].fops;
        s->v4l2dev->release = video_device_release;
        s->v4l2dev->tvnorms = V4L2_STD_ALL;
@@ -260,6 +260,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
                if (s_mpg->v4l2dev)
                        num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
        }
+       video_set_drvdata(s->v4l2dev, s);
 
        /* Register device. First try the desired minor, then any free one. */
        if (video_register_device(s->v4l2dev, vfl_type, num)) {
@@ -343,7 +344,7 @@ static void ivtv_vbi_setup(struct ivtv *itv)
        ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
 
        /* setup VBI registers */
-       itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+       v4l2_subdev_call(itv->sd_video, video, s_fmt, &itv->vbi.in);
 
        /* determine number of lines and total number of VBI bytes.
           A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
@@ -577,10 +578,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
                /* Initialize Digitizer for Capture */
-               itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
+               v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
                ivtv_msleep_timeout(300, 1);
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-               itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
+               v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
        }
 
        /* begin_capture */
index 4a37a7d2e69d53332341dd2f7cda8f66e6d6bc3e..5c5d1c462fefe7cd752e2ffa77b7ddc36ae4a024 100644 (file)
@@ -21,6 +21,7 @@
 #include "ivtv-i2c.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-queue.h"
+#include "ivtv-cards.h"
 #include "ivtv-vbi.h"
 
 static void ivtv_set_vps(struct ivtv *itv, int enabled)
@@ -37,7 +38,7 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled)
        data.data[9] = itv->vbi.vps_payload.data[2];
        data.data[10] = itv->vbi.vps_payload.data[3];
        data.data[11] = itv->vbi.vps_payload.data[4];
-       ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 }
 
 static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
@@ -51,12 +52,12 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
        data.line = (mode & 1) ? 21 : 0;
        data.data[0] = cc->odd[0];
        data.data[1] = cc->odd[1];
-       ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
        data.field = 1;
        data.line = (mode & 2) ? 21 : 0;
        data.data[0] = cc->even[0];
        data.data[1] = cc->even[1];
-       ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 }
 
 static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
@@ -79,7 +80,7 @@ static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
        data.line = enabled ? 23 : 0;
        data.data[0] = mode & 0xff;
        data.data[1] = (mode >> 8) & 0xff;
-       ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+       ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_vbi_data, &data);
 }
 
 static int odd_parity(u8 c)
@@ -313,7 +314,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8
                        continue;
                }
                vbi.p = p + 4;
-               itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+               v4l2_subdev_call(itv->sd_video, video, decode_vbi_line, &vbi);
                if (vbi.type && !(lines & (1 << vbi.line))) {
                        lines |= 1 << vbi.line;
                        itv->vbi.sliced_data[line].id = vbi.type;
@@ -437,7 +438,7 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
                        data.id = V4L2_SLICED_WSS_625;
                        data.field = 0;
 
-                       if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+                       if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
                                ivtv_set_wss(itv, 1, data.data[0] & 0xf);
                                vi->wss_missing_cnt = 0;
                        } else if (vi->wss_missing_cnt == 4) {
@@ -451,13 +452,13 @@ void ivtv_vbi_work_handler(struct ivtv *itv)
 
                        data.id = V4L2_SLICED_CAPTION_525;
                        data.field = 0;
-                       if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+                       if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
                                mode |= 1;
                                cc.odd[0] = data.data[0];
                                cc.odd[1] = data.data[1];
                        }
                        data.field = 1;
-                       if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
+                       if (v4l2_subdev_call(itv->sd_video, video, g_vbi_data, &data) == 0) {
                                mode |= 2;
                                cc.even[0] = data.data[0];
                                cc.even[1] = data.data[1];
index 921e281876f8181168fe60b8fdb3d7823e51a0bf..36abd2aef6f1473b6ff90948bb3235de5941ddbd 100644 (file)
@@ -48,6 +48,7 @@
 #endif
 
 #include "ivtv-driver.h"
+#include "ivtv-cards.h"
 #include "ivtv-i2c.h"
 #include "ivtv-udma.h"
 #include "ivtv-mailbox.h"
@@ -121,15 +122,15 @@ MODULE_LICENSE("GPL");
 #define IVTVFB_DEBUG(x, type, fmt, args...) \
        do { \
                if ((x) & ivtvfb_debug) \
-                       printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
+                       printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->instance , ## args); \
        } while (0)
 #define IVTVFB_DEBUG_WARN(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
 #define IVTVFB_DEBUG_INFO(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
 
 /* Standard kernel messages */
-#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->num , ## args)
-#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->num , ## args)
-#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->instance , ## args)
+#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->instance , ## args)
 
 /* --------------------------------------------------------------------- */
 
@@ -895,16 +896,16 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
        switch (blank_mode) {
        case FB_BLANK_UNBLANK:
                ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
-               ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
                break;
        case FB_BLANK_NORMAL:
        case FB_BLANK_HSYNC_SUSPEND:
        case FB_BLANK_VSYNC_SUSPEND:
                ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
-               ivtv_saa7127(itv, VIDIOC_STREAMON, NULL);
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
                break;
        case FB_BLANK_POWERDOWN:
-               ivtv_saa7127(itv, VIDIOC_STREAMOFF, NULL);
+               ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 0);
                ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
                break;
        }
@@ -1188,10 +1189,45 @@ static int ivtvfb_init_card(struct ivtv *itv)
 
 }
 
+static int __init ivtvfb_callback_init(struct device *dev, void *p)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+       struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+
+       if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+               if (ivtvfb_init_card(itv) == 0) {
+                       IVTVFB_INFO("Framebuffer registered on %s\n",
+                                       itv->device.name);
+                       (*(int *)p)++;
+               }
+       }
+       return 0;
+}
+
+static int ivtvfb_callback_cleanup(struct device *dev, void *p)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+       struct ivtv *itv = container_of(v4l2_dev, struct ivtv, device);
+
+       if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+               if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+                       IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n",
+                                      itv->instance);
+                       return 0;
+               }
+               IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
+               ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+               ivtvfb_release_buffers(itv);
+               itv->osd_video_pbase = 0;
+       }
+       return 0;
+}
+
 static int __init ivtvfb_init(void)
 {
-       struct ivtv *itv;
-       int i, registered = 0;
+       struct device_driver *drv;
+       int registered = 0;
+       int err;
 
        if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
                printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
@@ -1199,20 +1235,11 @@ static int __init ivtvfb_init(void)
                return -EINVAL;
        }
 
-       /* Locate & initialise all cards supporting an OSD. */
-       for (i = 0; i < ivtv_cards_active; i++) {
-               if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
-                       continue;
-               itv = ivtv_cards[i];
-               if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-                       if (ivtvfb_init_card(itv) == 0) {
-                               IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
-                               registered++;
-                       }
-               }
-       }
+       drv = driver_find("ivtv", &pci_bus_type);
+       err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
+       put_driver(drv);
        if (!registered) {
-               printk(KERN_ERR "ivtvfb:  no cards found");
+               printk(KERN_ERR "ivtvfb:  no cards found\n");
                return -ENODEV;
        }
        return 0;
@@ -1220,24 +1247,14 @@ static int __init ivtvfb_init(void)
 
 static void ivtvfb_cleanup(void)
 {
-       struct ivtv *itv;
-       int i;
+       struct device_driver *drv;
+       int err;
 
        printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
 
-       for (i = 0; i < ivtv_cards_active; i++) {
-               itv = ivtv_cards[i];
-               if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
-                       if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
-                               IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i);
-                               return;
-                       }
-                       IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
-                       ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
-                       ivtvfb_release_buffers(itv);
-                       itv->osd_video_pbase = 0;
-               }
-       }
+       drv = driver_find("ivtv", &pci_bus_type);
+       err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
+       put_driver(drv);
 }
 
 module_init(ivtvfb_init);
index 89a781c6929d77e0993c9eb448c5c6a6211e47e2..07be14a9fe7b7cd49b4fe95a21d9fd2cf3b7942b 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
 #include <media/m52790.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 
@@ -38,89 +38,130 @@ MODULE_LICENSE("GPL");
 
 
 struct m52790_state {
+       struct v4l2_subdev sd;
        u16 input;
        u16 output;
 };
 
+static inline struct m52790_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct m52790_state, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static int m52790_write(struct i2c_client *client)
+static int m52790_write(struct v4l2_subdev *sd)
 {
-       struct m52790_state *state = i2c_get_clientdata(client);
+       struct m52790_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        u8 sw1 = (state->input | state->output) & 0xff;
        u8 sw2 = (state->input | state->output) >> 8;
 
        return i2c_smbus_write_byte_data(client, sw1, sw2);
 }
 
-static int m52790_command(struct i2c_client *client, unsigned int cmd,
-                           void *arg)
+/* Note: audio and video are linked and cannot be switched separately.
+   So audio and video routing commands are identical for this chip.
+   In theory the video amplifier and audio modes could be handled
+   separately for the output, but that seems to be overkill right now.
+   The same holds for implementing an audio mute control, this is now
+   part of the audio output routing. The normal case is that another
+   chip takes care of the actual muting so making it part of the
+   output routing seems to be the right thing to do for now. */
+static int m52790_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
-       struct m52790_state *state = i2c_get_clientdata(client);
-       struct v4l2_routing *route = arg;
-
-       /* Note: audio and video are linked and cannot be switched separately.
-          So audio and video routing commands are identical for this chip.
-          In theory the video amplifier and audio modes could be handled
-          separately for the output, but that seems to be overkill right now.
-          The same holds for implementing an audio mute control, this is now
-          part of the audio output routing. The normal case is that another
-          chip takes care of the actual muting so making it part of the
-          output routing seems to be the right thing to do for now. */
-       switch (cmd) {
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = state->input;
-               route->output = state->output;
-               break;
-
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-               state->input = route->input;
-               state->output = route->output;
-               m52790_write(client);
-               break;
+       struct m52790_state *state = to_state(sd);
+
+       state->input = route->input;
+       state->output = route->output;
+       m52790_write(sd);
+       return 0;
+}
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client,
-                                       reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (reg->reg != 0)
-                       return -EINVAL;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = state->input | state->output;
-               else {
-                       state->input = reg->val & 0x0303;
-                       state->output = reg->val & ~0x0303;
-                       m52790_write(client);
-               }
-               break;
-       }
-#endif
+static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct m52790_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg,
-                               V4L2_IDENT_M52790, 0);
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (reg->reg != 0)
+               return -EINVAL;
+       reg->val = state->input | state->output;
+       return 0;
+}
 
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Switch 1: %02x\n",
-                               (state->input | state->output) & 0xff);
-               v4l_info(client, "Switch 2: %02x\n",
-                               (state->input | state->output) >> 8);
-               break;
+static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct m52790_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       default:
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
                return -EINVAL;
-       }
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (reg->reg != 0)
+               return -EINVAL;
+       state->input = reg->val & 0x0303;
+       state->output = reg->val & ~0x0303;
+       m52790_write(sd);
        return 0;
 }
+#endif
+
+static int m52790_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_M52790, 0);
+}
+
+static int m52790_log_status(struct v4l2_subdev *sd)
+{
+       struct m52790_state *state = to_state(sd);
+
+       v4l2_info(sd, "Switch 1: %02x\n",
+                       (state->input | state->output) & 0xff);
+       v4l2_info(sd, "Switch 2: %02x\n",
+                       (state->input | state->output) >> 8);
+       return 0;
+}
+
+static int m52790_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops m52790_core_ops = {
+       .log_status = m52790_log_status,
+       .g_chip_ident = m52790_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = m52790_g_register,
+       .s_register = m52790_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_audio_ops m52790_audio_ops = {
+       .s_routing = m52790_s_routing,
+};
+
+static const struct v4l2_subdev_video_ops m52790_video_ops = {
+       .s_routing = m52790_s_routing,
+};
+
+static const struct v4l2_subdev_ops m52790_ops = {
+       .core = &m52790_core_ops,
+       .audio = &m52790_audio_ops,
+       .video = &m52790_video_ops,
+};
 
 /* ----------------------------------------------------------------------- */
 
@@ -130,6 +171,7 @@ static int m52790_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct m52790_state *state;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -142,16 +184,20 @@ static int m52790_probe(struct i2c_client *client,
        if (state == NULL)
                return -ENOMEM;
 
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &m52790_ops);
        state->input = M52790_IN_TUNER;
        state->output = M52790_OUT_STEREO;
-       i2c_set_clientdata(client, state);
-       m52790_write(client);
+       m52790_write(sd);
        return 0;
 }
 
 static int m52790_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index 3da74dcee9024abe29bc341c75c09a1da224abb9..a622dbb72ed89e166fec1566f40abcc825e27c23 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-i2c-drv-legacy.h>
-#include <media/tvaudio.h>
 #include <media/msp3400.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
+#include <media/tvaudio.h>
 #include "msp3400-driver.h"
 
 /* ---------------------------------------------------------------------- */
@@ -265,7 +265,7 @@ static char *scart_names[] = {
 
 void msp_set_scart(struct i2c_client *client, int in, int out)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        state->in_scart = in;
 
@@ -289,7 +289,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
 
 void msp_set_audio(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int bal = 0, bass, treble, loudness;
        int val = 0;
        int reallymuted = state->muted | state->scan_in_progress;
@@ -336,7 +336,7 @@ void msp_set_audio(struct i2c_client *client)
 
 static void msp_wake_thread(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        if (NULL == state->kthread)
                return;
@@ -390,9 +390,9 @@ static int msp_mode_v4l1_to_v4l2(int mode)
 }
 #endif
 
-static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_VOLUME:
@@ -433,9 +433,10 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_VOLUME:
@@ -481,40 +482,16 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
+static int msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
-
-       if (msp_debug >= 2)
-               v4l_i2c_print_ioctl(client, cmd);
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
        switch (cmd) {
-       case AUDC_SET_RADIO:
-               if (state->radio)
-                       return 0;
-               state->radio = 1;
-               v4l_dbg(1, msp_debug, client, "switching to radio mode\n");
-               state->watch_stereo = 0;
-               switch (state->opmode) {
-               case OPMODE_MANUAL:
-                       /* set msp3400 to FM radio mode */
-                       msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
-                       msp3400c_set_carrier(client, MSP_CARRIER(10.7),
-                                           MSP_CARRIER(10.7));
-                       msp_set_audio(client);
-                       break;
-               case OPMODE_AUTODETECT:
-               case OPMODE_AUTOSELECT:
-                       /* the thread will do for us */
-                       msp_wake_thread(client);
-                       break;
-               }
-               break;
-
        /* --- v4l ioctls --- */
        /* take care: bttv does userspace copying, we'll get a
           kernel pointer here... */
-#ifdef CONFIG_VIDEO_ALLOW_V4L1
        case VIDIOCGAUDIO:
        {
                struct video_audio *va = arg;
@@ -588,105 +565,137 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                msp_wake_thread(client);
                break;
        }
-#endif
-       case VIDIOC_S_FREQUENCY:
-       {
-               /* new channel -- kick audio carrier scan */
-               msp_wake_thread(client);
-               break;
+       default:
+               return -ENOIOCTLCMD;
        }
+       return 0;
+}
+#endif
 
-       /* --- v4l2 ioctls --- */
-       case VIDIOC_S_STD:
-       {
-               v4l2_std_id *id = arg;
-               int update = state->radio || state->v4l2_std != *id;
+/* --- v4l2 ioctls --- */
+static int msp_s_radio(struct v4l2_subdev *sd)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               state->v4l2_std = *id;
-               state->radio = 0;
-               if (update)
-                       msp_wake_thread(client);
+       if (state->radio)
                return 0;
+       state->radio = 1;
+       v4l_dbg(1, msp_debug, client, "switching to radio mode\n");
+       state->watch_stereo = 0;
+       switch (state->opmode) {
+       case OPMODE_MANUAL:
+               /* set msp3400 to FM radio mode */
+               msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
+               msp3400c_set_carrier(client, MSP_CARRIER(10.7),
+                               MSP_CARRIER(10.7));
+               msp_set_audio(client);
+               break;
+       case OPMODE_AUTODETECT:
+       case OPMODE_AUTOSELECT:
+               /* the thread will do for us */
+               msp_wake_thread(client);
+               break;
        }
+       return 0;
+}
 
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-       {
-               struct v4l2_routing *rt = arg;
+static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               *rt = state->routing;
-               break;
-       }
+       /* new channel -- kick audio carrier scan */
+       msp_wake_thread(client);
+       return 0;
+}
 
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-       {
-               struct v4l2_routing *rt = arg;
-               int tuner = (rt->input >> 3) & 1;
-               int sc_in = rt->input & 0x7;
-               int sc1_out = rt->output & 0xf;
-               int sc2_out = (rt->output >> 4) & 0xf;
-               u16 val, reg;
-               int i;
-               int extern_input = 1;
-
-               if (state->routing.input == rt->input &&
-                   state->routing.output == rt->output)
-                       break;
-               state->routing = *rt;
-               /* check if the tuner input is used */
-               for (i = 0; i < 5; i++) {
-                       if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
-                               extern_input = 0;
-               }
-               state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT;
-               state->rxsubchans = V4L2_TUNER_SUB_STEREO;
-               msp_set_scart(client, sc_in, 0);
-               msp_set_scart(client, sc1_out, 1);
-               msp_set_scart(client, sc2_out, 2);
-               msp_set_audmode(client);
-               reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
-               val = msp_read_dem(client, reg);
-               msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
-               /* wake thread when a new input is chosen */
+static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int update = state->radio || state->v4l2_std != id;
+
+       state->v4l2_std = id;
+       state->radio = 0;
+       if (update)
                msp_wake_thread(client);
-               break;
+       return 0;
+}
+
+static int msp_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int tuner = (rt->input >> 3) & 1;
+       int sc_in = rt->input & 0x7;
+       int sc1_out = rt->output & 0xf;
+       int sc2_out = (rt->output >> 4) & 0xf;
+       u16 val, reg;
+       int i;
+       int extern_input = 1;
+
+       if (state->routing.input == rt->input &&
+                       state->routing.output == rt->output)
+               return 0;
+       state->routing = *rt;
+       /* check if the tuner input is used */
+       for (i = 0; i < 5; i++) {
+               if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+                       extern_input = 0;
        }
+       state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT;
+       state->rxsubchans = V4L2_TUNER_SUB_STEREO;
+       msp_set_scart(client, sc_in, 0);
+       msp_set_scart(client, sc1_out, 1);
+       msp_set_scart(client, sc2_out, 2);
+       msp_set_audmode(client);
+       reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
+       val = msp_read_dem(client, reg);
+       msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+       /* wake thread when a new input is chosen */
+       msp_wake_thread(client);
+       return 0;
+}
 
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *vt = arg;
+static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               if (state->radio)
-                       break;
-               if (state->opmode == OPMODE_AUTOSELECT)
-                       msp_detect_stereo(client);
-               vt->audmode    = state->audmode;
-               vt->rxsubchans = state->rxsubchans;
-               vt->capability |= V4L2_TUNER_CAP_STEREO |
-                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
-               break;
-       }
+       if (state->radio)
+               return 0;
+       if (state->opmode == OPMODE_AUTOSELECT)
+               msp_detect_stereo(client);
+       vt->audmode    = state->audmode;
+       vt->rxsubchans = state->rxsubchans;
+       vt->capability |= V4L2_TUNER_CAP_STEREO |
+               V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       return 0;
+}
 
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               if (state->radio)  /* TODO: add mono/stereo support for radio */
-                       break;
-               if (state->audmode == vt->audmode)
-                       break;
-               state->audmode = vt->audmode;
-               /* only set audmode */
-               msp_set_audmode(client);
-               break;
-       }
+       if (state->radio)  /* TODO: add mono/stereo support for radio */
+               return 0;
+       if (state->audmode == vt->audmode)
+               return 0;
+       state->audmode = vt->audmode;
+       /* only set audmode */
+       msp_set_audmode(client);
+       return 0;
+}
 
-       case VIDIOC_INT_I2S_CLOCK_FREQ:
-       {
-               u32 *a = (u32 *)arg;
+static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a);
+       v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq);
 
-               switch (*a) {
+       switch (freq) {
                case 1024000:
                        state->i2s_mode = 0;
                        break;
@@ -695,24 +704,24 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        break;
                default:
                        return -EINVAL;
-               }
-               break;
        }
+       return 0;
+}
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
+static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       struct msp_state *state = to_state(sd);
 
-               switch (qc->id) {
+       switch (qc->id) {
                case V4L2_CID_AUDIO_VOLUME:
                case V4L2_CID_AUDIO_MUTE:
                        return v4l2_ctrl_query_fill_std(qc);
                default:
                        break;
-               }
-               if (!state->has_sound_processing)
-                       return -EINVAL;
-               switch (qc->id) {
+       }
+       if (!state->has_sound_processing)
+               return -EINVAL;
+       switch (qc->id) {
                case V4L2_CID_AUDIO_LOUDNESS:
                case V4L2_CID_AUDIO_BALANCE:
                case V4L2_CID_AUDIO_BASS:
@@ -720,32 +729,38 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        return v4l2_ctrl_query_fill_std(qc);
                default:
                        return -EINVAL;
-               }
        }
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-               return msp_get_ctrl(client, arg);
-
-       case VIDIOC_S_CTRL:
-               return msp_set_ctrl(client, arg);
+static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_LOG_STATUS:
-       {
-               const char *p;
+       return v4l2_chip_ident_i2c_client(client, chip, state->ident,
+                       (state->rev1 << 16) | state->rev2);
+}
 
-               if (state->opmode == OPMODE_AUTOSELECT)
-                       msp_detect_stereo(client);
-               v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
-                               client->name, state->rev1, state->rev2);
-               v4l_info(client, "Audio:    volume %d%s\n",
-                               state->volume, state->muted ? " (muted)" : "");
-               if (state->has_sound_processing) {
-                       v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
-                                       state->balance, state->bass,
-                                       state->treble,
-                                       state->loudness ? "on" : "off");
-               }
-               switch (state->mode) {
+static int msp_log_status(struct v4l2_subdev *sd)
+{
+       struct msp_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       const char *p;
+
+       if (state->opmode == OPMODE_AUTOSELECT)
+               msp_detect_stereo(client);
+       v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n",
+                       client->name, state->rev1, state->rev2);
+       v4l_info(client, "Audio:    volume %d%s\n",
+                       state->volume, state->muted ? " (muted)" : "");
+       if (state->has_sound_processing) {
+               v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
+                               state->balance, state->bass,
+                               state->treble,
+                               state->loudness ? "on" : "off");
+       }
+       switch (state->mode) {
                case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
                case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
                case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
@@ -756,36 +771,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
                case MSP_MODE_BTSC: p = "BTSC"; break;
                case MSP_MODE_EXTERN: p = "External input"; break;
                default: p = "unknown"; break;
-               }
-               if (state->mode == MSP_MODE_EXTERN) {
-                       v4l_info(client, "Mode:     %s\n", p);
-               } else if (state->opmode == OPMODE_MANUAL) {
-                       v4l_info(client, "Mode:     %s (%s%s)\n", p,
+       }
+       if (state->mode == MSP_MODE_EXTERN) {
+               v4l_info(client, "Mode:     %s\n", p);
+       } else if (state->opmode == OPMODE_MANUAL) {
+               v4l_info(client, "Mode:     %s (%s%s)\n", p,
                                (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
                                (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
-               } else {
-                       if (state->opmode == OPMODE_AUTODETECT)
-                               v4l_info(client, "Mode:     %s\n", p);
-                       v4l_info(client, "Standard: %s (%s%s)\n",
+       } else {
+               if (state->opmode == OPMODE_AUTODETECT)
+                       v4l_info(client, "Mode:     %s\n", p);
+               v4l_info(client, "Standard: %s (%s%s)\n",
                                msp_standard_std_name(state->std),
                                (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
                                (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
-               }
-               v4l_info(client, "Audmode:  0x%04x\n", state->audmode);
-               v4l_info(client, "Routing:  0x%08x (input) 0x%08x (output)\n",
-                               state->routing.input, state->routing.output);
-               v4l_info(client, "ACB:      0x%04x\n", state->acb);
-               break;
-       }
-
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, state->ident,
-                               (state->rev1 << 16) | state->rev2);
-
-       default:
-               /* unknown */
-               return -EINVAL;
        }
+       v4l_info(client, "Audmode:  0x%04x\n", state->audmode);
+       v4l_info(client, "Routing:  0x%08x (input) 0x%08x (output)\n",
+                       state->routing.input, state->routing.output);
+       v4l_info(client, "ACB:      0x%04x\n", state->acb);
        return 0;
 }
 
@@ -803,11 +807,49 @@ static int msp_resume(struct i2c_client *client)
        return 0;
 }
 
+static int msp_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops msp_core_ops = {
+       .log_status = msp_log_status,
+       .g_chip_ident = msp_g_chip_ident,
+       .g_ctrl = msp_g_ctrl,
+       .s_ctrl = msp_s_ctrl,
+       .queryctrl = msp_queryctrl,
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
+       .ioctl = msp_ioctl,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops msp_tuner_ops = {
+       .s_frequency = msp_s_frequency,
+       .g_tuner = msp_g_tuner,
+       .s_tuner = msp_s_tuner,
+       .s_radio = msp_s_radio,
+       .s_std = msp_s_std,
+};
+
+static const struct v4l2_subdev_audio_ops msp_audio_ops = {
+       .s_routing = msp_s_routing,
+       .s_i2s_clock_freq = msp_s_i2s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops msp_ops = {
+       .core = &msp_core_ops,
+       .tuner = &msp_tuner_ops,
+       .audio = &msp_audio_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct msp_state *state;
+       struct v4l2_subdev *sd;
        int (*thread_func)(void *data) = NULL;
        int msp_hard;
        int msp_family;
@@ -827,7 +869,8 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (!state)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, state);
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &msp_ops);
 
        state->v4l2_std = V4L2_STD_NTSC;
        state->audmode = V4L2_TUNER_MODE_STEREO;
@@ -972,8 +1015,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 static int msp_remove(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
+       v4l2_device_unregister_subdev(&state->sd);
        /* shutdown control thread */
        if (state->kthread) {
                state->restart = 1;
index ab69a290e5dc7ecde1a71ab79cb33a171d776d93..3fe1c1b10f538ce61ebb47fd6a79c20cad5baa26 100644 (file)
@@ -5,6 +5,7 @@
 #define MSP3400_DRIVER_H
 
 #include <media/msp3400.h>
+#include <media/v4l2-device.h>
 
 /* ---------------------------------------------------------------------- */
 
@@ -49,6 +50,7 @@ extern int msp_dolby;
 extern int msp_stereo_thresh;
 
 struct msp_state {
+       struct v4l2_subdev sd;
        int rev1, rev2;
        int ident;
        u8 has_nicam;
@@ -96,6 +98,11 @@ struct msp_state {
        unsigned int         watch_stereo:1;
 };
 
+static inline struct msp_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct msp_state, sd);
+}
+
 /* msp3400-driver.c */
 int msp_write_dem(struct i2c_client *client, int addr, int val);
 int msp_write_dsp(struct i2c_client *client, int addr, int val);
index 846a14a61fd1fc049947a0bd7908392b54977771..a655e9c30146a986e7f95e1e4ba0d4fe25328c57 100644 (file)
@@ -159,7 +159,7 @@ const char *msp_standard_std_name(int std)
 
 static void msp_set_source(struct i2c_client *client, u16 src)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        if (msp_dolby) {
                msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */
@@ -186,7 +186,7 @@ void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2)
 
 void msp3400c_set_mode(struct i2c_client *client, int mode)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
        int tuner = (state->routing.input >> 3) & 1;
        int i;
@@ -227,7 +227,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
        static char *strmode[] = {
                "mono", "stereo", "lang2", "lang1", "lang1+lang2"
        };
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
                strmode[state->audmode] : "unknown";
        int src = 0;    /* channel source: FM/AM, nicam or SCART */
@@ -356,7 +356,7 @@ static void msp3400c_set_audmode(struct i2c_client *client)
 
 static void msp3400c_print_mode(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        if (state->main == state->second)
                v4l_dbg(1, msp_debug, client,
@@ -385,7 +385,7 @@ static void msp3400c_print_mode(struct i2c_client *client)
 
 static int msp3400c_detect_stereo(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int val;
        int rxsubchans = state->rxsubchans;
        int newnicam = state->nicam_on;
@@ -463,7 +463,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
 /* stereo/multilang monitoring */
 static void watch_stereo(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        if (msp_detect_stereo(client))
                msp_set_audmode(client);
@@ -475,7 +475,7 @@ static void watch_stereo(struct i2c_client *client)
 int msp3400c_thread(void *data)
 {
        struct i2c_client *client = data;
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        struct msp3400c_carrier_detect *cd;
        int count, max1, max2, val1, val2, val, i;
 
@@ -659,7 +659,7 @@ no_second:
 int msp3410d_thread(void *data)
 {
        struct i2c_client *client = data;
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int val, i, std, count;
 
        v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
@@ -825,7 +825,7 @@ restart:
 
 static int msp34xxg_modus(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        if (state->radio) {
                v4l_dbg(1, msp_debug, client, "selected radio modus\n");
@@ -852,7 +852,7 @@ static int msp34xxg_modus(struct i2c_client *client)
 
 static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
  {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int source, matrix;
 
        switch (state->audmode) {
@@ -895,7 +895,7 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
 
 static void msp34xxg_set_sources(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        u32 in = state->routing.input;
 
        msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
@@ -911,7 +911,7 @@ static void msp34xxg_set_sources(struct i2c_client *client)
 /* (re-)initialize the msp34xxg */
 static void msp34xxg_reset(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int tuner = (state->routing.input >> 3) & 1;
        int modus;
 
@@ -954,7 +954,7 @@ static void msp34xxg_reset(struct i2c_client *client)
 int msp34xxg_thread(void *data)
 {
        struct i2c_client *client = data;
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int val, i;
 
        v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
@@ -1049,7 +1049,7 @@ unmute:
 
 static int msp34xxg_detect_stereo(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
        int status = msp_read_dem(client, 0x0200);
        int is_bilingual = status & 0x100;
        int is_stereo = status & 0x40;
@@ -1078,7 +1078,7 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
 
 static void msp34xxg_set_audmode(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        if (state->std == 0x20) {
               if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
@@ -1095,7 +1095,7 @@ static void msp34xxg_set_audmode(struct i2c_client *client)
 
 void msp_set_audmode(struct i2c_client *client)
 {
-       struct msp_state *state = i2c_get_clientdata(client);
+       struct msp_state *state = to_state(i2c_get_clientdata(client));
 
        switch (state->opmode) {
        case OPMODE_MANUAL:
@@ -1110,7 +1110,7 @@ void msp_set_audmode(struct i2c_client *client)
 
 int msp_detect_stereo(struct i2c_client *client)
 {
-       struct msp_state *state  = i2c_get_clientdata(client);
+       struct msp_state *state  = to_state(i2c_get_clientdata(client));
 
        switch (state->opmode) {
        case OPMODE_MANUAL:
index 0c524376b67e66baa4f67ddcf262a647a02143e1..1a1a12453672984b903e1bb96461d48aa881242c 100644 (file)
@@ -272,21 +272,20 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
 static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       unsigned int width_flag = SOCAM_DATAWIDTH_10;
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       /* MT9M001 has all capture_format parameters fixed */
+       unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_MASTER;
 
        if (bus_switch_possible(mt9m001))
-               width_flag |= SOCAM_DATAWIDTH_8;
+               flags |= SOCAM_DATAWIDTH_8;
 
-       /* MT9M001 has all capture_format parameters fixed */
-       return SOCAM_PCLK_SAMPLE_RISING |
-               SOCAM_HSYNC_ACTIVE_HIGH |
-               SOCAM_VSYNC_ACTIVE_HIGH |
-               SOCAM_MASTER |
-               width_flag;
+       return soc_camera_apply_sensor_flags(icl, flags);
 }
 
-static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
-               __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m001_set_fmt(struct soc_camera_device *icd,
+                          __u32 pixfmt, struct v4l2_rect *rect)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        int ret;
@@ -298,7 +297,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
                ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
 
        /* The caller provides a supported format, as verified per
-        * call to icd->try_fmt_cap() */
+        * call to icd->try_fmt() */
        if (!ret)
                ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
        if (!ret)
@@ -325,18 +324,20 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
        return ret;
 }
 
-static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
-                              struct v4l2_format *f)
+static int mt9m001_try_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
 {
-       if (f->fmt.pix.height < 32 + icd->y_skip_top)
-               f->fmt.pix.height = 32 + icd->y_skip_top;
-       if (f->fmt.pix.height > 1024 + icd->y_skip_top)
-               f->fmt.pix.height = 1024 + icd->y_skip_top;
-       if (f->fmt.pix.width < 48)
-               f->fmt.pix.width = 48;
-       if (f->fmt.pix.width > 1280)
-               f->fmt.pix.width = 1280;
-       f->fmt.pix.width &= ~0x01; /* has to be even, unsure why was ~3 */
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->height < 32 + icd->y_skip_top)
+               pix->height = 32 + icd->y_skip_top;
+       if (pix->height > 1024 + icd->y_skip_top)
+               pix->height = 1024 + icd->y_skip_top;
+       if (pix->width < 48)
+               pix->width = 48;
+       if (pix->width > 1280)
+               pix->width = 1280;
+       pix->width &= ~0x01; /* has to be even, unsure why was ~3 */
 
        return 0;
 }
@@ -447,8 +448,8 @@ static struct soc_camera_ops mt9m001_ops = {
        .release                = mt9m001_release,
        .start_capture          = mt9m001_start_capture,
        .stop_capture           = mt9m001_stop_capture,
-       .set_fmt_cap            = mt9m001_set_fmt_cap,
-       .try_fmt_cap            = mt9m001_try_fmt_cap,
+       .set_fmt                = mt9m001_set_fmt,
+       .try_fmt                = mt9m001_try_fmt,
        .set_bus_param          = mt9m001_set_bus_param,
        .query_bus_param        = mt9m001_query_bus_param,
        .controls               = mt9m001_controls,
@@ -578,6 +579,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
 static int mt9m001_video_probe(struct soc_camera_device *icd)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
        s32 data;
        int ret;
 
@@ -588,7 +590,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Enable the chip */
-       data = reg_write(&mt9m001->icd, MT9M001_CHIP_ENABLE, 1);
+       data = reg_write(icd, MT9M001_CHIP_ENABLE, 1);
        dev_dbg(&icd->dev, "write: %d\n", data);
 
        /* Read out the chip version register */
@@ -600,7 +602,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
        case 0x8421:
                mt9m001->model = V4L2_IDENT_MT9M001C12ST;
                icd->formats = mt9m001_colour_formats;
-               if (mt9m001->client->dev.platform_data)
+               if (gpio_is_valid(icl->gpio))
                        icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
                else
                        icd->num_formats = 1;
@@ -608,7 +610,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
        case 0x8431:
                mt9m001->model = V4L2_IDENT_MT9M001C12STM;
                icd->formats = mt9m001_monochrome_formats;
-               if (mt9m001->client->dev.platform_data)
+               if (gpio_is_valid(icl->gpio))
                        icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
                else
                        icd->num_formats = 1;
@@ -640,8 +642,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
 
        dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
-               mt9m001->icd.dev.parent, mt9m001->icd.vdev);
-       soc_camera_video_stop(&mt9m001->icd);
+               icd->dev.parent, icd->vdev);
+       soc_camera_video_stop(icd);
 }
 
 static int mt9m001_probe(struct i2c_client *client,
index da0b2d553fd0f28caced38a6b954793f34fc39be..c89ea41fe25948d216535ac34ed5d1604c7a76e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Driver for MT9M111 CMOS Image Sensor from Micron
+ * Driver for MT9M111/MT9M112 CMOS Image Sensor from Micron
  *
  * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
  *
@@ -19,7 +19,7 @@
 #include <media/soc_camera.h>
 
 /*
- * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin)
+ * mt9m111 and mt9m112 i2c address is 0x5d or 0x48 (depending on SAddr pin)
  * The platform has to define i2c_board_info and call i2c_register_board_info()
  */
 
@@ -90,7 +90,7 @@
 #define MT9M111_OUTPUT_FORMAT_CTRL2_B  0x19b
 
 #define MT9M111_OPMODE_AUTOEXPO_EN     (1 << 14)
-
+#define MT9M111_OPMODE_AUTOWHITEBAL_EN (1 << 1)
 
 #define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14)
 #define MT9M111_OUTFMT_BYPASS_IFP      (1 << 10)
        .colorspace = _colorspace }
 #define RGB_FMT(_name, _depth, _fourcc) \
        COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB)
+#define JPG_FMT(_name, _depth, _fourcc) \
+       COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG)
 
 static const struct soc_camera_data_format mt9m111_colour_formats[] = {
-       COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG),
+       JPG_FMT("CbYCrY 16 bit", 16, V4L2_PIX_FMT_UYVY),
+       JPG_FMT("CrYCbY 16 bit", 16, V4L2_PIX_FMT_VYUY),
+       JPG_FMT("YCbYCr 16 bit", 16, V4L2_PIX_FMT_YUYV),
+       JPG_FMT("YCrYCb 16 bit", 16, V4L2_PIX_FMT_YVYU),
        RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565),
        RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555),
        RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16),
@@ -145,7 +150,7 @@ enum mt9m111_context {
 struct mt9m111 {
        struct i2c_client *client;
        struct soc_camera_device icd;
-       int model;      /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */
+       int model;      /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
        enum mt9m111_context context;
        unsigned int left, top, width, height;
        u32 pixfmt;
@@ -158,6 +163,7 @@ struct mt9m111 {
        unsigned int swap_rgb_red_blue:1;
        unsigned int swap_yuv_y_chromas:1;
        unsigned int swap_yuv_cb_cr:1;
+       unsigned int autowhitebalance:1;
 };
 
 static int reg_page_map_set(struct i2c_client *client, const u16 reg)
@@ -410,9 +416,13 @@ static int mt9m111_stop_capture(struct soc_camera_device *icd)
 
 static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
 {
-       return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
                SOCAM_DATAWIDTH_8;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
 }
 
 static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
@@ -438,7 +448,24 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
        case V4L2_PIX_FMT_RGB565:
                ret = mt9m111_setfmt_rgb565(icd);
                break;
+       case V4L2_PIX_FMT_UYVY:
+               mt9m111->swap_yuv_y_chromas = 0;
+               mt9m111->swap_yuv_cb_cr = 0;
+               ret = mt9m111_setfmt_yuv(icd);
+               break;
+       case V4L2_PIX_FMT_VYUY:
+               mt9m111->swap_yuv_y_chromas = 0;
+               mt9m111->swap_yuv_cb_cr = 1;
+               ret = mt9m111_setfmt_yuv(icd);
+               break;
        case V4L2_PIX_FMT_YUYV:
+               mt9m111->swap_yuv_y_chromas = 1;
+               mt9m111->swap_yuv_cb_cr = 0;
+               ret = mt9m111_setfmt_yuv(icd);
+               break;
+       case V4L2_PIX_FMT_YVYU:
+               mt9m111->swap_yuv_y_chromas = 1;
+               mt9m111->swap_yuv_cb_cr = 1;
                ret = mt9m111_setfmt_yuv(icd);
                break;
        default:
@@ -452,8 +479,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt)
        return ret;
 }
 
-static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
-                              __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9m111_set_fmt(struct soc_camera_device *icd,
+                          __u32 pixfmt, struct v4l2_rect *rect)
 {
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
@@ -473,13 +500,15 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd,
        return ret;
 }
 
-static int mt9m111_try_fmt_cap(struct soc_camera_device *icd,
-                              struct v4l2_format *f)
+static int mt9m111_try_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
 {
-       if (f->fmt.pix.height > MT9M111_MAX_HEIGHT)
-               f->fmt.pix.height = MT9M111_MAX_HEIGHT;
-       if (f->fmt.pix.width > MT9M111_MAX_WIDTH)
-               f->fmt.pix.width = MT9M111_MAX_WIDTH;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->height > MT9M111_MAX_HEIGHT)
+               pix->height = MT9M111_MAX_HEIGHT;
+       if (pix->width > MT9M111_MAX_WIDTH)
+               pix->width = MT9M111_MAX_WIDTH;
 
        return 0;
 }
@@ -597,8 +626,8 @@ static struct soc_camera_ops mt9m111_ops = {
        .release                = mt9m111_release,
        .start_capture          = mt9m111_start_capture,
        .stop_capture           = mt9m111_stop_capture,
-       .set_fmt_cap            = mt9m111_set_fmt_cap,
-       .try_fmt_cap            = mt9m111_try_fmt_cap,
+       .set_fmt                = mt9m111_set_fmt,
+       .try_fmt                = mt9m111_try_fmt,
        .query_bus_param        = mt9m111_query_bus_param,
        .set_bus_param          = mt9m111_set_bus_param,
        .controls               = mt9m111_controls,
@@ -634,18 +663,15 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 
 static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 {
-       unsigned int data, gain;
+       int data;
 
        data = reg_read(GLOBAL_GAIN);
        if (data >= 0)
-               gain = ((data & (1 << 10)) * 2)
-                       | ((data & (1 << 9)) * 2)
-                       | (data & 0x2f);
-       else
-               gain = data;
-
-       return gain;
+               return (data & 0x2f) * (1 << ((data >> 10) & 1)) *
+                       (1 << ((data >> 9) & 1));
+       return data;
 }
+
 static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 {
        u16 val;
@@ -679,6 +705,23 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 
        return ret;
 }
+
+static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
+{
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       int ret;
+
+       if (on)
+               ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+       else
+               ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN);
+
+       if (!ret)
+               mt9m111->autowhitebalance = on;
+
+       return ret;
+}
+
 static int mt9m111_get_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
@@ -715,6 +758,9 @@ static int mt9m111_get_control(struct soc_camera_device *icd,
        case V4L2_CID_EXPOSURE_AUTO:
                ctrl->value = mt9m111->autoexposure;
                break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ctrl->value = mt9m111->autowhitebalance;
+               break;
        }
        return 0;
 }
@@ -748,6 +794,9 @@ static int mt9m111_set_control(struct soc_camera_device *icd,
        case V4L2_CID_EXPOSURE_AUTO:
                ret =  mt9m111_set_autoexposure(icd, ctrl->value);
                break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ret =  mt9m111_set_autowhitebalance(icd, ctrl->value);
+               break;
        default:
                ret = -EINVAL;
        }
@@ -766,6 +815,7 @@ static int mt9m111_restore_state(struct soc_camera_device *icd)
        mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS);
        mt9m111_set_global_gain(icd, icd->gain);
        mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
+       mt9m111_set_autowhitebalance(icd, mt9m111->autowhitebalance);
        return 0;
 }
 
@@ -798,7 +848,7 @@ static int mt9m111_init(struct soc_camera_device *icd)
        if (!ret)
                ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure);
        if (ret)
-               dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret);
+               dev_err(&icd->dev, "mt9m11x init failed: %d\n", ret);
        return ret;
 }
 
@@ -808,7 +858,7 @@ static int mt9m111_release(struct soc_camera_device *icd)
 
        ret = mt9m111_disable(icd);
        if (ret < 0)
-               dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret);
+               dev_err(&icd->dev, "mt9m11x release failed: %d\n", ret);
 
        return ret;
 }
@@ -841,25 +891,30 @@ static int mt9m111_video_probe(struct soc_camera_device *icd)
        data = reg_read(CHIP_VERSION);
 
        switch (data) {
-       case 0x143a:
+       case 0x143a: /* MT9M111 */
                mt9m111->model = V4L2_IDENT_MT9M111;
-               icd->formats = mt9m111_colour_formats;
-               icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+               break;
+       case 0x148c: /* MT9M112 */
+               mt9m111->model = V4L2_IDENT_MT9M112;
                break;
        default:
                ret = -ENODEV;
                dev_err(&icd->dev,
-                       "No MT9M111 chip detected, register read %x\n", data);
+                       "No MT9M11x chip detected, register read %x\n", data);
                goto ei2c;
        }
 
-       dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n");
+       icd->formats = mt9m111_colour_formats;
+       icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats);
+
+       dev_info(&icd->dev, "Detected a MT9M11x chip ID %x\n", data);
 
        ret = soc_camera_video_start(icd);
        if (ret)
                goto eisis;
 
        mt9m111->autoexposure = 1;
+       mt9m111->autowhitebalance = 1;
 
        mt9m111->swap_rgb_even_odd = 1;
        mt9m111->swap_rgb_red_blue = 1;
@@ -889,7 +944,7 @@ static int mt9m111_probe(struct i2c_client *client,
        int ret;
 
        if (!icl) {
-               dev_err(&client->dev, "MT9M111 driver needs platform data\n");
+               dev_err(&client->dev, "MT9M11x driver needs platform data\n");
                return -EINVAL;
        }
 
@@ -968,6 +1023,6 @@ static void __exit mt9m111_mod_exit(void)
 module_init(mt9m111_mod_init);
 module_exit(mt9m111_mod_exit);
 
-MODULE_DESCRIPTION("Micron MT9M111 Camera driver");
+MODULE_DESCRIPTION("Micron MT9M111/MT9M112 Camera driver");
 MODULE_AUTHOR("Robert Jarzmik");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
new file mode 100644 (file)
index 0000000..1a9d539
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ * Driver for MT9T031 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
+ *
+ * This program is free software; you can 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/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+/* mt9t031 i2c address 0x5d
+ * The platform has to define i2c_board_info
+ * and call i2c_register_board_info() */
+
+/* mt9t031 selected register addresses */
+#define MT9T031_CHIP_VERSION           0x00
+#define MT9T031_ROW_START              0x01
+#define MT9T031_COLUMN_START           0x02
+#define MT9T031_WINDOW_HEIGHT          0x03
+#define MT9T031_WINDOW_WIDTH           0x04
+#define MT9T031_HORIZONTAL_BLANKING    0x05
+#define MT9T031_VERTICAL_BLANKING      0x06
+#define MT9T031_OUTPUT_CONTROL         0x07
+#define MT9T031_SHUTTER_WIDTH_UPPER    0x08
+#define MT9T031_SHUTTER_WIDTH          0x09
+#define MT9T031_PIXEL_CLOCK_CONTROL    0x0a
+#define MT9T031_FRAME_RESTART          0x0b
+#define MT9T031_SHUTTER_DELAY          0x0c
+#define MT9T031_RESET                  0x0d
+#define MT9T031_READ_MODE_1            0x1e
+#define MT9T031_READ_MODE_2            0x20
+#define MT9T031_READ_MODE_3            0x21
+#define MT9T031_ROW_ADDRESS_MODE       0x22
+#define MT9T031_COLUMN_ADDRESS_MODE    0x23
+#define MT9T031_GLOBAL_GAIN            0x35
+#define MT9T031_CHIP_ENABLE            0xF8
+
+#define MT9T031_MAX_HEIGHT             1536
+#define MT9T031_MAX_WIDTH              2048
+#define MT9T031_MIN_HEIGHT             2
+#define MT9T031_MIN_WIDTH              2
+#define MT9T031_HORIZONTAL_BLANK       142
+#define MT9T031_VERTICAL_BLANK         25
+#define MT9T031_COLUMN_SKIP            32
+#define MT9T031_ROW_SKIP               20
+
+#define MT9T031_BUS_PARAM      (SOCAM_PCLK_SAMPLE_RISING |     \
+       SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH |   \
+       SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH |      \
+       SOCAM_MASTER | SOCAM_DATAWIDTH_10)
+
+static const struct soc_camera_data_format mt9t031_colour_formats[] = {
+       {
+               .name           = "Bayer (sRGB) 10 bit",
+               .depth          = 10,
+               .fourcc         = V4L2_PIX_FMT_SGRBG10,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+       }
+};
+
+struct mt9t031 {
+       struct i2c_client *client;
+       struct soc_camera_device icd;
+       int model;      /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
+       unsigned char autoexposure;
+       u16 xskip;
+       u16 yskip;
+};
+
+static int reg_read(struct soc_camera_device *icd, const u8 reg)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       struct i2c_client *client = mt9t031->client;
+       s32 data = i2c_smbus_read_word_data(client, reg);
+       return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct soc_camera_device *icd, const u8 reg,
+                    const u16 data)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       return i2c_smbus_write_word_data(mt9t031->client, reg, swab16(data));
+}
+
+static int reg_set(struct soc_camera_device *icd, const u8 reg,
+                  const u16 data)
+{
+       int ret;
+
+       ret = reg_read(icd, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(icd, reg, ret | data);
+}
+
+static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+                    const u16 data)
+{
+       int ret;
+
+       ret = reg_read(icd, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(icd, reg, ret & ~data);
+}
+
+static int set_shutter(struct soc_camera_device *icd, const u32 data)
+{
+       int ret;
+
+       ret = reg_write(icd, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
+
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_SHUTTER_WIDTH, data & 0xffff);
+
+       return ret;
+}
+
+static int get_shutter(struct soc_camera_device *icd, u32 *data)
+{
+       int ret;
+
+       ret = reg_read(icd, MT9T031_SHUTTER_WIDTH_UPPER);
+       *data = ret << 16;
+
+       if (ret >= 0)
+               ret = reg_read(icd, MT9T031_SHUTTER_WIDTH);
+       *data |= ret & 0xffff;
+
+       return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_init(struct soc_camera_device *icd)
+{
+       int ret;
+
+       /* Disable chip output, synchronous option update */
+       dev_dbg(icd->vdev->parent, "%s\n", __func__);
+
+       ret = reg_write(icd, MT9T031_RESET, 1);
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_RESET, 0);
+       if (ret >= 0)
+               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+
+       return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9t031_release(struct soc_camera_device *icd)
+{
+       /* Disable the chip */
+       reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+       return 0;
+}
+
+static int mt9t031_start_capture(struct soc_camera_device *icd)
+{
+       /* Switch to master "normal" mode */
+       if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+               return -EIO;
+       return 0;
+}
+
+static int mt9t031_stop_capture(struct soc_camera_device *icd)
+{
+       /* Stop sensor readout */
+       if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+               return -EIO;
+       return 0;
+}
+
+static int mt9t031_set_bus_param(struct soc_camera_device *icd,
+                                unsigned long flags)
+{
+       /* The caller should have queried our parameters, check anyway */
+       if (flags & ~MT9T031_BUS_PARAM)
+               return -EINVAL;
+
+       if (flags & SOCAM_PCLK_SAMPLE_FALLING)
+               reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+       else
+               reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+
+       return 0;
+}
+
+static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+
+       return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
+}
+
+static int mt9t031_set_fmt(struct soc_camera_device *icd,
+                          __u32 pixfmt, struct v4l2_rect *rect)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       int ret;
+       const u16 hblank = MT9T031_HORIZONTAL_BLANK,
+               vblank = MT9T031_VERTICAL_BLANK;
+       u16 xbin, xskip = mt9t031->xskip, ybin, yskip = mt9t031->yskip,
+               width = rect->width * xskip, height = rect->height * yskip;
+
+       if (pixfmt) {
+               /* S_FMT - use binning and skipping for scaling, recalculate */
+               /* Is this more optimal than just a division? */
+               for (xskip = 8; xskip > 1; xskip--)
+                       if (rect->width * xskip <= icd->width_max)
+                               break;
+
+               for (yskip = 8; yskip > 1; yskip--)
+                       if (rect->height * yskip <= icd->height_max)
+                               break;
+
+               width = rect->width * xskip;
+               height = rect->height * yskip;
+
+               dev_dbg(&icd->dev, "xskip %u, width %u, yskip %u, height %u\n",
+                       xskip, width, yskip, height);
+       }
+
+       xbin = min(xskip, (u16)3);
+       ybin = min(yskip, (u16)3);
+
+       /* Make sure we don't exceed frame limits */
+       if (rect->left + width > icd->width_max)
+               rect->left = (icd->width_max - width) / 2;
+
+       if (rect->top + height > icd->height_max)
+               rect->top = (icd->height_max - height) / 2;
+
+       /* Could just do roundup(rect->left, [xy]bin); but this is cheaper */
+       switch (xbin) {
+       case 2:
+               rect->left = (rect->left + 1) & ~1;
+               break;
+       case 3:
+               rect->left = roundup(rect->left, 3);
+       }
+
+       switch (ybin) {
+       case 2:
+               rect->top = (rect->top + 1) & ~1;
+               break;
+       case 3:
+               rect->top = roundup(rect->top, 3);
+       }
+
+       /* Blanking and start values - default... */
+       ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
+
+       if (pixfmt) {
+               /* Binning, skipping */
+               if (ret >= 0)
+                       ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
+                                       ((xbin - 1) << 4) | (xskip - 1));
+               if (ret >= 0)
+                       ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
+                                       ((ybin - 1) << 4) | (yskip - 1));
+       }
+       dev_dbg(&icd->dev, "new left %u, top %u\n", rect->left, rect->top);
+
+       /* The caller provides a supported format, as guaranteed by
+        * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_COLUMN_START, rect->left);
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_ROW_START, rect->top);
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
+       if (ret >= 0)
+               ret = reg_write(icd, MT9T031_WINDOW_HEIGHT,
+                               height + icd->y_skip_top - 1);
+       if (ret >= 0 && mt9t031->autoexposure) {
+               ret = set_shutter(icd, height + icd->y_skip_top + vblank);
+               if (ret >= 0) {
+                       const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
+                       const struct v4l2_queryctrl *qctrl =
+                               soc_camera_find_qctrl(icd->ops,
+                                                     V4L2_CID_EXPOSURE);
+                       icd->exposure = (shutter_max / 2 + (height +
+                                        icd->y_skip_top + vblank - 1) *
+                                        (qctrl->maximum - qctrl->minimum)) /
+                               shutter_max + qctrl->minimum;
+               }
+       }
+
+       if (!ret && pixfmt) {
+               mt9t031->xskip = xskip;
+               mt9t031->yskip = yskip;
+       }
+
+       return ret < 0 ? ret : 0;
+}
+
+static int mt9t031_try_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
+{
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->height < icd->height_min)
+               pix->height = icd->height_min;
+       if (pix->height > icd->height_max)
+               pix->height = icd->height_max;
+       if (pix->width < icd->width_min)
+               pix->width = icd->width_min;
+       if (pix->width > icd->width_max)
+               pix->width = icd->width_max;
+
+       pix->width &= ~0x01; /* has to be even */
+       pix->height &= ~0x01; /* has to be even */
+
+       return 0;
+}
+
+static int mt9t031_get_chip_id(struct soc_camera_device *icd,
+                              struct v4l2_chip_ident *id)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+       if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       if (id->match_chip != mt9t031->client->addr)
+               return -ENODEV;
+
+       id->ident       = mt9t031->model;
+       id->revision    = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t031_get_register(struct soc_camera_device *icd,
+                               struct v4l2_register *reg)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+       if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+               return -EINVAL;
+
+       if (reg->match_chip != mt9t031->client->addr)
+               return -ENODEV;
+
+       reg->val = reg_read(icd, reg->reg);
+
+       if (reg->val > 0xffff)
+               return -EIO;
+
+       return 0;
+}
+
+static int mt9t031_set_register(struct soc_camera_device *icd,
+                               struct v4l2_register *reg)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+       if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+               return -EINVAL;
+
+       if (reg->match_chip != mt9t031->client->addr)
+               return -ENODEV;
+
+       if (reg_write(icd, reg->reg, reg->val) < 0)
+               return -EIO;
+
+       return 0;
+}
+#endif
+
+static const struct v4l2_queryctrl mt9t031_controls[] = {
+       {
+               .id             = V4L2_CID_VFLIP,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Flip Vertically",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 0,
+       }, {
+               .id             = V4L2_CID_GAIN,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Gain",
+               .minimum        = 0,
+               .maximum        = 127,
+               .step           = 1,
+               .default_value  = 64,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id             = V4L2_CID_EXPOSURE,
+               .type           = V4L2_CTRL_TYPE_INTEGER,
+               .name           = "Exposure",
+               .minimum        = 1,
+               .maximum        = 255,
+               .step           = 1,
+               .default_value  = 255,
+               .flags          = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id             = V4L2_CID_EXPOSURE_AUTO,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Automatic Exposure",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       }
+};
+
+static int mt9t031_video_probe(struct soc_camera_device *);
+static void mt9t031_video_remove(struct soc_camera_device *);
+static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
+
+static struct soc_camera_ops mt9t031_ops = {
+       .owner                  = THIS_MODULE,
+       .probe                  = mt9t031_video_probe,
+       .remove                 = mt9t031_video_remove,
+       .init                   = mt9t031_init,
+       .release                = mt9t031_release,
+       .start_capture          = mt9t031_start_capture,
+       .stop_capture           = mt9t031_stop_capture,
+       .set_fmt                = mt9t031_set_fmt,
+       .try_fmt                = mt9t031_try_fmt,
+       .set_bus_param          = mt9t031_set_bus_param,
+       .query_bus_param        = mt9t031_query_bus_param,
+       .controls               = mt9t031_controls,
+       .num_controls           = ARRAY_SIZE(mt9t031_controls),
+       .get_control            = mt9t031_get_control,
+       .set_control            = mt9t031_set_control,
+       .get_chip_id            = mt9t031_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .get_register           = mt9t031_get_register,
+       .set_register           = mt9t031_set_register,
+#endif
+};
+
+static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       int data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               data = reg_read(icd, MT9T031_READ_MODE_2);
+               if (data < 0)
+                       return -EIO;
+               ctrl->value = !!(data & 0x8000);
+               break;
+       case V4L2_CID_HFLIP:
+               data = reg_read(icd, MT9T031_READ_MODE_2);
+               if (data < 0)
+                       return -EIO;
+               ctrl->value = !!(data & 0x4000);
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               ctrl->value = mt9t031->autoexposure;
+               break;
+       }
+       return 0;
+}
+
+static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       const struct v4l2_queryctrl *qctrl;
+       int data;
+
+       qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id);
+
+       if (!qctrl)
+               return -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (ctrl->value)
+                       data = reg_set(icd, MT9T031_READ_MODE_2, 0x8000);
+               else
+                       data = reg_clear(icd, MT9T031_READ_MODE_2, 0x8000);
+               if (data < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_HFLIP:
+               if (ctrl->value)
+                       data = reg_set(icd, MT9T031_READ_MODE_2, 0x4000);
+               else
+                       data = reg_clear(icd, MT9T031_READ_MODE_2, 0x4000);
+               if (data < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_GAIN:
+               if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+                       return -EINVAL;
+               /* See Datasheet Table 7, Gain settings. */
+               if (ctrl->value <= qctrl->default_value) {
+                       /* Pack it into 0..1 step 0.125, register values 0..8 */
+                       unsigned long range = qctrl->default_value - qctrl->minimum;
+                       data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
+
+                       dev_dbg(&icd->dev, "Setting gain %d\n", data);
+                       data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+                       if (data < 0)
+                               return -EIO;
+               } else {
+                       /* Pack it into 1.125..15 variable step, register values 9..67 */
+                       /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+                       unsigned long range = qctrl->maximum - qctrl->default_value - 1;
+                       unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
+                                              111 + range / 2) / range + 9;
+
+                       if (gain <= 32)
+                               data = gain;
+                       else if (gain <= 64)
+                               data = ((gain - 32) * 16 + 16) / 32 + 80;
+                       else
+                               data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+                       dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+                                reg_read(icd, MT9T031_GLOBAL_GAIN), data);
+                       data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+                       if (data < 0)
+                               return -EIO;
+               }
+
+               /* Success */
+               icd->gain = ctrl->value;
+               break;
+       case V4L2_CID_EXPOSURE:
+               /* mt9t031 has maximum == default */
+               if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+                       return -EINVAL;
+               else {
+                       const unsigned long range = qctrl->maximum - qctrl->minimum;
+                       const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 +
+                                            range / 2) / range + 1;
+                       u32 old;
+
+                       get_shutter(icd, &old);
+                       dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
+                               old, shutter);
+                       if (set_shutter(icd, shutter) < 0)
+                               return -EIO;
+                       icd->exposure = ctrl->value;
+                       mt9t031->autoexposure = 0;
+               }
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (ctrl->value) {
+                       const u16 vblank = MT9T031_VERTICAL_BLANK;
+                       const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
+                       if (set_shutter(icd, icd->height +
+                                       icd->y_skip_top + vblank) < 0)
+                               return -EIO;
+                       qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+                       icd->exposure = (shutter_max / 2 + (icd->height +
+                                        icd->y_skip_top + vblank - 1) *
+                                        (qctrl->maximum - qctrl->minimum)) /
+                               shutter_max + qctrl->minimum;
+                       mt9t031->autoexposure = 1;
+               } else
+                       mt9t031->autoexposure = 0;
+               break;
+       }
+       return 0;
+}
+
+/* Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one */
+static int mt9t031_video_probe(struct soc_camera_device *icd)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       s32 data;
+       int ret;
+
+       /* We must have a parent by now. And it cannot be a wrong one.
+        * So this entire test is completely redundant. */
+       if (!icd->dev.parent ||
+           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+               return -ENODEV;
+
+       /* Enable the chip */
+       data = reg_write(icd, MT9T031_CHIP_ENABLE, 1);
+       dev_dbg(&icd->dev, "write: %d\n", data);
+
+       /* Read out the chip version register */
+       data = reg_read(icd, MT9T031_CHIP_VERSION);
+
+       switch (data) {
+       case 0x1621:
+               mt9t031->model = V4L2_IDENT_MT9T031;
+               icd->formats = mt9t031_colour_formats;
+               icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
+               break;
+       default:
+               ret = -ENODEV;
+               dev_err(&icd->dev,
+                       "No MT9T031 chip detected, register read %x\n", data);
+               goto ei2c;
+       }
+
+       dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
+
+       /* Now that we know the model, we can start video */
+       ret = soc_camera_video_start(icd);
+       if (ret)
+               goto evstart;
+
+       return 0;
+
+evstart:
+ei2c:
+       return ret;
+}
+
+static void mt9t031_video_remove(struct soc_camera_device *icd)
+{
+       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+
+       dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
+               icd->dev.parent, icd->vdev);
+       soc_camera_video_stop(icd);
+}
+
+static int mt9t031_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9t031 *mt9t031;
+       struct soc_camera_device *icd;
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct soc_camera_link *icl = client->dev.platform_data;
+       int ret;
+
+       if (!icl) {
+               dev_err(&client->dev, "MT9T031 driver needs platform data\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
+       if (!mt9t031)
+               return -ENOMEM;
+
+       mt9t031->client = client;
+       i2c_set_clientdata(client, mt9t031);
+
+       /* Second stage probe - when a capture adapter is there */
+       icd = &mt9t031->icd;
+       icd->ops        = &mt9t031_ops;
+       icd->control    = &client->dev;
+       icd->x_min      = MT9T031_COLUMN_SKIP;
+       icd->y_min      = MT9T031_ROW_SKIP;
+       icd->x_current  = icd->x_min;
+       icd->y_current  = icd->y_min;
+       icd->width_min  = MT9T031_MIN_WIDTH;
+       icd->width_max  = MT9T031_MAX_WIDTH;
+       icd->height_min = MT9T031_MIN_HEIGHT;
+       icd->height_max = MT9T031_MAX_HEIGHT;
+       icd->y_skip_top = 0;
+       icd->iface      = icl->bus_id;
+       /* Simulated autoexposure. If enabled, we calculate shutter width
+        * ourselves in the driver based on vertical blanking and frame width */
+       mt9t031->autoexposure = 1;
+
+       mt9t031->xskip = 1;
+       mt9t031->yskip = 1;
+
+       ret = soc_camera_device_register(icd);
+       if (ret)
+               goto eisdr;
+
+       return 0;
+
+eisdr:
+       i2c_set_clientdata(client, NULL);
+       kfree(mt9t031);
+       return ret;
+}
+
+static int mt9t031_remove(struct i2c_client *client)
+{
+       struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
+
+       soc_camera_device_unregister(&mt9t031->icd);
+       i2c_set_clientdata(client, NULL);
+       kfree(mt9t031);
+
+       return 0;
+}
+
+static const struct i2c_device_id mt9t031_id[] = {
+       { "mt9t031", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t031_id);
+
+static struct i2c_driver mt9t031_i2c_driver = {
+       .driver = {
+               .name = "mt9t031",
+       },
+       .probe          = mt9t031_probe,
+       .remove         = mt9t031_remove,
+       .id_table       = mt9t031_id,
+};
+
+static int __init mt9t031_mod_init(void)
+{
+       return i2c_add_driver(&mt9t031_i2c_driver);
+}
+
+static void __exit mt9t031_mod_exit(void)
+{
+       i2c_del_driver(&mt9t031_i2c_driver);
+}
+
+module_init(mt9t031_mod_init);
+module_exit(mt9t031_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9T031 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
index 2584201059d8570efff3d72a59325e9a11a9d82a..14a5f9c21ffa22d76cd10e76f52825fe5d9f9a33 100644 (file)
@@ -273,6 +273,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
        unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
        int ret;
        u16 pixclk = 0;
@@ -296,6 +297,8 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
        }
 
+       flags = soc_camera_apply_sensor_flags(icl, flags);
+
        if (flags & SOCAM_PCLK_SAMPLE_RISING)
                pixclk |= 0x10;
 
@@ -337,14 +340,14 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
                width_flag;
 }
 
-static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
-               __u32 pixfmt, struct v4l2_rect *rect)
+static int mt9v022_set_fmt(struct soc_camera_device *icd,
+                          __u32 pixfmt, struct v4l2_rect *rect)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
        int ret;
 
        /* The caller provides a supported format, as verified per call to
-        * icd->try_fmt_cap(), datawidth is from our supported format list */
+        * icd->try_fmt(), datawidth is from our supported format list */
        switch (pixfmt) {
        case V4L2_PIX_FMT_GREY:
        case V4L2_PIX_FMT_Y16:
@@ -400,18 +403,20 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
        return 0;
 }
 
-static int mt9v022_try_fmt_cap(struct soc_camera_device *icd,
-                              struct v4l2_format *f)
+static int mt9v022_try_fmt(struct soc_camera_device *icd,
+                          struct v4l2_format *f)
 {
-       if (f->fmt.pix.height < 32 + icd->y_skip_top)
-               f->fmt.pix.height = 32 + icd->y_skip_top;
-       if (f->fmt.pix.height > 480 + icd->y_skip_top)
-               f->fmt.pix.height = 480 + icd->y_skip_top;
-       if (f->fmt.pix.width < 48)
-               f->fmt.pix.width = 48;
-       if (f->fmt.pix.width > 752)
-               f->fmt.pix.width = 752;
-       f->fmt.pix.width &= ~0x03; /* ? */
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       if (pix->height < 32 + icd->y_skip_top)
+               pix->height = 32 + icd->y_skip_top;
+       if (pix->height > 480 + icd->y_skip_top)
+               pix->height = 480 + icd->y_skip_top;
+       if (pix->width < 48)
+               pix->width = 48;
+       if (pix->width > 752)
+               pix->width = 752;
+       pix->width &= ~0x03; /* ? */
 
        return 0;
 }
@@ -538,8 +543,8 @@ static struct soc_camera_ops mt9v022_ops = {
        .release                = mt9v022_release,
        .start_capture          = mt9v022_start_capture,
        .stop_capture           = mt9v022_stop_capture,
-       .set_fmt_cap            = mt9v022_set_fmt_cap,
-       .try_fmt_cap            = mt9v022_try_fmt_cap,
+       .set_fmt                = mt9v022_set_fmt,
+       .try_fmt                = mt9v022_try_fmt,
        .set_bus_param          = mt9v022_set_bus_param,
        .query_bus_param        = mt9v022_query_bus_param,
        .controls               = mt9v022_controls,
@@ -690,6 +695,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
 static int mt9v022_video_probe(struct soc_camera_device *icd)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
        s32 data;
        int ret;
 
@@ -725,7 +731,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
                icd->formats = mt9v022_colour_formats;
-               if (mt9v022->client->dev.platform_data)
+               if (gpio_is_valid(icl->gpio))
                        icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
                else
                        icd->num_formats = 1;
@@ -733,7 +739,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
                icd->formats = mt9v022_monochrome_formats;
-               if (mt9v022->client->dev.platform_data)
+               if (gpio_is_valid(icl->gpio))
                        icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
                else
                        icd->num_formats = 1;
@@ -760,8 +766,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
 
        dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
-               mt9v022->icd.dev.parent, mt9v022->icd.vdev);
-       soc_camera_video_stop(&mt9v022->icd);
+               icd->dev.parent, icd->vdev);
+       soc_camera_video_stop(icd);
 }
 
 static int mt9v022_probe(struct i2c_client *client,
diff --git a/drivers/media/video/omap24xxcam-dma.c b/drivers/media/video/omap24xxcam-dma.c
new file mode 100644 (file)
index 0000000..1d54b86
--- /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(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",
+                      __func__);
+               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..85c3c7c
--- /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(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(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->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,
+               .owner = THIS_MODULE,
+       },
+};
+
+/*
+ *
+ * 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..2ce67f5
--- /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(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
index 210f1240b331ccc8dff41094df4d138a5a3ebb8b..6ee9b69cc4a90585c7daa10b27bcc0136f43bfa8 100644 (file)
@@ -4011,8 +4011,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
 
 /* Do not call this function directly! */
 static int
-ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = file->private_data;
        struct usb_ov511 *ov = video_get_drvdata(vdev);
@@ -4461,7 +4460,7 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
        if (mutex_lock_interruptible(&ov->lock))
                return -EINTR;
 
-       rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
+       rc = video_usercopy(file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
        mutex_unlock(&ov->lock);
        return rc;
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
new file mode 100644 (file)
index 0000000..54b736f
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * ov772x Camera Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/soc_camera.h>
+#include <media/ov772x.h>
+
+/*
+ * register offset
+ */
+#define GAIN        0x00 /* AGC - Gain control gain setting */
+#define BLUE        0x01 /* AWB - Blue channel gain setting */
+#define RED         0x02 /* AWB - Red   channel gain setting */
+#define GREEN       0x03 /* AWB - Green channel gain setting */
+#define COM1        0x04 /* Common control 1 */
+#define BAVG        0x05 /* U/B Average Level */
+#define GAVG        0x06 /* Y/Gb Average Level */
+#define RAVG        0x07 /* V/R Average Level */
+#define AECH        0x08 /* Exposure Value - AEC MSBs */
+#define COM2        0x09 /* Common control 2 */
+#define PID         0x0A /* Product ID Number MSB */
+#define VER         0x0B /* Product ID Number LSB */
+#define COM3        0x0C /* Common control 3 */
+#define COM4        0x0D /* Common control 4 */
+#define COM5        0x0E /* Common control 5 */
+#define COM6        0x0F /* Common control 6 */
+#define AEC         0x10 /* Exposure Value */
+#define CLKRC       0x11 /* Internal clock */
+#define COM7        0x12 /* Common control 7 */
+#define COM8        0x13 /* Common control 8 */
+#define COM9        0x14 /* Common control 9 */
+#define COM10       0x15 /* Common control 10 */
+#define REG16       0x16 /* Register 16 */
+#define HSTART      0x17 /* Horizontal sensor size */
+#define HSIZE       0x18 /* Horizontal frame (HREF column) end high 8-bit */
+#define VSTART      0x19 /* Vertical frame (row) start high 8-bit */
+#define VSIZE       0x1A /* Vertical sensor size */
+#define PSHFT       0x1B /* Data format - pixel delay select */
+#define MIDH        0x1C /* Manufacturer ID byte - high */
+#define MIDL        0x1D /* Manufacturer ID byte - low  */
+#define LAEC        0x1F /* Fine AEC value */
+#define COM11       0x20 /* Common control 11 */
+#define BDBASE      0x22 /* Banding filter Minimum AEC value */
+#define DBSTEP      0x23 /* Banding filter Maximum Setp */
+#define AEW         0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB         0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VPT         0x26 /* AGC/AEC Fast mode operating region */
+#define REG28       0x28 /* Register 28 */
+#define HOUTSIZE    0x29 /* Horizontal data output size MSBs */
+#define EXHCH       0x2A /* Dummy pixel insert MSB */
+#define EXHCL       0x2B /* Dummy pixel insert LSB */
+#define VOUTSIZE    0x2C /* Vertical data output size MSBs */
+#define ADVFL       0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADVFH       0x2E /* MSG of insert dummy lines in Vertical direction */
+#define YAVE        0x2F /* Y/G Channel Average value */
+#define LUMHTH      0x30 /* Histogram AEC/AGC Luminance high level threshold */
+#define LUMLTH      0x31 /* Histogram AEC/AGC Luminance low  level threshold */
+#define HREF        0x32 /* Image start and size control */
+#define DM_LNL      0x33 /* Dummy line low  8 bits */
+#define DM_LNH      0x34 /* Dummy line high 8 bits */
+#define ADOFF_B     0x35 /* AD offset compensation value for B  channel */
+#define ADOFF_R     0x36 /* AD offset compensation value for R  channel */
+#define ADOFF_GB    0x37 /* AD offset compensation value for Gb channel */
+#define ADOFF_GR    0x38 /* AD offset compensation value for Gr channel */
+#define OFF_B       0x39 /* Analog process B  channel offset value */
+#define OFF_R       0x3A /* Analog process R  channel offset value */
+#define OFF_GB      0x3B /* Analog process Gb channel offset value */
+#define OFF_GR      0x3C /* Analog process Gr channel offset value */
+#define COM12       0x3D /* Common control 12 */
+#define COM13       0x3E /* Common control 13 */
+#define COM14       0x3F /* Common control 14 */
+#define COM15       0x40 /* Common control 15*/
+#define COM16       0x41 /* Common control 16 */
+#define TGT_B       0x42 /* BLC blue channel target value */
+#define TGT_R       0x43 /* BLC red  channel target value */
+#define TGT_GB      0x44 /* BLC Gb   channel target value */
+#define TGT_GR      0x45 /* BLC Gr   channel target value */
+/* for ov7720 */
+#define LCC0        0x46 /* Lens correction control 0 */
+#define LCC1        0x47 /* Lens correction option 1 - X coordinate */
+#define LCC2        0x48 /* Lens correction option 2 - Y coordinate */
+#define LCC3        0x49 /* Lens correction option 3 */
+#define LCC4        0x4A /* Lens correction option 4 - radius of the circular */
+#define LCC5        0x4B /* Lens correction option 5 */
+#define LCC6        0x4C /* Lens correction option 6 */
+/* for ov7725 */
+#define LC_CTR      0x46 /* Lens correction control */
+#define LC_XC       0x47 /* X coordinate of lens correction center relative */
+#define LC_YC       0x48 /* Y coordinate of lens correction center relative */
+#define LC_COEF     0x49 /* Lens correction coefficient */
+#define LC_RADI     0x4A /* Lens correction radius */
+#define LC_COEFB    0x4B /* Lens B channel compensation coefficient */
+#define LC_COEFR    0x4C /* Lens R channel compensation coefficient */
+
+#define FIXGAIN     0x4D /* Analog fix gain amplifer */
+#define AREF0       0x4E /* Sensor reference control */
+#define AREF1       0x4F /* Sensor reference current control */
+#define AREF2       0x50 /* Analog reference control */
+#define AREF3       0x51 /* ADC    reference control */
+#define AREF4       0x52 /* ADC    reference control */
+#define AREF5       0x53 /* ADC    reference control */
+#define AREF6       0x54 /* Analog reference control */
+#define AREF7       0x55 /* Analog reference control */
+#define UFIX        0x60 /* U channel fixed value output */
+#define VFIX        0x61 /* V channel fixed value output */
+#define AWBB_BLK    0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0   0x63 /* AWB control byte 0 */
+#define DSP_CTRL1   0x64 /* DSP control byte 1 */
+#define DSP_CTRL2   0x65 /* DSP control byte 2 */
+#define DSP_CTRL3   0x66 /* DSP control byte 3 */
+#define DSP_CTRL4   0x67 /* DSP control byte 4 */
+#define AWB_BIAS    0x68 /* AWB BLC level clip */
+#define AWB_CTRL1   0x69 /* AWB control  1 */
+#define AWB_CTRL2   0x6A /* AWB control  2 */
+#define AWB_CTRL3   0x6B /* AWB control  3 */
+#define AWB_CTRL4   0x6C /* AWB control  4 */
+#define AWB_CTRL5   0x6D /* AWB control  5 */
+#define AWB_CTRL6   0x6E /* AWB control  6 */
+#define AWB_CTRL7   0x6F /* AWB control  7 */
+#define AWB_CTRL8   0x70 /* AWB control  8 */
+#define AWB_CTRL9   0x71 /* AWB control  9 */
+#define AWB_CTRL10  0x72 /* AWB control 10 */
+#define AWB_CTRL11  0x73 /* AWB control 11 */
+#define AWB_CTRL12  0x74 /* AWB control 12 */
+#define AWB_CTRL13  0x75 /* AWB control 13 */
+#define AWB_CTRL14  0x76 /* AWB control 14 */
+#define AWB_CTRL15  0x77 /* AWB control 15 */
+#define AWB_CTRL16  0x78 /* AWB control 16 */
+#define AWB_CTRL17  0x79 /* AWB control 17 */
+#define AWB_CTRL18  0x7A /* AWB control 18 */
+#define AWB_CTRL19  0x7B /* AWB control 19 */
+#define AWB_CTRL20  0x7C /* AWB control 20 */
+#define AWB_CTRL21  0x7D /* AWB control 21 */
+#define GAM1        0x7E /* Gamma Curve  1st segment input end point */
+#define GAM2        0x7F /* Gamma Curve  2nd segment input end point */
+#define GAM3        0x80 /* Gamma Curve  3rd segment input end point */
+#define GAM4        0x81 /* Gamma Curve  4th segment input end point */
+#define GAM5        0x82 /* Gamma Curve  5th segment input end point */
+#define GAM6        0x83 /* Gamma Curve  6th segment input end point */
+#define GAM7        0x84 /* Gamma Curve  7th segment input end point */
+#define GAM8        0x85 /* Gamma Curve  8th segment input end point */
+#define GAM9        0x86 /* Gamma Curve  9th segment input end point */
+#define GAM10       0x87 /* Gamma Curve 10th segment input end point */
+#define GAM11       0x88 /* Gamma Curve 11th segment input end point */
+#define GAM12       0x89 /* Gamma Curve 12th segment input end point */
+#define GAM13       0x8A /* Gamma Curve 13th segment input end point */
+#define GAM14       0x8B /* Gamma Curve 14th segment input end point */
+#define GAM15       0x8C /* Gamma Curve 15th segment input end point */
+#define SLOP        0x8D /* Gamma curve highest segment slope */
+#define DNSTH       0x8E /* De-noise threshold */
+#define EDGE0       0x8F /* Edge enhancement control 0 */
+#define EDGE1       0x90 /* Edge enhancement control 1 */
+#define DNSOFF      0x91 /* Auto De-noise threshold control */
+#define EDGE2       0x92 /* Edge enhancement strength low  point control */
+#define EDGE3       0x93 /* Edge enhancement strength high point control */
+#define MTX1        0x94 /* Matrix coefficient 1 */
+#define MTX2        0x95 /* Matrix coefficient 2 */
+#define MTX3        0x96 /* Matrix coefficient 3 */
+#define MTX4        0x97 /* Matrix coefficient 4 */
+#define MTX5        0x98 /* Matrix coefficient 5 */
+#define MTX6        0x99 /* Matrix coefficient 6 */
+#define MTX_CTRL    0x9A /* Matrix control */
+#define BRIGHT      0x9B /* Brightness control */
+#define CNTRST      0x9C /* Contrast contrast */
+#define CNTRST_CTRL 0x9D /* Contrast contrast center */
+#define UVAD_J0     0x9E /* Auto UV adjust contrast 0 */
+#define UVAD_J1     0x9F /* Auto UV adjust contrast 1 */
+#define SCAL0       0xA0 /* Scaling control 0 */
+#define SCAL1       0xA1 /* Scaling control 1 */
+#define SCAL2       0xA2 /* Scaling control 2 */
+#define FIFODLYM    0xA3 /* FIFO manual mode delay control */
+#define FIFODLYA    0xA4 /* FIFO auto   mode delay control */
+#define SDE         0xA6 /* Special digital effect control */
+#define USAT        0xA7 /* U component saturation control */
+#define VSAT        0xA8 /* V component saturation control */
+/* for ov7720 */
+#define HUE0        0xA9 /* Hue control 0 */
+#define HUE1        0xAA /* Hue control 1 */
+/* for ov7725 */
+#define HUECOS      0xA9 /* Cosine value */
+#define HUESIN      0xAA /* Sine value */
+
+#define SIGN        0xAB /* Sign bit for Hue and contrast */
+#define DSPAUTO     0xAC /* DSP auto function ON/OFF control */
+
+/*
+ * register detail
+ */
+
+/* COM2 */
+#define SOFT_SLEEP_MODE 0x10   /* Soft sleep mode */
+                               /* Output drive capability */
+#define OCAP_1x         0x00   /* 1x */
+#define OCAP_2x         0x01   /* 2x */
+#define OCAP_3x         0x02   /* 3x */
+#define OCAP_4x         0x03   /* 4x */
+
+/* COM3 */
+#define SWAP_MASK       0x38
+
+#define VFIMG_ON_OFF    0x80   /* Vertical flip image ON/OFF selection */
+#define HMIMG_ON_OFF    0x40   /* Horizontal mirror image ON/OFF selection */
+#define SWAP_RGB        0x20   /* Swap B/R  output sequence in RGB mode */
+#define SWAP_YUV        0x10   /* Swap Y/UV output sequence in YUV mode */
+#define SWAP_ML         0x08   /* Swap output MSB/LSB */
+                               /* Tri-state option for output clock */
+#define NOTRI_CLOCK     0x04   /*   0: Tri-state    at this period */
+                               /*   1: No tri-state at this period */
+                               /* Tri-state option for output data */
+#define NOTRI_DATA      0x02   /*   0: Tri-state    at this period */
+                               /*   1: No tri-state at this period */
+#define SCOLOR_TEST     0x01   /* Sensor color bar test pattern */
+
+/* COM4 */
+                               /* PLL frequency control */
+#define PLL_BYPASS      0x00   /*  00: Bypass PLL */
+#define PLL_4x          0x40   /*  01: PLL 4x */
+#define PLL_6x          0x80   /*  10: PLL 6x */
+#define PLL_8x          0xc0   /*  11: PLL 8x */
+                               /* AEC evaluate window */
+#define AEC_FULL        0x00   /*  00: Full window */
+#define AEC_1p2         0x10   /*  01: 1/2  window */
+#define AEC_1p4         0x20   /*  10: 1/4  window */
+#define AEC_2p3         0x30   /*  11: Low 2/3 window */
+
+/* COM5 */
+#define AFR_ON_OFF      0x80   /* Auto frame rate control ON/OFF selection */
+#define AFR_SPPED       0x40   /* Auto frame rate control speed slection */
+                               /* Auto frame rate max rate control */
+#define AFR_NO_RATE     0x00   /*     No  reduction of frame rate */
+#define AFR_1p2         0x10   /*     Max reduction to 1/2 frame rate */
+#define AFR_1p4         0x20   /*     Max reduction to 1/4 frame rate */
+#define AFR_1p8         0x30   /* Max reduction to 1/8 frame rate */
+                               /* Auto frame rate active point control */
+#define AF_2x           0x00   /*     Add frame when AGC reaches  2x gain */
+#define AF_4x           0x04   /*     Add frame when AGC reaches  4x gain */
+#define AF_8x           0x08   /*     Add frame when AGC reaches  8x gain */
+#define AF_16x          0x0c   /* Add frame when AGC reaches 16x gain */
+                               /* AEC max step control */
+#define AEC_NO_LIMIT    0x01   /*   0 : AEC incease step has limit */
+                               /*   1 : No limit to AEC increase step */
+
+/* COM7 */
+                               /* SCCB Register Reset */
+#define SCCB_RESET      0x80   /*   0 : No change */
+                               /*   1 : Resets all registers to default */
+                               /* Resolution selection */
+#define SLCT_MASK       0x40   /*   Mask of VGA or QVGA */
+#define SLCT_VGA        0x00   /*   0 : VGA */
+#define SLCT_QVGA       0x40   /*   1 : QVGA */
+#define ITU656_ON_OFF   0x20   /* ITU656 protocol ON/OFF selection */
+                               /* RGB output format control */
+#define FMT_GBR422      0x00   /*      00 : GBR 4:2:2 */
+#define FMT_RGB565      0x04   /*      01 : RGB 565 */
+#define FMT_RGB555      0x08   /*      10 : RGB 555 */
+#define FMT_RGB444      0x0c   /* 11 : RGB 444 */
+                               /* Output format control */
+#define OFMT_YUV        0x00   /*      00 : YUV */
+#define OFMT_P_BRAW     0x01   /*      01 : Processed Bayer RAW */
+#define OFMT_RGB        0x02   /*      10 : RGB */
+#define OFMT_BRAW       0x03   /* 11 : Bayer RAW */
+
+/* COM8 */
+#define FAST_ALGO       0x80   /* Enable fast AGC/AEC algorithm */
+                               /* AEC Setp size limit */
+#define UNLMT_STEP      0x40   /*   0 : Step size is limited */
+                               /*   1 : Unlimited step size */
+#define BNDF_ON_OFF     0x20   /* Banding filter ON/OFF */
+#define AEC_BND         0x10   /* Enable AEC below banding value */
+#define AEC_ON_OFF      0x08   /* Fine AEC ON/OFF control */
+#define AGC_ON          0x04   /* AGC Enable */
+#define AWB_ON          0x02   /* AWB Enable */
+#define AEC_ON          0x01   /* AEC Enable */
+
+/* COM9 */
+#define BASE_AECAGC     0x80   /* Histogram or average based AEC/AGC */
+                               /* Automatic gain ceiling - maximum AGC value */
+#define GAIN_2x         0x00   /*    000 :   2x */
+#define GAIN_4x         0x10   /*    001 :   4x */
+#define GAIN_8x         0x20   /*    010 :   8x */
+#define GAIN_16x        0x30   /* 011 :  16x */
+#define GAIN_32x        0x40   /*    100 :  32x */
+#define GAIN_64x        0x50   /* 101 :  64x */
+#define GAIN_128x       0x60   /* 110 : 128x */
+#define DROP_VSYNC      0x04   /* Drop VSYNC output of corrupt frame */
+#define DROP_HREF       0x02   /* Drop HREF  output of corrupt frame */
+
+/* COM11 */
+#define SGLF_ON_OFF     0x02   /* Single frame ON/OFF selection */
+#define SGLF_TRIG       0x01   /* Single frame transfer trigger */
+
+/* EXHCH */
+#define VSIZE_LSB       0x04   /* Vertical data output size LSB */
+
+/* DSP_CTRL1 */
+#define FIFO_ON         0x80   /* FIFO enable/disable selection */
+#define UV_ON_OFF       0x40   /* UV adjust function ON/OFF selection */
+#define YUV444_2_422    0x20   /* YUV444 to 422 UV channel option selection */
+#define CLR_MTRX_ON_OFF 0x10   /* Color matrix ON/OFF selection */
+#define INTPLT_ON_OFF   0x08   /* Interpolation ON/OFF selection */
+#define GMM_ON_OFF      0x04   /* Gamma function ON/OFF selection */
+#define AUTO_BLK_ON_OFF 0x02   /* Black defect auto correction ON/OFF */
+#define AUTO_WHT_ON_OFF 0x01   /* White define auto correction ON/OFF */
+
+/* DSP_CTRL3 */
+#define UV_MASK         0x80   /* UV output sequence option */
+#define UV_ON           0x80   /*   ON */
+#define UV_OFF          0x00   /*   OFF */
+#define CBAR_MASK       0x20   /* DSP Color bar mask */
+#define CBAR_ON         0x20   /*   ON */
+#define CBAR_OFF        0x00   /*   OFF */
+
+/* HSTART */
+#define HST_VGA         0x23
+#define HST_QVGA        0x3F
+
+/* HSIZE */
+#define HSZ_VGA         0xA0
+#define HSZ_QVGA        0x50
+
+/* VSTART */
+#define VST_VGA         0x07
+#define VST_QVGA        0x03
+
+/* VSIZE */
+#define VSZ_VGA         0xF0
+#define VSZ_QVGA        0x78
+
+/* HOUTSIZE */
+#define HOSZ_VGA        0xA0
+#define HOSZ_QVGA       0x50
+
+/* VOUTSIZE */
+#define VOSZ_VGA        0xF0
+#define VOSZ_QVGA       0x78
+
+/*
+ * bit configure (32 bit)
+ * this is used in struct ov772x_color_format :: option
+ */
+#define OP_UV       0x00000001
+#define OP_SWAP_RGB 0x00000002
+
+/*
+ * ID
+ */
+#define OV7720  0x7720
+#define OV7725  0x7721
+#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
+
+/*
+ * struct
+ */
+struct regval_list {
+       unsigned char reg_num;
+       unsigned char value;
+};
+
+struct ov772x_color_format {
+       char                     *name;
+       __u32                     fourcc;
+       const struct regval_list *regs;
+       unsigned int              option;
+};
+
+struct ov772x_win_size {
+       char                     *name;
+       __u32                     width;
+       __u32                     height;
+       unsigned char             com7_bit;
+       const struct regval_list *regs;
+};
+
+struct ov772x_priv {
+       struct ov772x_camera_info        *info;
+       struct i2c_client                *client;
+       struct soc_camera_device          icd;
+       const struct ov772x_color_format *fmt;
+       const struct ov772x_win_size     *win;
+       int                               model;
+};
+
+#define ENDMARKER { 0xff, 0xff }
+
+/*
+ * register setting for color format
+ */
+static const struct regval_list ov772x_RGB555_regs[] = {
+       { COM3, 0x00 },
+       { COM7, FMT_RGB555 | OFMT_RGB },
+       ENDMARKER,
+};
+
+static const struct regval_list ov772x_RGB565_regs[] = {
+       { COM3, 0x00 },
+       { COM7, FMT_RGB565 | OFMT_RGB },
+       ENDMARKER,
+};
+
+static const struct regval_list ov772x_YYUV_regs[] = {
+       { COM3, SWAP_YUV },
+       { COM7, OFMT_YUV },
+       ENDMARKER,
+};
+
+static const struct regval_list ov772x_UVYY_regs[] = {
+       { COM3, 0x00 },
+       { COM7, OFMT_YUV },
+       ENDMARKER,
+};
+
+
+/*
+ * register setting for window size
+ */
+static const struct regval_list ov772x_qvga_regs[] = {
+       { HSTART,   HST_QVGA },
+       { HSIZE,    HSZ_QVGA },
+       { VSTART,   VST_QVGA },
+       { VSIZE,    VSZ_QVGA  },
+       { HOUTSIZE, HOSZ_QVGA },
+       { VOUTSIZE, VOSZ_QVGA },
+       ENDMARKER,
+};
+
+static const struct regval_list ov772x_vga_regs[] = {
+       { HSTART,   HST_VGA },
+       { HSIZE,    HSZ_VGA },
+       { VSTART,   VST_VGA },
+       { VSIZE,    VSZ_VGA },
+       { HOUTSIZE, HOSZ_VGA },
+       { VOUTSIZE, VOSZ_VGA },
+       ENDMARKER,
+};
+
+/*
+ * supported format list
+ */
+
+#define SETFOURCC(type) .name = (#type), .fourcc = (V4L2_PIX_FMT_ ## type)
+static const struct soc_camera_data_format ov772x_fmt_lists[] = {
+       {
+               SETFOURCC(YUYV),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               SETFOURCC(YVYU),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               SETFOURCC(UYVY),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               SETFOURCC(RGB555),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       },
+       {
+               SETFOURCC(RGB555X),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       },
+       {
+               SETFOURCC(RGB565),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       },
+       {
+               SETFOURCC(RGB565X),
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+       },
+};
+
+/*
+ * color format list
+ */
+#define T_YUYV 0
+static const struct ov772x_color_format ov772x_cfmts[] = {
+       [T_YUYV] = {
+               SETFOURCC(YUYV),
+               .regs   = ov772x_YYUV_regs,
+       },
+       {
+               SETFOURCC(YVYU),
+               .regs   = ov772x_YYUV_regs,
+               .option = OP_UV,
+       },
+       {
+               SETFOURCC(UYVY),
+               .regs   = ov772x_UVYY_regs,
+       },
+       {
+               SETFOURCC(RGB555),
+               .regs   = ov772x_RGB555_regs,
+               .option = OP_SWAP_RGB,
+       },
+       {
+               SETFOURCC(RGB555X),
+               .regs   = ov772x_RGB555_regs,
+       },
+       {
+               SETFOURCC(RGB565),
+               .regs   = ov772x_RGB565_regs,
+               .option = OP_SWAP_RGB,
+       },
+       {
+               SETFOURCC(RGB565X),
+               .regs   = ov772x_RGB565_regs,
+       },
+};
+
+
+/*
+ * window size list
+ */
+#define VGA_WIDTH   640
+#define VGA_HEIGHT  480
+#define QVGA_WIDTH  320
+#define QVGA_HEIGHT 240
+#define MAX_WIDTH   VGA_WIDTH
+#define MAX_HEIGHT  VGA_HEIGHT
+
+static const struct ov772x_win_size ov772x_win_vga = {
+       .name     = "VGA",
+       .width    = VGA_WIDTH,
+       .height   = VGA_HEIGHT,
+       .com7_bit = SLCT_VGA,
+       .regs     = ov772x_vga_regs,
+};
+
+static const struct ov772x_win_size ov772x_win_qvga = {
+       .name     = "QVGA",
+       .width    = QVGA_WIDTH,
+       .height   = QVGA_HEIGHT,
+       .com7_bit = SLCT_QVGA,
+       .regs     = ov772x_qvga_regs,
+};
+
+
+/*
+ * general function
+ */
+
+static int ov772x_write_array(struct i2c_client        *client,
+                             const struct regval_list *vals)
+{
+       while (vals->reg_num != 0xff) {
+               int ret = i2c_smbus_write_byte_data(client,
+                                                   vals->reg_num,
+                                                   vals->value);
+               if (ret < 0)
+                       return ret;
+               vals++;
+       }
+       return 0;
+}
+
+static int ov772x_mask_set(struct i2c_client *client,
+                                         u8  command,
+                                         u8  mask,
+                                         u8  set)
+{
+       s32 val = i2c_smbus_read_byte_data(client, command);
+       val &= ~mask;
+       val |=  set;
+
+       return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static int ov772x_reset(struct i2c_client *client)
+{
+       int ret = i2c_smbus_write_byte_data(client, COM7, SCCB_RESET);
+       msleep(1);
+       return ret;
+}
+
+/*
+ * soc_camera_ops function
+ */
+
+static int ov772x_init(struct soc_camera_device *icd)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       int ret = 0;
+
+       if (priv->info->link.power) {
+               ret = priv->info->link.power(&priv->client->dev, 1);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (priv->info->link.reset)
+               ret = priv->info->link.reset(&priv->client->dev);
+
+       return ret;
+}
+
+static int ov772x_release(struct soc_camera_device *icd)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       int ret = 0;
+
+       if (priv->info->link.power)
+               ret = priv->info->link.power(&priv->client->dev, 0);
+
+       return ret;
+}
+
+static int ov772x_start_capture(struct soc_camera_device *icd)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       int                 ret;
+
+       if (!priv->win)
+               priv->win = &ov772x_win_vga;
+       if (!priv->fmt)
+               priv->fmt = &ov772x_cfmts[T_YUYV];
+
+       /*
+        * reset hardware
+        */
+       ov772x_reset(priv->client);
+
+       /*
+        * set color format
+        */
+       ret = ov772x_write_array(priv->client, priv->fmt->regs);
+       if (ret < 0)
+               goto start_end;
+
+       /*
+        * set size format
+        */
+       ret = ov772x_write_array(priv->client, priv->win->regs);
+       if (ret < 0)
+               goto start_end;
+
+       /*
+        * set COM7 bit ( QVGA or VGA )
+        */
+       ret = ov772x_mask_set(priv->client,
+                             COM7, SLCT_MASK, priv->win->com7_bit);
+       if (ret < 0)
+               goto start_end;
+
+       /*
+        * set UV setting
+        */
+       if (priv->fmt->option & OP_UV) {
+               ret = ov772x_mask_set(priv->client,
+                                     DSP_CTRL3, UV_MASK, UV_ON);
+               if (ret < 0)
+                       goto start_end;
+       }
+
+       /*
+        * set SWAP setting
+        */
+       if (priv->fmt->option & OP_SWAP_RGB) {
+               ret = ov772x_mask_set(priv->client,
+                                     COM3, SWAP_MASK, SWAP_RGB);
+               if (ret < 0)
+                       goto start_end;
+       }
+
+       dev_dbg(&icd->dev,
+                "format %s, win %s\n", priv->fmt->name, priv->win->name);
+
+start_end:
+       priv->fmt = NULL;
+       priv->win = NULL;
+
+       return ret;
+}
+
+static int ov772x_stop_capture(struct soc_camera_device *icd)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       ov772x_reset(priv->client);
+       return 0;
+}
+
+static int ov772x_set_bus_param(struct soc_camera_device *icd,
+                               unsigned long             flags)
+{
+       return 0;
+}
+
+static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       struct soc_camera_link *icl = priv->client->dev.platform_data;
+       unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+               priv->info->buswidth;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int ov772x_get_chip_id(struct soc_camera_device *icd,
+                             struct v4l2_chip_ident   *id)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+       id->ident    = priv->model;
+       id->revision = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov772x_get_register(struct soc_camera_device *icd,
+                              struct v4l2_register *reg)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       int                 ret;
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+       if (ret < 0)
+               return ret;
+
+       reg->val = (__u64)ret;
+
+       return 0;
+}
+
+static int ov772x_set_register(struct soc_camera_device *icd,
+                              struct v4l2_register *reg)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+       if (reg->reg > 0xff ||
+           reg->val > 0xff)
+               return -EINVAL;
+
+       return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+}
+#endif
+
+static const struct ov772x_win_size*
+ov772x_select_win(u32 width, u32 height)
+{
+       __u32 diff;
+       const struct ov772x_win_size *win;
+
+       /* default is QVGA */
+       diff = abs(width - ov772x_win_qvga.width) +
+               abs(height - ov772x_win_qvga.height);
+       win = &ov772x_win_qvga;
+
+       /* VGA */
+       if (diff >
+           abs(width  - ov772x_win_vga.width) +
+           abs(height - ov772x_win_vga.height))
+               win = &ov772x_win_vga;
+
+       return win;
+}
+
+
+static int ov772x_set_fmt(struct soc_camera_device *icd,
+                         __u32                     pixfmt,
+                         struct v4l2_rect         *rect)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       int ret = -EINVAL;
+       int i;
+
+       /*
+        * select format
+        */
+       priv->fmt = NULL;
+       for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
+               if (pixfmt == ov772x_cfmts[i].fourcc) {
+                       priv->fmt = ov772x_cfmts + i;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       /*
+        * select win
+        */
+       priv->win = ov772x_select_win(rect->width, rect->height);
+
+       return ret;
+}
+
+static int ov772x_try_fmt(struct soc_camera_device *icd,
+                         struct v4l2_format       *f)
+{
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       const struct ov772x_win_size *win;
+
+       /*
+        * select suitable win
+        */
+       win = ov772x_select_win(pix->width, pix->height);
+
+       pix->width  = win->width;
+       pix->height = win->height;
+       pix->field  = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov772x_video_probe(struct soc_camera_device *icd)
+{
+       struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+       u8                  pid, ver;
+       const char         *devname;
+
+       /*
+        * We must have a parent by now. And it cannot be a wrong one.
+        * So this entire test is completely redundant.
+        */
+       if (!icd->dev.parent ||
+           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+               return -ENODEV;
+
+       /*
+        * ov772x only use 8 or 10 bit bus width
+        */
+       if (SOCAM_DATAWIDTH_10 != priv->info->buswidth &&
+           SOCAM_DATAWIDTH_8  != priv->info->buswidth) {
+               dev_err(&icd->dev, "bus width error\n");
+               return -ENODEV;
+       }
+
+       icd->formats     = ov772x_fmt_lists;
+       icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists);
+
+       /*
+        * check and show product ID and manufacturer ID
+        */
+       pid = i2c_smbus_read_byte_data(priv->client, PID);
+       ver = i2c_smbus_read_byte_data(priv->client, VER);
+
+       switch (VERSION(pid, ver)) {
+       case OV7720:
+               devname     = "ov7720";
+               priv->model = V4L2_IDENT_OV7720;
+               break;
+       case OV7725:
+               devname     = "ov7725";
+               priv->model = V4L2_IDENT_OV7725;
+               break;
+       default:
+               dev_err(&icd->dev,
+                       "Product ID error %x:%x\n", pid, ver);
+               return -ENODEV;
+       }
+
+       dev_info(&icd->dev,
+                "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+                devname,
+                pid,
+                ver,
+                i2c_smbus_read_byte_data(priv->client, MIDH),
+                i2c_smbus_read_byte_data(priv->client, MIDL));
+
+
+       return soc_camera_video_start(icd);
+}
+
+static void ov772x_video_remove(struct soc_camera_device *icd)
+{
+       soc_camera_video_stop(icd);
+}
+
+static struct soc_camera_ops ov772x_ops = {
+       .owner                  = THIS_MODULE,
+       .probe                  = ov772x_video_probe,
+       .remove                 = ov772x_video_remove,
+       .init                   = ov772x_init,
+       .release                = ov772x_release,
+       .start_capture          = ov772x_start_capture,
+       .stop_capture           = ov772x_stop_capture,
+       .set_fmt                = ov772x_set_fmt,
+       .try_fmt                = ov772x_try_fmt,
+       .set_bus_param          = ov772x_set_bus_param,
+       .query_bus_param        = ov772x_query_bus_param,
+       .get_chip_id            = ov772x_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .get_register           = ov772x_get_register,
+       .set_register           = ov772x_set_register,
+#endif
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int ov772x_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct ov772x_priv        *priv;
+       struct ov772x_camera_info *info;
+       struct soc_camera_device  *icd;
+       struct i2c_adapter        *adapter = to_i2c_adapter(client->dev.parent);
+       int                        ret;
+
+       info = client->dev.platform_data;
+       if (!info)
+               return -EINVAL;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&adapter->dev,
+                       "I2C-Adapter doesn't support "
+                       "I2C_FUNC_SMBUS_BYTE_DATA\n");
+               return -EIO;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->info   = info;
+       priv->client = client;
+       i2c_set_clientdata(client, priv);
+
+       icd             = &priv->icd;
+       icd->ops        = &ov772x_ops;
+       icd->control    = &client->dev;
+       icd->width_max  = MAX_WIDTH;
+       icd->height_max = MAX_HEIGHT;
+       icd->iface      = priv->info->link.bus_id;
+
+       ret = soc_camera_device_register(icd);
+
+       if (ret) {
+               i2c_set_clientdata(client, NULL);
+               kfree(priv);
+       }
+
+       return ret;
+}
+
+static int ov772x_remove(struct i2c_client *client)
+{
+       struct ov772x_priv *priv = i2c_get_clientdata(client);
+
+       soc_camera_device_unregister(&priv->icd);
+       i2c_set_clientdata(client, NULL);
+       kfree(priv);
+       return 0;
+}
+
+static const struct i2c_device_id ov772x_id[] = {
+       { "ov772x", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov772x_id);
+
+static struct i2c_driver ov772x_i2c_driver = {
+       .driver = {
+               .name = "ov772x",
+       },
+       .probe    = ov772x_probe,
+       .remove   = ov772x_remove,
+       .id_table = ov772x_id,
+};
+
+/*
+ * module function
+ */
+
+static int __init ov772x_module_init(void)
+{
+       return i2c_add_driver(&ov772x_i2c_driver);
+}
+
+static void __exit ov772x_module_exit(void)
+{
+       i2c_del_driver(&ov772x_i2c_driver);
+}
+
+module_init(ov772x_module_init);
+module_exit(ov772x_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov772x");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
index 994807818aa26eacd2ffc09920445d2cc69f58d9..45730fac1570b0be08e3313700e525be3d710790 100644 (file)
@@ -10,8 +10,8 @@
  *     14478 Potsdam, Germany
  *
  *     Most of this code is directly derived from his userspace driver.
- *     His driver works so send any reports to alan@redhat.com unless the
- *     userspace driver also doesn't work for you...
+ *     His driver works so send any reports to alan@lxorguk.ukuu.org.uk
+ *     unless the userspace driver also doesn't work for you...
  *
  *      Changes:
  *      08/07/2003        Daniele Bellucci <bellucda@tiscali.it>
@@ -680,8 +680,7 @@ static int pms_capture(struct pms_device *dev, char __user *buf, int rgb555, int
  *     Video4linux interfacing
  */
 
-static int pms_do_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, void *arg)
+static int pms_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
        struct pms_device *pd=(struct pms_device *)dev;
@@ -866,7 +865,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
 static int pms_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, pms_do_ioctl);
+       return video_usercopy(file, cmd, arg, pms_do_ioctl);
 }
 
 static ssize_t pms_read(struct file *file, char __user *buf,
index 5b81ba469641c89b302a777d9f41f62043609133..4358079f1966f4efa4a60eaded89e9c75e1866fd 100644 (file)
@@ -2395,7 +2395,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 
        scnprintf(hdw->bus_info,sizeof(hdw->bus_info),
                  "usb %s address %d",
-                 hdw->usb_dev->dev.bus_id,
+                 dev_name(&hdw->usb_dev->dev),
                  hdw->usb_dev->devnum);
 
        ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
index 733680f2131714a7f1642cf0f36655f28695b024..e641cd971453c2b6cb622ae1ff2c36d38cd7f831 100644 (file)
@@ -628,10 +628,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
 
        class_dev->class = &class_ptr->class;
        if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
-               snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu",
+               dev_set_name(class_dev, "sn-%lu",
                         pvr2_hdw_get_sn(sfp->channel.hdw));
        } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
-               snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c",
+               dev_set_name(class_dev, "unit-%c",
                         pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
        } else {
                kfree(class_dev);
index 97ed95957992ff9d5107ff90b1c754f3f2c6bbdc..52af1c4359655dbcd6159434e37ab02eb915b56b 100644 (file)
@@ -168,8 +168,7 @@ static const char *get_v4l_name(int v4l_type)
  * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
  *
  */
-static int __pvr2_v4l2_do_ioctl(struct file *file,
-                             unsigned int cmd, void *arg)
+static int pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct pvr2_v4l2_fh *fh = file->private_data;
        struct pvr2_v4l2 *vp = fh->vhead;
@@ -864,7 +863,7 @@ static int __pvr2_v4l2_do_ioctl(struct file *file,
 
        default :
                ret = v4l_compat_translate_ioctl(file, cmd,
-                                                arg, __pvr2_v4l2_do_ioctl);
+                                                arg, pvr2_v4l2_do_ioctl);
        }
 
        pvr2_hdw_commit_ctl(hdw);
@@ -890,12 +889,6 @@ static int __pvr2_v4l2_do_ioctl(struct file *file,
        return ret;
 }
 
-static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg)
-{
-       return __pvr2_v4l2_do_ioctl(file, cmd, arg);
-}
-
 static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
 {
        int num = dip->devbase.num;
@@ -963,7 +956,7 @@ static int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
 #define IVTV_IOC_G_CODEC        0xFFEE7703
 #define IVTV_IOC_S_CODEC        0xFFEE7704
        if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
-       return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl);
+       return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
 }
 
 
index f3897a3fdb75b3542de06f693e60e213ed642f1a..1ce9da167b7e5e8de2b4f73064386eab3eda8f99 100644 (file)
@@ -1412,7 +1412,7 @@ static int pwc_video_ioctl(struct inode *inode, struct file *file,
 
        mutex_lock(&pdev->modlock);
        if (!pdev->unplugged)
-               r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+               r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl);
        mutex_unlock(&pdev->modlock);
 out:
        return r;
index 76a1376c9751dd1c06acacc766af6676a36efe40..d7c147328e35268b6d68138cb499df52bdebe38c 100644 (file)
@@ -337,8 +337,7 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
 
 }
 
-int pwc_video_do_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, void *arg)
+int pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev;
index 74178754b39b874dc049c3fc630f78d1c97601b1..c046a253566880c115e437946ee2e38129aa89b8 100644 (file)
@@ -340,8 +340,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power);
 extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
 
 /** Functions in pwc-v4l.c */
-extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg);
+extern int pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
index eb6be580292899ed8a6b5d0fa41b204f52d9f07d..9d33de22cc48fe6670e235bec9a30fc6c05a0deb 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/version.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/mutex.h>
 #include <linux/clk.h>
 
 #include <media/v4l2-common.h>
 #include <mach/pxa-regs.h>
 #include <mach/camera.h>
 
+#include "pxa_camera.h"
+
 #define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
 #define PXA_CAM_DRV_NAME "pxa27x-camera"
 
+/* Camera Interface */
+#define CICR0          0x0000
+#define CICR1          0x0004
+#define CICR2          0x0008
+#define CICR3          0x000C
+#define CICR4          0x0010
+#define CISR           0x0014
+#define CIFR           0x0018
+#define CITOR          0x001C
+#define CIBR0          0x0028
+#define CIBR1          0x0030
+#define CIBR2          0x0038
+
+#define CICR0_DMAEN    (1 << 31)       /* DMA request enable */
+#define CICR0_PAR_EN   (1 << 30)       /* Parity enable */
+#define CICR0_SL_CAP_EN        (1 << 29)       /* Capture enable for slave mode */
+#define CICR0_ENB      (1 << 28)       /* Camera interface enable */
+#define CICR0_DIS      (1 << 27)       /* Camera interface disable */
+#define CICR0_SIM      (0x7 << 24)     /* Sensor interface mode mask */
+#define CICR0_TOM      (1 << 9)        /* Time-out mask */
+#define CICR0_RDAVM    (1 << 8)        /* Receive-data-available mask */
+#define CICR0_FEM      (1 << 7)        /* FIFO-empty mask */
+#define CICR0_EOLM     (1 << 6)        /* End-of-line mask */
+#define CICR0_PERRM    (1 << 5)        /* Parity-error mask */
+#define CICR0_QDM      (1 << 4)        /* Quick-disable mask */
+#define CICR0_CDM      (1 << 3)        /* Disable-done mask */
+#define CICR0_SOFM     (1 << 2)        /* Start-of-frame mask */
+#define CICR0_EOFM     (1 << 1)        /* End-of-frame mask */
+#define CICR0_FOM      (1 << 0)        /* FIFO-overrun mask */
+
+#define CICR1_TBIT     (1 << 31)       /* Transparency bit */
+#define CICR1_RGBT_CONV        (0x3 << 29)     /* RGBT conversion mask */
+#define CICR1_PPL      (0x7ff << 15)   /* Pixels per line mask */
+#define CICR1_RGB_CONV (0x7 << 12)     /* RGB conversion mask */
+#define CICR1_RGB_F    (1 << 11)       /* RGB format */
+#define CICR1_YCBCR_F  (1 << 10)       /* YCbCr format */
+#define CICR1_RGB_BPP  (0x7 << 7)      /* RGB bis per pixel mask */
+#define CICR1_RAW_BPP  (0x3 << 5)      /* Raw bis per pixel mask */
+#define CICR1_COLOR_SP (0x3 << 3)      /* Color space mask */
+#define CICR1_DW       (0x7 << 0)      /* Data width mask */
+
+#define CICR2_BLW      (0xff << 24)    /* Beginning-of-line pixel clock
+                                          wait count mask */
+#define CICR2_ELW      (0xff << 16)    /* End-of-line pixel clock
+                                          wait count mask */
+#define CICR2_HSW      (0x3f << 10)    /* Horizontal sync pulse width mask */
+#define CICR2_BFPW     (0x3f << 3)     /* Beginning-of-frame pixel clock
+                                          wait count mask */
+#define CICR2_FSW      (0x7 << 0)      /* Frame stabilization
+                                          wait count mask */
+
+#define CICR3_BFW      (0xff << 24)    /* Beginning-of-frame line clock
+                                          wait count mask */
+#define CICR3_EFW      (0xff << 16)    /* End-of-frame line clock
+                                          wait count mask */
+#define CICR3_VSW      (0x3f << 10)    /* Vertical sync pulse width mask */
+#define CICR3_BFPW     (0x3f << 3)     /* Beginning-of-frame pixel clock
+                                          wait count mask */
+#define CICR3_LPF      (0x7ff << 0)    /* Lines per frame mask */
+
+#define CICR4_MCLK_DLY (0x3 << 24)     /* MCLK Data Capture Delay mask */
+#define CICR4_PCLK_EN  (1 << 23)       /* Pixel clock enable */
+#define CICR4_PCP      (1 << 22)       /* Pixel clock polarity */
+#define CICR4_HSP      (1 << 21)       /* Horizontal sync polarity */
+#define CICR4_VSP      (1 << 20)       /* Vertical sync polarity */
+#define CICR4_MCLK_EN  (1 << 19)       /* MCLK enable */
+#define CICR4_FR_RATE  (0x7 << 8)      /* Frame rate mask */
+#define CICR4_DIV      (0xff << 0)     /* Clock divisor mask */
+
+#define CISR_FTO       (1 << 15)       /* FIFO time-out */
+#define CISR_RDAV_2    (1 << 14)       /* Channel 2 receive data available */
+#define CISR_RDAV_1    (1 << 13)       /* Channel 1 receive data available */
+#define CISR_RDAV_0    (1 << 12)       /* Channel 0 receive data available */
+#define CISR_FEMPTY_2  (1 << 11)       /* Channel 2 FIFO empty */
+#define CISR_FEMPTY_1  (1 << 10)       /* Channel 1 FIFO empty */
+#define CISR_FEMPTY_0  (1 << 9)        /* Channel 0 FIFO empty */
+#define CISR_EOL       (1 << 8)        /* End of line */
+#define CISR_PAR_ERR   (1 << 7)        /* Parity error */
+#define CISR_CQD       (1 << 6)        /* Camera interface quick disable */
+#define CISR_CDD       (1 << 5)        /* Camera interface disable done */
+#define CISR_SOF       (1 << 4)        /* Start of frame */
+#define CISR_EOF       (1 << 3)        /* End of frame */
+#define CISR_IFO_2     (1 << 2)        /* FIFO overrun for Channel 2 */
+#define CISR_IFO_1     (1 << 1)        /* FIFO overrun for Channel 1 */
+#define CISR_IFO_0     (1 << 0)        /* FIFO overrun for Channel 0 */
+
+#define CIFR_FLVL2     (0x7f << 23)    /* FIFO 2 level mask */
+#define CIFR_FLVL1     (0x7f << 16)    /* FIFO 1 level mask */
+#define CIFR_FLVL0     (0xff << 8)     /* FIFO 0 level mask */
+#define CIFR_THL_0     (0x3 << 4)      /* Threshold Level for Channel 0 FIFO */
+#define CIFR_RESET_F   (1 << 3)        /* Reset input FIFOs */
+#define CIFR_FEN2      (1 << 2)        /* FIFO enable for channel 2 */
+#define CIFR_FEN1      (1 << 1)        /* FIFO enable for channel 1 */
+#define CIFR_FEN0      (1 << 0)        /* FIFO enable for channel 0 */
+
 #define CICR0_SIM_MP   (0 << 24)
 #define CICR0_SIM_SP   (1 << 24)
 #define CICR0_SIM_MS   (2 << 24)
                        CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
                        CICR0_EOFM | CICR0_FOM)
 
-static DEFINE_MUTEX(camera_lock);
-
 /*
  * Structures
  */
@@ -120,7 +214,9 @@ struct pxa_camera_dev {
        struct pxacamera_platform_data *pdata;
        struct resource         *res;
        unsigned long           platform_flags;
-       unsigned long           platform_mclk_10khz;
+       unsigned long           ciclk;
+       unsigned long           mclk;
+       u32                     mclk_divisor;
 
        struct list_head        capture;
 
@@ -143,8 +239,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
                              unsigned int *size)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
 
        dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
@@ -170,8 +265,7 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int i;
@@ -247,8 +341,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                struct videobuf_buffer *vb, enum v4l2_field field)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
        int ret;
@@ -367,8 +460,7 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
                               struct videobuf_buffer *vb)
 {
        struct soc_camera_device *icd = vq->priv_data;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
        struct pxa_buffer *active;
@@ -385,7 +477,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
        active = pcdev->active;
 
        if (!active) {
-               CIFR |= CIFR_RESET_F;
+               unsigned long cifr, cicr0;
+
+               cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+               __raw_writel(cifr, pcdev->base + CIFR);
 
                for (i = 0; i < pcdev->channels; i++) {
                        DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
@@ -394,7 +489,9 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
                }
 
                pcdev->active = buf;
-               CICR0 |= CICR0_ENB;
+
+               cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB;
+               __raw_writel(cicr0, pcdev->base + CICR0);
        } else {
                struct pxa_cam_dma *buf_dma;
                struct pxa_cam_dma *act_dma;
@@ -478,6 +575,8 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
                              struct videobuf_buffer *vb,
                              struct pxa_buffer *buf)
 {
+       unsigned long cicr0;
+
        /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
        list_del_init(&vb->queue);
        vb->state = VIDEOBUF_DONE;
@@ -490,7 +589,9 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
                DCSR(pcdev->dma_chans[0]) = 0;
                DCSR(pcdev->dma_chans[1]) = 0;
                DCSR(pcdev->dma_chans[2]) = 0;
-               CICR0 &= ~CICR0_ENB;
+
+               cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
+               __raw_writel(cicr0, pcdev->base + CICR0);
                return;
        }
 
@@ -505,6 +606,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
        unsigned long flags;
        u32 status, camera_status, overrun;
        struct videobuf_buffer *vb;
+       unsigned long cifr, cicr0;
 
        spin_lock_irqsave(&pcdev->lock, flags);
 
@@ -527,22 +629,26 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                goto out;
        }
 
-       camera_status = CISR;
+       camera_status = __raw_readl(pcdev->base + CISR);
        overrun = CISR_IFO_0;
        if (pcdev->channels == 3)
                overrun |= CISR_IFO_1 | CISR_IFO_2;
        if (camera_status & overrun) {
                dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
                /* Stop the Capture Interface */
-               CICR0 &= ~CICR0_ENB;
+               cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB;
+               __raw_writel(cicr0, pcdev->base + CICR0);
+
                /* Stop DMA */
                DCSR(channel) = 0;
                /* Reset the FIFOs */
-               CIFR |= CIFR_RESET_F;
+               cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+               __raw_writel(cifr, pcdev->base + CIFR);
                /* Enable End-Of-Frame Interrupt */
-               CICR0 &= ~CICR0_EOFM;
+               cicr0 &= ~CICR0_EOFM;
+               __raw_writel(cicr0, pcdev->base + CICR0);
                /* Restart the Capture Interface */
-               CICR0 |= CICR0_ENB;
+               __raw_writel(cicr0 | CICR0_ENB, pcdev->base + CICR0);
                goto out;
        }
 
@@ -598,24 +704,43 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
                                sizeof(struct pxa_buffer), icd);
 }
 
-static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
+static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
 {
-       unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
-       unsigned long div;
+       unsigned long mclk = pcdev->mclk;
+       u32 div;
        unsigned long lcdclk;
 
-       lcdclk = clk_get_rate(pcdev->clk) / 10000;
+       lcdclk = clk_get_rate(pcdev->clk);
+       pcdev->ciclk = lcdclk;
 
-       /* We verify platform_mclk_10khz != 0, so if anyone breaks it, here
-        * they get a nice Oops */
-       div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;
+       /* mclk <= ciclk / 4 (27.4.2) */
+       if (mclk > lcdclk / 4) {
+               mclk = lcdclk / 4;
+               dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk);
+       }
+
+       /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
+       div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
 
-       dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "
-               "divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);
+       /* If we're not supplying MCLK, leave it at 0 */
+       if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+               pcdev->mclk = lcdclk / (2 * (div + 1));
+
+       dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, "
+               "divisor %u\n", lcdclk, mclk, div);
 
        return div;
 }
 
+static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
+                                    unsigned long pclk)
+{
+       /* We want a timeout > 1 pixel time, not ">=" */
+       u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1;
+
+       __raw_writel(ciclk_per_pixel, pcdev->base + CITOR);
+}
+
 static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
 {
        struct pxacamera_platform_data *pdata = pcdev->pdata;
@@ -629,7 +754,8 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
                pdata->init(pcdev->dev);
        }
 
-       CICR0 = 0x3FF;   /* disable all interrupts */
+       /* disable all interrupts */
+       __raw_writel(0x3ff, pcdev->base + CICR0);
 
        if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
                cicr4 |= CICR4_PCLK_EN;
@@ -642,7 +768,14 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
        if (pcdev->platform_flags & PXA_CAMERA_VSP)
                cicr4 |= CICR4_VSP;
 
-       CICR4 = mclk_get_divisor(pcdev) | cicr4;
+       __raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4);
+
+       if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+               /* Initialise the timeout under the assumption pclk = mclk */
+               recalculate_fifo_timeout(pcdev, pcdev->mclk);
+       else
+               /* "Safe default" - 13MHz */
+               recalculate_fifo_timeout(pcdev, 13000000);
 
        clk_enable(pcdev->clk);
 }
@@ -655,14 +788,15 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
 static irqreturn_t pxa_camera_irq(int irq, void *data)
 {
        struct pxa_camera_dev *pcdev = data;
-       unsigned int status = CISR;
+       unsigned long status, cicr0;
 
-       dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
+       status = __raw_readl(pcdev->base + CISR);
+       dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status);
 
        if (!status)
                return IRQ_NONE;
 
-       CISR = status;
+       __raw_writel(status, pcdev->base + CISR);
 
        if (status & CISR_EOF) {
                int i;
@@ -671,22 +805,24 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
                                pcdev->active->dmas[i].sg_dma;
                        DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
                }
-               CICR0 |= CICR0_EOFM;
+               cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
+               __raw_writel(cicr0, pcdev->base + CICR0);
        }
 
        return IRQ_HANDLED;
 }
 
-/* The following two functions absolutely depend on the fact, that
- * there can be only one camera on PXA quick capture interface */
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on PXA quick capture interface
+ * Called with .video_lock held
+ */
 static int pxa_camera_add_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        int ret;
 
-       mutex_lock(&camera_lock);
-
        if (pcdev->icd) {
                ret = -EBUSY;
                goto ebusy;
@@ -702,11 +838,10 @@ static int pxa_camera_add_device(struct soc_camera_device *icd)
                pcdev->icd = icd;
 
 ebusy:
-       mutex_unlock(&camera_lock);
-
        return ret;
 }
 
+/* Called with .video_lock held */
 static void pxa_camera_remove_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -718,7 +853,7 @@ static void pxa_camera_remove_device(struct soc_camera_device *icd)
                 icd->devnum);
 
        /* disable capture, disable interrupts */
-       CICR0 = 0x3ff;
+       __raw_writel(0x3ff, pcdev->base + CICR0);
 
        /* Stop DMA engine */
        DCSR(pcdev->dma_chans[0]) = 0;
@@ -765,6 +900,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
                if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
                        return -EINVAL;
                *flags |= SOCAM_DATAWIDTH_8;
+               break;
+       default:
+               return -EINVAL;
        }
 
        return 0;
@@ -772,11 +910,10 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
 
 static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
-       u32 cicr0, cicr1, cicr4 = 0;
+       u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0;
        int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
 
        if (ret < 0)
@@ -823,12 +960,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
         * We fix bit-per-pixel equal to data-width... */
        switch (common_flags & SOCAM_DATAWIDTH_MASK) {
        case SOCAM_DATAWIDTH_10:
-               icd->buswidth = 10;
                dw = 4;
                bpp = 0x40;
                break;
        case SOCAM_DATAWIDTH_9:
-               icd->buswidth = 9;
                dw = 3;
                bpp = 0x20;
                break;
@@ -836,7 +971,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
                /* Actually it can only be 8 now,
                 * default is just to silence compiler warnings */
        case SOCAM_DATAWIDTH_8:
-               icd->buswidth = 8;
                dw = 2;
                bpp = 0;
        }
@@ -852,9 +986,9 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
                cicr4 |= CICR4_VSP;
 
-       cicr0 = CICR0;
+       cicr0 = __raw_readl(pcdev->base + CICR0);
        if (cicr0 & CICR0_ENB)
-               CICR0 = cicr0 & ~CICR0_ENB;
+               __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0);
 
        cicr1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
 
@@ -862,7 +996,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        case V4L2_PIX_FMT_YUV422P:
                pcdev->channels = 3;
                cicr1 |= CICR1_YCBCR_F;
+               /*
+                * Normally, pxa bus wants as input UYVY format. We allow all
+                * reorderings of the YUV422 format, as no processing is done,
+                * and the YUV stream is just passed through without any
+                * transformation. Note that UYVY is the only format that
+                * should be used if pxa framebuffer Overlay2 is used.
+                */
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
        case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
                cicr1 |= CICR1_COLOR_SP_VAL(2);
                break;
        case V4L2_PIX_FMT_RGB555:
@@ -874,27 +1018,32 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
                break;
        }
 
-       CICR1 = cicr1;
-       CICR2 = 0;
-       CICR3 = CICR3_LPF_VAL(icd->height - 1) |
+       cicr2 = 0;
+       cicr3 = CICR3_LPF_VAL(icd->height - 1) |
                CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
-       CICR4 = mclk_get_divisor(pcdev) | cicr4;
+       cicr4 |= pcdev->mclk_divisor;
+
+       __raw_writel(cicr1, pcdev->base + CICR1);
+       __raw_writel(cicr2, pcdev->base + CICR2);
+       __raw_writel(cicr3, pcdev->base + CICR3);
+       __raw_writel(cicr4, pcdev->base + CICR4);
 
        /* CIF interrupts are not used, only DMA */
-       CICR0 = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
-                CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)) |
-               CICR0_DMAEN | CICR0_IRQ_MASK | (cicr0 & CICR0_ENB);
+       cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+               CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP));
+       cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK;
+       __raw_writel(cicr0, pcdev->base + CICR0);
 
        return 0;
 }
 
-static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
+                                   unsigned char buswidth)
 {
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        unsigned long bus_flags, camera_flags;
-       int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+       int ret = test_platform_param(pcdev, buswidth, &bus_flags);
 
        if (ret < 0)
                return ret;
@@ -904,28 +1053,210 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
        return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
 }
 
-static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
-                                 __u32 pixfmt, struct v4l2_rect *rect)
+static const struct soc_camera_data_format pxa_camera_formats[] = {
+       {
+               .name           = "Planar YUV422 16 bit",
+               .depth          = 16,
+               .fourcc         = V4L2_PIX_FMT_YUV422P,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+};
+
+static bool buswidth_supported(struct soc_camera_device *icd, int depth)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
+
+       switch (depth) {
+       case 8:
+               return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8);
+       case 9:
+               return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9);
+       case 10:
+               return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10);
+       }
+       return false;
+}
+
+static int required_buswidth(const struct soc_camera_data_format *fmt)
 {
-       return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+       switch (fmt->fourcc) {
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB555:
+               return 8;
+       default:
+               return fmt->depth;
+       }
 }
 
-static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
-                                 struct v4l2_format *f)
+static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+                                 struct soc_camera_format_xlate *xlate)
 {
-       /* limit to pxa hardware capabilities */
-       if (f->fmt.pix.height < 32)
-               f->fmt.pix.height = 32;
-       if (f->fmt.pix.height > 2048)
-               f->fmt.pix.height = 2048;
-       if (f->fmt.pix.width < 48)
-               f->fmt.pix.width = 48;
-       if (f->fmt.pix.width > 2048)
-               f->fmt.pix.width = 2048;
-       f->fmt.pix.width &= ~0x01;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       int formats = 0, buswidth, ret;
+
+       buswidth = required_buswidth(icd->formats + idx);
 
+       if (!buswidth_supported(icd, buswidth))
+               return 0;
+
+       ret = pxa_camera_try_bus_param(icd, buswidth);
+       if (ret < 0)
+               return 0;
+
+       switch (icd->formats[idx].fourcc) {
+       case V4L2_PIX_FMT_UYVY:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &pxa_camera_formats[0];
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = buswidth;
+                       xlate++;
+                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                               pxa_camera_formats[0].name,
+                               icd->formats[idx].name);
+               }
+       case V4L2_PIX_FMT_VYUY:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB555:
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = icd->formats + idx;
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = buswidth;
+                       xlate++;
+                       dev_dbg(&ici->dev, "Providing format %s packed\n",
+                               icd->formats[idx].name);
+               }
+               break;
+       default:
+               /* Generic pass-through */
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = icd->formats + idx;
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = icd->formats[idx].depth;
+                       xlate++;
+                       dev_dbg(&ici->dev,
+                               "Providing format %s in pass-through mode\n",
+                               icd->formats[idx].name);
+               }
+       }
+
+       return formats;
+}
+
+static int pxa_camera_set_fmt(struct soc_camera_device *icd,
+                             __u32 pixfmt, struct v4l2_rect *rect)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct pxa_camera_dev *pcdev = ici->priv;
+       const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
+       const struct soc_camera_format_xlate *xlate;
+       struct soc_camera_sense sense = {
+               .master_clock = pcdev->mclk,
+               .pixel_clock_max = pcdev->ciclk / 4,
+       };
+       int ret, buswidth;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       buswidth = xlate->buswidth;
+       host_fmt = xlate->host_fmt;
+       cam_fmt = xlate->cam_fmt;
+
+       /* If PCLK is used to latch data from the sensor, check sense */
+       if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+               icd->sense = &sense;
+
+       switch (pixfmt) {
+       case 0:                         /* Only geometry change */
+               ret = icd->ops->set_fmt(icd, pixfmt, rect);
+               break;
+       default:
+               ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
+       }
+
+       icd->sense = NULL;
+
+       if (ret < 0) {
+               dev_warn(&ici->dev, "Failed to configure for format %x\n",
+                        pixfmt);
+       } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
+               if (sense.pixel_clock > sense.pixel_clock_max) {
+                       dev_err(&ici->dev,
+                               "pixel clock %lu set by the camera too high!",
+                               sense.pixel_clock);
+                       return -EIO;
+               }
+               recalculate_fifo_timeout(pcdev, sense.pixel_clock);
+       }
+
+       if (pixfmt && !ret) {
+               icd->buswidth = buswidth;
+               icd->current_fmt = host_fmt;
+       }
+
+       return ret;
+}
+
+static int pxa_camera_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       const struct soc_camera_format_xlate *xlate;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       __u32 pixfmt = pix->pixelformat;
+       enum v4l2_field field;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       /* limit to pxa hardware capabilities */
+       if (pix->height < 32)
+               pix->height = 32;
+       if (pix->height > 2048)
+               pix->height = 2048;
+       if (pix->width < 48)
+               pix->width = 48;
+       if (pix->width > 2048)
+               pix->width = 2048;
+       pix->width &= ~0x01;
+
+       pix->bytesperline = pix->width *
+               DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+       pix->sizeimage = pix->height * pix->bytesperline;
+
+       /* camera has to see its format, but the user the original one */
+       pix->pixelformat = xlate->cam_fmt->fourcc;
        /* limit to sensor capabilities */
-       return icd->ops->try_fmt_cap(icd, f);
+       ret = icd->ops->try_fmt(icd, f);
+       pix->pixelformat = xlate->host_fmt->fourcc;
+
+       field = pix->field;
+
+       if (field == V4L2_FIELD_ANY) {
+               pix->field = V4L2_FIELD_NONE;
+       } else if (field != V4L2_FIELD_NONE) {
+               dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+               return -EINVAL;
+       }
+
+       return ret;
 }
 
 static int pxa_camera_reqbufs(struct soc_camera_file *icf,
@@ -977,16 +1308,15 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
 
 static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
 {
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        int i = 0, ret = 0;
 
-       pcdev->save_cicr[i++] = CICR0;
-       pcdev->save_cicr[i++] = CICR1;
-       pcdev->save_cicr[i++] = CICR2;
-       pcdev->save_cicr[i++] = CICR3;
-       pcdev->save_cicr[i++] = CICR4;
+       pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0);
+       pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1);
+       pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2);
+       pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3);
+       pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4);
 
        if ((pcdev->icd) && (pcdev->icd->ops->suspend))
                ret = pcdev->icd->ops->suspend(pcdev->icd, state);
@@ -996,8 +1326,7 @@ static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state)
 
 static int pxa_camera_resume(struct soc_camera_device *icd)
 {
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
        int i = 0, ret = 0;
 
@@ -1005,23 +1334,27 @@ static int pxa_camera_resume(struct soc_camera_device *icd)
        DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
        DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD;
 
-       CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB;
-       CICR1 = pcdev->save_cicr[i++];
-       CICR2 = pcdev->save_cicr[i++];
-       CICR3 = pcdev->save_cicr[i++];
-       CICR4 = pcdev->save_cicr[i++];
+       __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0);
+       __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1);
+       __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2);
+       __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3);
+       __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4);
 
        if ((pcdev->icd) && (pcdev->icd->ops->resume))
                ret = pcdev->icd->ops->resume(pcdev->icd);
 
        /* Restart frame capture if active buffer exists */
        if (!ret && pcdev->active) {
+               unsigned long cifr, cicr0;
+
                /* Reset the FIFOs */
-               CIFR |= CIFR_RESET_F;
-               /* Enable End-Of-Frame Interrupt */
-               CICR0 &= ~CICR0_EOFM;
-               /* Restart the Capture Interface */
-               CICR0 |= CICR0_ENB;
+               cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+               __raw_writel(cifr, pcdev->base + CIFR);
+
+               cicr0 = __raw_readl(pcdev->base + CICR0);
+               cicr0 &= ~CICR0_EOFM;   /* Enable End-Of-Frame Interrupt */
+               cicr0 |= CICR0_ENB;     /* Restart the Capture Interface */
+               __raw_writel(cicr0, pcdev->base + CICR0);
        }
 
        return ret;
@@ -1033,13 +1366,13 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .remove         = pxa_camera_remove_device,
        .suspend        = pxa_camera_suspend,
        .resume         = pxa_camera_resume,
-       .set_fmt_cap    = pxa_camera_set_fmt_cap,
-       .try_fmt_cap    = pxa_camera_try_fmt_cap,
+       .get_formats    = pxa_camera_get_formats,
+       .set_fmt        = pxa_camera_set_fmt,
+       .try_fmt        = pxa_camera_try_fmt,
        .init_videobuf  = pxa_camera_init_videobuf,
        .reqbufs        = pxa_camera_reqbufs,
        .poll           = pxa_camera_poll,
        .querycap       = pxa_camera_querycap,
-       .try_bus_param  = pxa_camera_try_bus_param,
        .set_bus_param  = pxa_camera_set_bus_param,
 };
 
@@ -1071,7 +1404,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
                goto exit;
        }
 
-       pcdev->clk = clk_get(&pdev->dev, "CAMCLK");
+       pcdev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(pcdev->clk)) {
                err = PTR_ERR(pcdev->clk);
                goto exit_kfree;
@@ -1090,14 +1423,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
                         "data widths, using default 10 bit\n");
                pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
        }
-       pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz;
-       if (!pcdev->platform_mclk_10khz) {
+       pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
+       if (!pcdev->mclk) {
                dev_warn(&pdev->dev,
-                        "mclk_10khz == 0! Please, fix your platform data. "
+                        "mclk == 0! Please, fix your platform data. "
                         "Using default 20MHz\n");
-               pcdev->platform_mclk_10khz = 2000;
+               pcdev->mclk = 20000000;
        }
 
+       pcdev->dev = &pdev->dev;
+       pcdev->mclk_divisor = mclk_get_divisor(pcdev);
+
        INIT_LIST_HEAD(&pcdev->capture);
        spin_lock_init(&pcdev->lock);
 
@@ -1117,7 +1453,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
        }
        pcdev->irq = irq;
        pcdev->base = base;
-       pcdev->dev = &pdev->dev;
 
        /* request dma */
        err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
diff --git a/drivers/media/video/pxa_camera.h b/drivers/media/video/pxa_camera.h
new file mode 100644 (file)
index 0000000..89cbfc9
--- /dev/null
@@ -0,0 +1,95 @@
+/* Camera Interface */
+#define CICR0          __REG(0x50000000)
+#define CICR1          __REG(0x50000004)
+#define CICR2          __REG(0x50000008)
+#define CICR3          __REG(0x5000000C)
+#define CICR4          __REG(0x50000010)
+#define CISR           __REG(0x50000014)
+#define CIFR           __REG(0x50000018)
+#define CITOR          __REG(0x5000001C)
+#define CIBR0          __REG(0x50000028)
+#define CIBR1          __REG(0x50000030)
+#define CIBR2          __REG(0x50000038)
+
+#define CICR0_DMAEN    (1 << 31)       /* DMA request enable */
+#define CICR0_PAR_EN   (1 << 30)       /* Parity enable */
+#define CICR0_SL_CAP_EN        (1 << 29)       /* Capture enable for slave mode */
+#define CICR0_ENB      (1 << 28)       /* Camera interface enable */
+#define CICR0_DIS      (1 << 27)       /* Camera interface disable */
+#define CICR0_SIM      (0x7 << 24)     /* Sensor interface mode mask */
+#define CICR0_TOM      (1 << 9)        /* Time-out mask */
+#define CICR0_RDAVM    (1 << 8)        /* Receive-data-available mask */
+#define CICR0_FEM      (1 << 7)        /* FIFO-empty mask */
+#define CICR0_EOLM     (1 << 6)        /* End-of-line mask */
+#define CICR0_PERRM    (1 << 5)        /* Parity-error mask */
+#define CICR0_QDM      (1 << 4)        /* Quick-disable mask */
+#define CICR0_CDM      (1 << 3)        /* Disable-done mask */
+#define CICR0_SOFM     (1 << 2)        /* Start-of-frame mask */
+#define CICR0_EOFM     (1 << 1)        /* End-of-frame mask */
+#define CICR0_FOM      (1 << 0)        /* FIFO-overrun mask */
+
+#define CICR1_TBIT     (1 << 31)       /* Transparency bit */
+#define CICR1_RGBT_CONV        (0x3 << 29)     /* RGBT conversion mask */
+#define CICR1_PPL      (0x7ff << 15)   /* Pixels per line mask */
+#define CICR1_RGB_CONV (0x7 << 12)     /* RGB conversion mask */
+#define CICR1_RGB_F    (1 << 11)       /* RGB format */
+#define CICR1_YCBCR_F  (1 << 10)       /* YCbCr format */
+#define CICR1_RGB_BPP  (0x7 << 7)      /* RGB bis per pixel mask */
+#define CICR1_RAW_BPP  (0x3 << 5)      /* Raw bis per pixel mask */
+#define CICR1_COLOR_SP (0x3 << 3)      /* Color space mask */
+#define CICR1_DW       (0x7 << 0)      /* Data width mask */
+
+#define CICR2_BLW      (0xff << 24)    /* Beginning-of-line pixel clock
+                                          wait count mask */
+#define CICR2_ELW      (0xff << 16)    /* End-of-line pixel clock
+                                          wait count mask */
+#define CICR2_HSW      (0x3f << 10)    /* Horizontal sync pulse width mask */
+#define CICR2_BFPW     (0x3f << 3)     /* Beginning-of-frame pixel clock
+                                          wait count mask */
+#define CICR2_FSW      (0x7 << 0)      /* Frame stabilization
+                                          wait count mask */
+
+#define CICR3_BFW      (0xff << 24)    /* Beginning-of-frame line clock
+                                          wait count mask */
+#define CICR3_EFW      (0xff << 16)    /* End-of-frame line clock
+                                          wait count mask */
+#define CICR3_VSW      (0x3f << 10)    /* Vertical sync pulse width mask */
+#define CICR3_BFPW     (0x3f << 3)     /* Beginning-of-frame pixel clock
+                                          wait count mask */
+#define CICR3_LPF      (0x7ff << 0)    /* Lines per frame mask */
+
+#define CICR4_MCLK_DLY (0x3 << 24)     /* MCLK Data Capture Delay mask */
+#define CICR4_PCLK_EN  (1 << 23)       /* Pixel clock enable */
+#define CICR4_PCP      (1 << 22)       /* Pixel clock polarity */
+#define CICR4_HSP      (1 << 21)       /* Horizontal sync polarity */
+#define CICR4_VSP      (1 << 20)       /* Vertical sync polarity */
+#define CICR4_MCLK_EN  (1 << 19)       /* MCLK enable */
+#define CICR4_FR_RATE  (0x7 << 8)      /* Frame rate mask */
+#define CICR4_DIV      (0xff << 0)     /* Clock divisor mask */
+
+#define CISR_FTO       (1 << 15)       /* FIFO time-out */
+#define CISR_RDAV_2    (1 << 14)       /* Channel 2 receive data available */
+#define CISR_RDAV_1    (1 << 13)       /* Channel 1 receive data available */
+#define CISR_RDAV_0    (1 << 12)       /* Channel 0 receive data available */
+#define CISR_FEMPTY_2  (1 << 11)       /* Channel 2 FIFO empty */
+#define CISR_FEMPTY_1  (1 << 10)       /* Channel 1 FIFO empty */
+#define CISR_FEMPTY_0  (1 << 9)        /* Channel 0 FIFO empty */
+#define CISR_EOL       (1 << 8)        /* End of line */
+#define CISR_PAR_ERR   (1 << 7)        /* Parity error */
+#define CISR_CQD       (1 << 6)        /* Camera interface quick disable */
+#define CISR_CDD       (1 << 5)        /* Camera interface disable done */
+#define CISR_SOF       (1 << 4)        /* Start of frame */
+#define CISR_EOF       (1 << 3)        /* End of frame */
+#define CISR_IFO_2     (1 << 2)        /* FIFO overrun for Channel 2 */
+#define CISR_IFO_1     (1 << 1)        /* FIFO overrun for Channel 1 */
+#define CISR_IFO_0     (1 << 0)        /* FIFO overrun for Channel 0 */
+
+#define CIFR_FLVL2     (0x7f << 23)    /* FIFO 2 level mask */
+#define CIFR_FLVL1     (0x7f << 16)    /* FIFO 1 level mask */
+#define CIFR_FLVL0     (0xff << 8)     /* FIFO 0 level mask */
+#define CIFR_THL_0     (0x3 << 4)      /* Threshold Level for Channel 0 FIFO */
+#define CIFR_RESET_F   (1 << 3)        /* Reset input FIFOs */
+#define CIFR_FEN2      (1 << 2)        /* FIFO enable for channel 2 */
+#define CIFR_FEN1      (1 << 1)        /* FIFO enable for channel 1 */
+#define CIFR_FEN0      (1 << 0)        /* FIFO enable for channel 0 */
+
index 4a21b8a6a7091a844c98e27b3090fb93f5c3cf9e..f159441e937527afbab13e49e824214613e3da6d 100644 (file)
@@ -15,7 +15,7 @@
  * <richard.guenther@student.uni-tuebingen.de>
  *
  * with changes by
- * Alan Cox <Alan.Cox@linux.org>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  * and
  *
@@ -804,8 +804,7 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t,
  *
  *  Returns 0 if successful
  */
-static int do_saa5246a_ioctl(struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg)
+static int do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct saa5246a_device *t = video_drvdata(file);
 
@@ -953,7 +952,7 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file,
 
        cmd = vtx_fix_command(cmd);
        mutex_lock(&t->lock);
-       err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl);
+       err = video_usercopy(file, cmd, arg, do_saa5246a_ioctl);
        mutex_unlock(&t->lock);
        return err;
 }
index 3bb959c25d9d5724e720cec199538d609d340073..6ef3affb97f163d165c227a178c199ea5913d7bc 100644 (file)
@@ -8,7 +8,7 @@
  *     you can add arbitary multiple teletext devices to Linux video4linux
  *     now (well 32 anyway).
  *
- *     Alan Cox <Alan.Cox@linux.org>
+ *     Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  *     The original driver was heavily modified to match the i2c interface
  *     It was truncated to use the WinTV boards, too.
@@ -190,8 +190,7 @@ static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
  *     Standard character-device-driver functions
  */
 
-static int do_saa5249_ioctl(struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg)
+static int do_saa5249_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        static int virtual_mode = false;
        struct saa5249_device *t = video_drvdata(file);
@@ -488,7 +487,7 @@ static int saa5249_ioctl(struct inode *inode, struct file *file,
 
        cmd = vtx_fix_command(cmd);
        mutex_lock(&t->lock);
-       err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl);
+       err = video_usercopy(file, cmd, arg, do_saa5249_ioctl);
        mutex_unlock(&t->lock);
        return err;
 }
index c8e9cb3db30a9651692e3c4d732cca6a82643c06..22708ecdf1bbaad27f1d8e81ef30054102d0977c 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 #include <media/saa7115.h>
@@ -70,6 +70,7 @@ static unsigned short normal_i2c[] = {
 I2C_CLIENT_INSMOD;
 
 struct saa711x_state {
+       struct v4l2_subdev sd;
        v4l2_std_id std;
        int input;
        int output;
@@ -89,10 +90,17 @@ struct saa711x_state {
        u8 apll;
 };
 
+static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa711x_state, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 
-static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_write_byte_data(client, reg, value);
 }
 
@@ -128,9 +136,9 @@ static int saa711x_has_reg(const int id, const u8 reg)
        return 1;
 }
 
-static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
+static int saa711x_writeregs(struct v4l2_subdev *sd, const unsigned char *regs)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
        unsigned char reg, data;
 
        while (*regs != 0x00) {
@@ -139,18 +147,20 @@ static int saa711x_writeregs(struct i2c_client *client, const unsigned char *reg
 
                /* According with datasheets, reserved regs should be
                   filled with 0 - seems better not to touch on they */
-               if (saa711x_has_reg(state->ident,reg)) {
-                       if (saa711x_write(client, reg, data) < 0)
+               if (saa711x_has_reg(state->ident, reg)) {
+                       if (saa711x_write(sd, reg, data) < 0)
                                return -1;
                } else {
-                       v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
+                       v4l2_dbg(1, debug, sd, "tried to access reserved reg 0x%02x\n", reg);
                }
        }
        return 0;
 }
 
-static inline int saa711x_read(struct i2c_client *client, u8 reg)
+static inline int saa711x_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
@@ -601,7 +611,7 @@ static int saa711x_odd_parity(u8 c)
        return c & 1;
 }
 
-static int saa711x_decode_vps(u8 * dst, u8 * p)
+static int saa711x_decode_vps(u8 *dst, u8 *p)
 {
        static const u8 biphase_tbl[] = {
                0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
@@ -648,7 +658,7 @@ static int saa711x_decode_vps(u8 * dst, u8 * p)
        return err & 0xf0;
 }
 
-static int saa711x_decode_wss(u8 * p)
+static int saa711x_decode_wss(u8 *p)
 {
        static const int wss_bits[8] = {
                0, 0, 0, 1, 0, 1, 1, 1
@@ -675,9 +685,9 @@ static int saa711x_decode_wss(u8 * p)
        return wss;
 }
 
-static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
        u32 acpf;
        u32 acni;
        u32 hz;
@@ -685,10 +695,10 @@ static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
        u8 acc = 0;     /* reg 0x3a, audio clock control */
 
        /* Checks for chips that don't have audio clock (saa7111, saa7113) */
-       if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
+       if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
                return 0;
 
-       v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
+       v4l2_dbg(1, debug, sd, "set audio clock freq: %d\n", freq);
 
        /* sanity check */
        if (freq < 32000 || freq > 48000)
@@ -715,66 +725,66 @@ static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
        if (state->apll)
                acc |= 0x08;
 
-       saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
-       saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
-       saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
+       saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
+       saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
+       saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
 
-       saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
-       saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
+       saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
+       saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
                                                        (acpf >> 8) & 0xff);
-       saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
+       saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
                                                        (acpf >> 16) & 0x03);
 
-       saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
-       saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
-       saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
+       saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
+       saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
+       saa711x_write(sd, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
        state->audclk_freq = freq;
        return 0;
 }
 
-static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                if (ctrl->value < 0 || ctrl->value > 255) {
-                       v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->bright = ctrl->value;
-               saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
+               saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, state->bright);
                break;
 
        case V4L2_CID_CONTRAST:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->contrast = ctrl->value;
-               saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
+               saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
                break;
 
        case V4L2_CID_SATURATION:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->sat = ctrl->value;
-               saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
+               saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, state->sat);
                break;
 
        case V4L2_CID_HUE:
                if (ctrl->value < -127 || ctrl->value > 127) {
-                       v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->hue = ctrl->value;
-               saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
+               saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue);
                break;
 
        default:
@@ -784,9 +794,9 @@ static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
        return 0;
 }
 
-static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -808,16 +818,16 @@ static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *c
        return 0;
 }
 
-static int saa711x_set_size(struct i2c_client *client, int width, int height)
+static int saa711x_set_size(struct v4l2_subdev *sd, int width, int height)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
        int HPSC, HFSC;
        int VSCY;
        int res;
        int is_50hz = state->std & V4L2_STD_625_50;
        int Vsrc = is_50hz ? 576 : 480;
 
-       v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
+       v4l2_dbg(1, debug, sd, "decoder set size to %ix%i\n", width, height);
 
        /* FIXME need better bounds checking here */
        if ((width < 1) || (width > 1440))
@@ -825,7 +835,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
        if ((height < 1) || (height > Vsrc))
                return -EINVAL;
 
-       if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
+       if (!saa711x_has_reg(state->ident, R_D0_B_HORIZ_PRESCALING)) {
                /* Decoder only supports 720 columns and 480 or 576 lines */
                if (width != 720)
                        return -EINVAL;
@@ -843,22 +853,22 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
        /* Set output width/height */
        /* width */
 
-       saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
+       saa711x_write(sd, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
                                        (u8) (width & 0xff));
-       saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
+       saa711x_write(sd, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
                                        (u8) ((width >> 8) & 0xff));
 
        /* Vertical Scaling uses height/2 */
-       res=height/2;
+       res = height / 2;
 
        /* On 60Hz, it is using a higher Vertical Output Size */
        if (!is_50hz)
                res += (VRES_60HZ - 480) >> 1;
 
                /* height */
-       saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
+       saa711x_write(sd, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
                                        (u8) (res & 0xff));
-       saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
+       saa711x_write(sd, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
                                        (u8) ((res >> 8) & 0xff));
 
        /* Scaling settings */
@@ -869,54 +879,54 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height)
        HFSC = (int)((1024 * 720) / (HPSC * width));
        /* FIXME hardcodes to "Task B"
         * write H prescaler integer */
-       saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
+       saa711x_write(sd, R_D0_B_HORIZ_PRESCALING,
                                (u8) (HPSC & 0x3f));
 
-       v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+       v4l2_dbg(1, debug, sd, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
        /* write H fine-scaling (luminance) */
-       saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
+       saa711x_write(sd, R_D8_B_HORIZ_LUMA_SCALING_INC,
                                (u8) (HFSC & 0xff));
-       saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
+       saa711x_write(sd, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
                                (u8) ((HFSC >> 8) & 0xff));
        /* write H fine-scaling (chrominance)
         * must be lum/2, so i'll just bitshift :) */
-       saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
+       saa711x_write(sd, R_DC_B_HORIZ_CHROMA_SCALING,
                                (u8) ((HFSC >> 1) & 0xff));
-       saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
+       saa711x_write(sd, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
                                (u8) ((HFSC >> 9) & 0xff));
 
        VSCY = (int)((1024 * Vsrc) / height);
-       v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+       v4l2_dbg(1, debug, sd, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
 
        /* Correct Contrast and Luminance */
-       saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
+       saa711x_write(sd, R_D5_B_LUMA_CONTRAST_CNTL,
                                        (u8) (64 * 1024 / VSCY));
-       saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
+       saa711x_write(sd, R_D6_B_CHROMA_SATURATION_CNTL,
                                        (u8) (64 * 1024 / VSCY));
 
                /* write V fine-scaling (luminance) */
-       saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
+       saa711x_write(sd, R_E0_B_VERT_LUMA_SCALING_INC,
                                        (u8) (VSCY & 0xff));
-       saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
+       saa711x_write(sd, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
                                        (u8) ((VSCY >> 8) & 0xff));
                /* write V fine-scaling (chrominance) */
-       saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
+       saa711x_write(sd, R_E2_B_VERT_CHROMA_SCALING_INC,
                                        (u8) (VSCY & 0xff));
-       saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
+       saa711x_write(sd, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
                                        (u8) ((VSCY >> 8) & 0xff));
 
-       saa711x_writeregs(client, saa7115_cfg_reset_scaler);
+       saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
 
        /* Activates task "B" */
-       saa711x_write(client, R_80_GLOBAL_CNTL_1,
-                               saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20);
+       saa711x_write(sd, R_80_GLOBAL_CNTL_1,
+                               saa711x_read(sd, R_80_GLOBAL_CNTL_1) | 0x20);
 
        return 0;
 }
 
-static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+static void saa711x_set_v4lstd(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
 
        /* Prevent unnecessary standard changes. During a standard
           change the I-Port is temporarily disabled. Any devices
@@ -932,13 +942,13 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
 
        // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
        if (std & V4L2_STD_525_60) {
-               v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
-               saa711x_writeregs(client, saa7115_cfg_60hz_video);
-               saa711x_set_size(client, 720, 480);
+               v4l2_dbg(1, debug, sd, "decoder set standard 60 Hz\n");
+               saa711x_writeregs(sd, saa7115_cfg_60hz_video);
+               saa711x_set_size(sd, 720, 480);
        } else {
-               v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
-               saa711x_writeregs(client, saa7115_cfg_50hz_video);
-               saa711x_set_size(client, 720, 576);
+               v4l2_dbg(1, debug, sd, "decoder set standard 50 Hz\n");
+               saa711x_writeregs(sd, saa7115_cfg_50hz_video);
+               saa711x_set_size(sd, 720, 576);
        }
 
        /* Register 0E - Bits D6-D4 on NO-AUTO mode
@@ -952,7 +962,7 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
        */
        if (state->ident == V4L2_IDENT_SAA7111 ||
            state->ident == V4L2_IDENT_SAA7113) {
-               u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
+               u8 reg = saa711x_read(sd, R_0E_CHROMA_CNTL_1) & 0x8f;
 
                if (std == V4L2_STD_PAL_M) {
                        reg |= 0x30;
@@ -965,87 +975,31 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
                } else if (std & V4L2_STD_SECAM) {
                        reg |= 0x50;
                }
-               saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
+               saa711x_write(sd, R_0E_CHROMA_CNTL_1, reg);
        } else {
                /* restart task B if needed */
-               int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
+               int taskb = saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10;
 
                if (taskb && state->ident == V4L2_IDENT_SAA7114) {
-                       saa711x_writeregs(client, saa7115_cfg_vbi_on);
+                       saa711x_writeregs(sd, saa7115_cfg_vbi_on);
                }
 
                /* switch audio mode too! */
-               saa711x_set_audio_clock_freq(client, state->audclk_freq);
-       }
-}
-
-static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
-{
-       struct saa711x_state *state = i2c_get_clientdata(client);
-
-       return state->std;
-}
-
-static void saa711x_log_status(struct i2c_client *client)
-{
-       struct saa711x_state *state = i2c_get_clientdata(client);
-       int reg1e, reg1f;
-       int signalOk;
-       int vcr;
-
-       v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
-       if (state->ident != V4L2_IDENT_SAA7115) {
-               /* status for the saa7114 */
-               reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
-               signalOk = (reg1f & 0xc1) == 0x81;
-               v4l_info(client, "Video signal:    %s\n", signalOk ? "ok" : "bad");
-               v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
-               return;
-       }
-
-       /* status for the saa7115 */
-       reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
-       reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
-
-       signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
-       vcr = !(reg1f & 0x10);
-
-       if (state->input >= 6) {
-               v4l_info(client, "Input:           S-Video %d\n", state->input - 6);
-       } else {
-               v4l_info(client, "Input:           Composite %d\n", state->input);
+               saa711x_s_clock_freq(sd, state->audclk_freq);
        }
-       v4l_info(client, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
-       v4l_info(client, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
-
-       switch (reg1e & 0x03) {
-               case 1:
-                       v4l_info(client, "Detected format: NTSC\n");
-                       break;
-               case 2:
-                       v4l_info(client, "Detected format: PAL\n");
-                       break;
-               case 3:
-                       v4l_info(client, "Detected format: SECAM\n");
-                       break;
-               default:
-                       v4l_info(client, "Detected format: BW/No color\n");
-                       break;
-       }
-       v4l_info(client, "Width, Height:   %d, %d\n", state->width, state->height);
 }
 
 /* setup the sliced VBI lcr registers according to the sliced VBI format */
-static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+static void saa711x_set_lcr(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
        int is_50hz = (state->std & V4L2_STD_625_50);
        u8 lcr[24];
        int i, x;
 
 #if 1
        /* saa7113/7114/7118 VBI support are experimental */
-       if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
+       if (!saa711x_has_reg(state->ident, R_41_LCR_BASE))
                return;
 
 #else
@@ -1109,16 +1063,16 @@ static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
 
        /* write the lcr registers */
        for (i = 2; i <= 23; i++) {
-               saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
+               saa711x_write(sd, i - 2 + R_41_LCR_BASE, lcr[i]);
        }
 
        /* enable/disable raw VBI capturing */
-       saa711x_writeregs(client, fmt == NULL ?
+       saa711x_writeregs(sd, fmt == NULL ?
                                saa7115_cfg_vbi_on :
                                saa7115_cfg_vbi_off);
 }
 
-static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
        static u16 lcr2vbi[] = {
                0, V4L2_SLICED_TELETEXT_B, 0,   /* 1 */
@@ -1134,10 +1088,10 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
                return -EINVAL;
        memset(sliced, 0, sizeof(*sliced));
        /* done if using raw VBI */
-       if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
+       if (saa711x_read(sd, R_80_GLOBAL_CNTL_1) & 0x10)
                return 0;
        for (i = 2; i <= 23; i++) {
-               u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
+               u8 v = saa711x_read(sd, i - 2 + R_41_LCR_BASE);
 
                sliced->service_lines[0][i] = lcr2vbi[v >> 4];
                sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -1147,20 +1101,20 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
        return 0;
 }
 
-static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
 {
        if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
-               saa711x_set_lcr(client, &fmt->fmt.sliced);
+               saa711x_set_lcr(sd, &fmt->fmt.sliced);
                return 0;
        }
        if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-               saa711x_set_lcr(client, NULL);
+               saa711x_set_lcr(sd, NULL);
                return 0;
        }
        if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
+       return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height);
 }
 
 /* Decode the sliced VBI data stream as created by the saa7115.
@@ -1169,13 +1123,12 @@ static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
    The current implementation uses SAV/EAV codes and not the ancillary data
    headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
    code. */
-static void saa711x_decode_vbi_line(struct i2c_client *client,
-                                   struct v4l2_decode_vbi_line *vbi)
+static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi)
 {
+       struct saa711x_state *state = to_state(sd);
        static const char vbi_no_data_pattern[] = {
                0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
        };
-       struct saa711x_state *state = i2c_get_clientdata(client);
        u8 *p = vbi->p;
        u32 wss;
        int id1, id2;   /* the ID1 and ID2 bytes from the internal header */
@@ -1202,7 +1155,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
        /* If the VBI slicer does not detect any signal it will fill up
           the payload buffer with 0xa0 bytes. */
        if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
-               return;
+               return 0;
 
        /* decode payloads */
        switch (id2) {
@@ -1211,275 +1164,352 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
                break;
        case 4:
                if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
-                       return;
+                       return 0;
                vbi->type = V4L2_SLICED_CAPTION_525;
                break;
        case 5:
                wss = saa711x_decode_wss(p);
                if (wss == -1)
-                       return;
+                       return 0;
                p[0] = wss & 0xff;
                p[1] = wss >> 8;
                vbi->type = V4L2_SLICED_WSS_625;
                break;
        case 7:
                if (saa711x_decode_vps(p, p) != 0)
-                       return;
+                       return 0;
                vbi->type = V4L2_SLICED_VPS;
                break;
        default:
-               return;
+               break;
        }
+       return 0;
 }
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
-static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
-       struct saa711x_state *state = i2c_get_clientdata(client);
+       struct saa711x_state *state = to_state(sd);
+       int status;
 
-       /* ioctls to allow direct access to the saa7115 registers for testing */
-       switch (cmd) {
-       case VIDIOC_S_FMT:
-               return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
+       if (state->radio)
+               return 0;
+       status = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
 
-       case VIDIOC_G_FMT:
-               return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
+       v4l2_dbg(1, debug, sd, "status: 0x%02x\n", status);
+       vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+       return 0;
+}
 
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
+static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill_std(qc);
+       default:
+               return -EINVAL;
+       }
+}
 
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *vt = arg;
-               int status;
+static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct saa711x_state *state = to_state(sd);
 
-               if (state->radio)
-                       break;
-               status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
+       state->radio = 0;
+       saa711x_set_v4lstd(sd, std);
+       return 0;
+}
 
-               v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
-               vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
-               break;
-       }
+static int saa711x_s_radio(struct v4l2_subdev *sd)
+{
+       struct saa711x_state *state = to_state(sd);
 
-       case VIDIOC_LOG_STATUS:
-               saa711x_log_status(client);
-               break;
+       state->radio = 1;
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-               return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
+static int saa711x_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct saa711x_state *state = to_state(sd);
+       u32 input = route->input;
+       u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
+
+       v4l2_dbg(1, debug, sd, "decoder set input %d output %d\n", route->input, route->output);
+       /* saa7111/3 does not have these inputs */
+       if ((state->ident == V4L2_IDENT_SAA7113 ||
+            state->ident == V4L2_IDENT_SAA7111) &&
+           (route->input == SAA7115_COMPOSITE4 ||
+            route->input == SAA7115_COMPOSITE5)) {
+               return -EINVAL;
+       }
+       if (route->input > SAA7115_SVIDEO3)
+               return -EINVAL;
+       if (route->output > SAA7115_IPORT_ON)
+               return -EINVAL;
+       if (state->input == route->input && state->output == route->output)
+               return 0;
+       v4l2_dbg(1, debug, sd, "now setting %s input %s output\n",
+               (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite",
+               (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
+       state->input = route->input;
+
+       /* saa7111 has slightly different input numbering */
+       if (state->ident == V4L2_IDENT_SAA7111) {
+               if (input >= SAA7115_COMPOSITE4)
+                       input -= 2;
+               /* saa7111 specific */
+               saa711x_write(sd, R_10_CHROMA_CNTL_2,
+                               (saa711x_read(sd, R_10_CHROMA_CNTL_2) & 0x3f) |
+                               ((route->output & 0xc0) ^ 0x40));
+               saa711x_write(sd, R_13_RT_X_PORT_OUT_CNTL,
+                               (saa711x_read(sd, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
+                               ((route->output & 2) ? 0x0a : 0));
+       }
 
-       case VIDIOC_S_CTRL:
-               return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
+       /* select mode */
+       saa711x_write(sd, R_02_INPUT_CNTL_1,
+                     (saa711x_read(sd, R_02_INPUT_CNTL_1) & mask) |
+                      input);
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
+       /* bypass chrominance trap for S-Video modes */
+       saa711x_write(sd, R_09_LUMA_CNTL,
+                       (saa711x_read(sd, R_09_LUMA_CNTL) & 0x7f) |
+                       (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
 
-               switch (qc->id) {
-                       case V4L2_CID_BRIGHTNESS:
-                       case V4L2_CID_CONTRAST:
-                       case V4L2_CID_SATURATION:
-                       case V4L2_CID_HUE:
-                               return v4l2_ctrl_query_fill_std(qc);
-                       default:
-                               return -EINVAL;
-               }
+       state->output = route->output;
+       if (state->ident == V4L2_IDENT_SAA7114 ||
+                       state->ident == V4L2_IDENT_SAA7115) {
+               saa711x_write(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
+                               (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
+                               (state->output & 0x01));
        }
+       return 0;
+}
 
-       case VIDIOC_G_STD:
-               *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
-               break;
+static int saa711x_s_gpio(struct v4l2_subdev *sd, u32 val)
+{
+       struct saa711x_state *state = to_state(sd);
 
-       case VIDIOC_S_STD:
-               state->radio = 0;
-               saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
-               break;
+       if (state->ident != V4L2_IDENT_SAA7111)
+               return -EINVAL;
+       saa711x_write(sd, 0x11, (saa711x_read(sd, 0x11) & 0x7f) |
+               (val ? 0x80 : 0));
+       return 0;
+}
 
-       case AUDC_SET_RADIO:
-               state->radio = 1;
-               break;
+static int saa711x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct saa711x_state *state = to_state(sd);
 
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-       {
-               struct v4l2_routing *route = arg;
+       v4l2_dbg(1, debug, sd, "%s output\n",
+                       enable ? "enable" : "disable");
 
-               route->input = state->input;
-               route->output = state->output;
-               break;
+       if (state->enable != enable) {
+               state->enable = enable;
+               saa711x_write(sd, R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
+                               state->enable);
        }
+       return 0;
+}
 
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-       {
-               struct v4l2_routing *route = arg;
-               u32 input = route->input;
-               u8 mask = (state->ident == V4L2_IDENT_SAA7111) ? 0xf8 : 0xf0;
-
-               v4l_dbg(1, debug, client, "decoder set input %d output %d\n", route->input, route->output);
-               /* saa7111/3 does not have these inputs */
-               if ((state->ident == V4L2_IDENT_SAA7113 ||
-                    state->ident == V4L2_IDENT_SAA7111) &&
-                   (route->input == SAA7115_COMPOSITE4 ||
-                    route->input == SAA7115_COMPOSITE5)) {
-                       return -EINVAL;
-               }
-               if (route->input > SAA7115_SVIDEO3)
-                       return -EINVAL;
-               if (route->output > SAA7115_IPORT_ON)
-                       return -EINVAL;
-               if (state->input == route->input && state->output == route->output)
-                       break;
-               v4l_dbg(1, debug, client, "now setting %s input %s output\n",
-                       (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite", (route->output == SAA7115_IPORT_ON) ? "iport on" : "iport off");
-               state->input = route->input;
-
-               /* saa7111 has slightly different input numbering */
-               if (state->ident == V4L2_IDENT_SAA7111) {
-                       if (input >= SAA7115_COMPOSITE4)
-                               input -= 2;
-                       /* saa7111 specific */
-                       saa711x_write(client, R_10_CHROMA_CNTL_2,
-                                       (saa711x_read(client, R_10_CHROMA_CNTL_2) & 0x3f) |
-                                       ((route->output & 0xc0) ^ 0x40));
-                       saa711x_write(client, R_13_RT_X_PORT_OUT_CNTL,
-                                       (saa711x_read(client, R_13_RT_X_PORT_OUT_CNTL) & 0xf0) |
-                                       ((route->output & 2) ? 0x0a : 0));
-               }
+static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, struct v4l2_crystal_freq *freq)
+{
+       struct saa711x_state *state = to_state(sd);
 
-               /* select mode */
-               saa711x_write(client, R_02_INPUT_CNTL_1,
-                             (saa711x_read(client, R_02_INPUT_CNTL_1) & mask) |
-                              input);
+       if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+                       freq->freq != SAA7115_FREQ_24_576_MHZ)
+               return -EINVAL;
+       state->crystal_freq = freq->freq;
+       state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+       state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+       state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+       saa711x_s_clock_freq(sd, state->audclk_freq);
+       return 0;
+}
 
-               /* bypass chrominance trap for S-Video modes */
-               saa711x_write(client, R_09_LUMA_CNTL,
-                             (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
-                              (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
+static int saa711x_reset(struct v4l2_subdev *sd, u32 val)
+{
+       v4l2_dbg(1, debug, sd, "decoder RESET\n");
+       saa711x_writeregs(sd, saa7115_cfg_reset_scaler);
+       return 0;
+}
 
-               state->output = route->output;
-               if (state->ident == V4L2_IDENT_SAA7114 ||
-                       state->ident == V4L2_IDENT_SAA7115) {
-                       saa711x_write(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK,
-                             (saa711x_read(client, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
-                              (state->output & 0x01));
+static int saa711x_g_vbi_data(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *data)
+{
+       /* Note: the internal field ID is inverted for NTSC,
+          so data->field 0 maps to the saa7115 even field,
+          whereas for PAL it maps to the saa7115 odd field. */
+       switch (data->id) {
+       case V4L2_SLICED_WSS_625:
+               if (saa711x_read(sd, 0x6b) & 0xc0)
+                       return -EIO;
+               data->data[0] = saa711x_read(sd, 0x6c);
+               data->data[1] = saa711x_read(sd, 0x6d);
+               return 0;
+       case V4L2_SLICED_CAPTION_525:
+               if (data->field == 0) {
+                       /* CC */
+                       if (saa711x_read(sd, 0x66) & 0x30)
+                               return -EIO;
+                       data->data[0] = saa711x_read(sd, 0x69);
+                       data->data[1] = saa711x_read(sd, 0x6a);
+                       return 0;
                }
-               break;
+               /* XDS */
+               if (saa711x_read(sd, 0x66) & 0xc0)
+                       return -EIO;
+               data->data[0] = saa711x_read(sd, 0x67);
+               data->data[1] = saa711x_read(sd, 0x68);
+               return 0;
+       default:
+               return -EINVAL;
        }
+}
 
-       case VIDIOC_STREAMON:
-       case VIDIOC_STREAMOFF:
-               v4l_dbg(1, debug, client, "%s output\n",
-                       (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
-
-               if (state->enable != (cmd == VIDIOC_STREAMON)) {
-                       state->enable = (cmd == VIDIOC_STREAMON);
-                       saa711x_write(client,
-                               R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
-                               state->enable);
-               }
-               break;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_S_CRYSTAL_FREQ:
-       {
-               struct v4l2_crystal_freq *freq = arg;
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = saa711x_read(sd, reg->reg & 0xff);
+       return 0;
+}
 
-               if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
-                   freq->freq != SAA7115_FREQ_24_576_MHZ)
-                       return -EINVAL;
-               state->crystal_freq = freq->freq;
-               state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
-               state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
-               state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
-               saa711x_set_audio_clock_freq(client, state->audclk_freq);
-               break;
-       }
+static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_DECODE_VBI_LINE:
-               saa711x_decode_vbi_line(client, arg);
-               break;
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       saa711x_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
+}
+#endif
 
-       case VIDIOC_INT_RESET:
-               v4l_dbg(1, debug, client, "decoder RESET\n");
-               saa711x_writeregs(client, saa7115_cfg_reset_scaler);
-               break;
+static int saa711x_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct saa711x_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_INT_S_GPIO:
-               if (state->ident != V4L2_IDENT_SAA7111)
-                       return -EINVAL;
-               saa711x_write(client, 0x11, (saa711x_read(client, 0x11) & 0x7f) |
-                       (*(u32 *)arg ? 0x80 : 0));
-               break;
+       return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
 
-       case VIDIOC_INT_G_VBI_DATA:
-       {
-               struct v4l2_sliced_vbi_data *data = arg;
+static int saa711x_log_status(struct v4l2_subdev *sd)
+{
+       struct saa711x_state *state = to_state(sd);
+       int reg1e, reg1f;
+       int signalOk;
+       int vcr;
 
-               /* Note: the internal field ID is inverted for NTSC,
-                  so data->field 0 maps to the saa7115 even field,
-                  whereas for PAL it maps to the saa7115 odd field. */
-               switch (data->id) {
-               case V4L2_SLICED_WSS_625:
-                       if (saa711x_read(client, 0x6b) & 0xc0)
-                               return -EIO;
-                       data->data[0] = saa711x_read(client, 0x6c);
-                       data->data[1] = saa711x_read(client, 0x6d);
-                       return 0;
-               case V4L2_SLICED_CAPTION_525:
-                       if (data->field == 0) {
-                               /* CC */
-                               if (saa711x_read(client, 0x66) & 0x30)
-                                       return -EIO;
-                               data->data[0] = saa711x_read(client, 0x69);
-                               data->data[1] = saa711x_read(client, 0x6a);
-                               return 0;
-                       }
-                       /* XDS */
-                       if (saa711x_read(client, 0x66) & 0xc0)
-                               return -EIO;
-                       data->data[0] = saa711x_read(client, 0x67);
-                       data->data[1] = saa711x_read(client, 0x68);
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-               break;
+       v4l2_info(sd, "Audio frequency: %d Hz\n", state->audclk_freq);
+       if (state->ident != V4L2_IDENT_SAA7115) {
+               /* status for the saa7114 */
+               reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+               signalOk = (reg1f & 0xc1) == 0x81;
+               v4l2_info(sd, "Video signal:    %s\n", signalOk ? "ok" : "bad");
+               v4l2_info(sd, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
+               return 0;
        }
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
+       /* status for the saa7115 */
+       reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+       reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
 
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = saa711x_read(client, reg->reg & 0xff);
-               else
-                       saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
-               break;
-       }
-#endif
+       signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+       vcr = !(reg1f & 0x10);
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
+       if (state->input >= 6)
+               v4l2_info(sd, "Input:           S-Video %d\n", state->input - 6);
+       else
+               v4l2_info(sd, "Input:           Composite %d\n", state->input);
+       v4l2_info(sd, "Video signal:    %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+       v4l2_info(sd, "Frequency:       %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
 
+       switch (reg1e & 0x03) {
+       case 1:
+               v4l2_info(sd, "Detected format: NTSC\n");
+               break;
+       case 2:
+               v4l2_info(sd, "Detected format: PAL\n");
+               break;
+       case 3:
+               v4l2_info(sd, "Detected format: SECAM\n");
+               break;
        default:
-               return -EINVAL;
+               v4l2_info(sd, "Detected format: BW/No color\n");
+               break;
        }
-
+       v4l2_info(sd, "Width, Height:   %d, %d\n", state->width, state->height);
        return 0;
 }
 
+static int saa711x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa711x_core_ops = {
+       .log_status = saa711x_log_status,
+       .g_chip_ident = saa711x_g_chip_ident,
+       .g_ctrl = saa711x_g_ctrl,
+       .s_ctrl = saa711x_s_ctrl,
+       .queryctrl = saa711x_queryctrl,
+       .reset = saa711x_reset,
+       .s_gpio = saa711x_s_gpio,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = saa711x_g_register,
+       .s_register = saa711x_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops saa711x_tuner_ops = {
+       .s_std = saa711x_s_std,
+       .s_radio = saa711x_s_radio,
+       .g_tuner = saa711x_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
+       .s_clock_freq = saa711x_s_clock_freq,
+};
+
+static const struct v4l2_subdev_video_ops saa711x_video_ops = {
+       .s_routing = saa711x_s_routing,
+       .s_crystal_freq = saa711x_s_crystal_freq,
+       .g_fmt = saa711x_g_fmt,
+       .s_fmt = saa711x_s_fmt,
+       .g_vbi_data = saa711x_g_vbi_data,
+       .decode_vbi_line = saa711x_decode_vbi_line,
+       .s_stream = saa711x_s_stream,
+};
+
+static const struct v4l2_subdev_ops saa711x_ops = {
+       .core = &saa711x_core_ops,
+       .tuner = &saa711x_tuner_ops,
+       .audio = &saa711x_audio_ops,
+       .video = &saa711x_video_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
-static int saa7115_probe(struct i2c_client *client,
+static int saa711x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct saa711x_state *state;
+       struct v4l2_subdev *sd;
        int     i;
        char    name[17];
        char chip_id;
@@ -1490,8 +1520,8 @@ static int saa7115_probe(struct i2c_client *client,
                return -EIO;
 
        for (i = 0; i < 0x0f; i++) {
-               saa711x_write(client, 0, i);
-               name[i] = (saa711x_read(client, 0) & 0x0f) + '0';
+               i2c_smbus_write_byte_data(client, 0, i);
+               name[i] = (i2c_smbus_read_byte_data(client, 0) & 0x0f) + '0';
                if (name[i] > '9')
                        name[i] += 'a' - '9' - 1;
        }
@@ -1518,7 +1548,8 @@ static int saa7115_probe(struct i2c_client *client,
        state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
-       i2c_set_clientdata(client, state);
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
        state->input = -1;
        state->output = SAA7115_IPORT_ON;
        state->enable = 1;
@@ -1545,41 +1576,45 @@ static int saa7115_probe(struct i2c_client *client,
                break;
        default:
                state->ident = V4L2_IDENT_SAA7111;
-               v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
+               v4l2_info(sd, "WARNING: Chip is not known - Falling back to saa7111\n");
 
        }
 
        state->audclk_freq = 48000;
 
-       v4l_dbg(1, debug, client, "writing init values\n");
+       v4l2_dbg(1, debug, sd, "writing init values\n");
 
        /* init to 60hz/48khz */
        state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
        switch (state->ident) {
        case V4L2_IDENT_SAA7111:
-               saa711x_writeregs(client, saa7111_init);
+               saa711x_writeregs(sd, saa7111_init);
                break;
        case V4L2_IDENT_SAA7113:
-               saa711x_writeregs(client, saa7113_init);
+               saa711x_writeregs(sd, saa7113_init);
                break;
        default:
                state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
-               saa711x_writeregs(client, saa7115_init_auto_input);
+               saa711x_writeregs(sd, saa7115_init_auto_input);
        }
        if (state->ident != V4L2_IDENT_SAA7111)
-               saa711x_writeregs(client, saa7115_init_misc);
-       saa711x_set_v4lstd(client, V4L2_STD_NTSC);
+               saa711x_writeregs(sd, saa7115_init_misc);
+       saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
 
-       v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
-               saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
+       v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
+               saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
+               saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7115_remove(struct i2c_client *client)
+static int saa711x_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
@@ -1597,9 +1632,9 @@ MODULE_DEVICE_TABLE(i2c, saa7115_id);
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa7115",
        .driverid = I2C_DRIVERID_SAA711X,
-       .command = saa7115_command,
-       .probe = saa7115_probe,
-       .remove = saa7115_remove,
+       .command = saa711x_command,
+       .probe = saa711x_probe,
+       .remove = saa711x_remove,
        .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
        .id_table = saa7115_id,
 };
index cc02fb18efa75bcc9662cedb194bfe378fe247b9..bfc85654795e089189a1e676ac9d63b9651f0fcd 100644 (file)
@@ -53,7 +53,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 #include <media/saa7127.h>
@@ -231,6 +231,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = {
  */
 
 struct saa7127_state {
+       struct v4l2_subdev sd;
        v4l2_std_id std;
        u32 ident;
        enum saa7127_input_type input_type;
@@ -250,6 +251,11 @@ struct saa7127_state {
        u8 reg_61;
 };
 
+static inline struct saa7127_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa7127_state, sd);
+}
+
 static const char * const output_strs[] =
 {
        "S-Video + Composite",
@@ -281,32 +287,35 @@ static const char * const wss_strs[] = {
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_read(struct i2c_client *client, u8 reg)
+static int saa7127_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        return i2c_smbus_read_byte_data(client, reg);
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
+static int saa7127_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int i;
 
        for (i = 0; i < 3; i++) {
                if (i2c_smbus_write_byte_data(client, reg, val) == 0)
                        return 0;
        }
-       v4l_err(client, "I2C Write Problem\n");
+       v4l2_err(sd, "I2C Write Problem\n");
        return -1;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_write_inittab(struct i2c_client *client,
+static int saa7127_write_inittab(struct v4l2_subdev *sd,
                                 const struct i2c_reg_value *regs)
 {
        while (regs->reg != 0) {
-               saa7127_write(client, regs->reg, regs->value);
+               saa7127_write(sd, regs->reg, regs->value);
                regs++;
        }
        return 0;
@@ -314,16 +323,16 @@ static int saa7127_write_inittab(struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_vps(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
        int enable = (data->line != 0);
 
        if (enable && (data->field != 0 || data->line != 16))
                return -EINVAL;
        if (state->vps_enable != enable) {
-               v4l_dbg(1, debug, client, "Turn VPS Signal %s\n", enable ? "on" : "off");
-               saa7127_write(client, 0x54, enable << 7);
+               v4l2_dbg(1, debug, sd, "Turn VPS Signal %s\n", enable ? "on" : "off");
+               saa7127_write(sd, 0x54, enable << 7);
                state->vps_enable = enable;
        }
        if (!enable)
@@ -334,91 +343,91 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
        state->vps_data[2] = data->data[9];
        state->vps_data[3] = data->data[10];
        state->vps_data[4] = data->data[11];
-       v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n",
+       v4l2_dbg(1, debug, sd, "Set VPS data %02x %02x %02x %02x %02x\n",
                state->vps_data[0], state->vps_data[1],
                state->vps_data[2], state->vps_data[3],
                state->vps_data[4]);
-       saa7127_write(client, 0x55, state->vps_data[0]);
-       saa7127_write(client, 0x56, state->vps_data[1]);
-       saa7127_write(client, 0x57, state->vps_data[2]);
-       saa7127_write(client, 0x58, state->vps_data[3]);
-       saa7127_write(client, 0x59, state->vps_data[4]);
+       saa7127_write(sd, 0x55, state->vps_data[0]);
+       saa7127_write(sd, 0x56, state->vps_data[1]);
+       saa7127_write(sd, 0x57, state->vps_data[2]);
+       saa7127_write(sd, 0x58, state->vps_data[3]);
+       saa7127_write(sd, 0x59, state->vps_data[4]);
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_cc(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
        u16 cc = data->data[1] << 8 | data->data[0];
        int enable = (data->line != 0);
 
        if (enable && (data->field != 0 || data->line != 21))
                return -EINVAL;
        if (state->cc_enable != enable) {
-               v4l_dbg(1, debug, client,
+               v4l2_dbg(1, debug, sd,
                        "Turn CC %s\n", enable ? "on" : "off");
-               saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+               saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
                        (state->xds_enable << 7) | (enable << 6) | 0x11);
                state->cc_enable = enable;
        }
        if (!enable)
                return 0;
 
-       v4l_dbg(2, debug, client, "CC data: %04x\n", cc);
-       saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
-       saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+       v4l2_dbg(2, debug, sd, "CC data: %04x\n", cc);
+       saa7127_write(sd, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+       saa7127_write(sd, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
        state->cc_data = cc;
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_xds(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
        u16 xds = data->data[1] << 8 | data->data[0];
        int enable = (data->line != 0);
 
        if (enable && (data->field != 1 || data->line != 21))
                return -EINVAL;
        if (state->xds_enable != enable) {
-               v4l_dbg(1, debug, client, "Turn XDS %s\n", enable ? "on" : "off");
-               saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+               v4l2_dbg(1, debug, sd, "Turn XDS %s\n", enable ? "on" : "off");
+               saa7127_write(sd, SAA7127_REG_CLOSED_CAPTION,
                                (enable << 7) | (state->cc_enable << 6) | 0x11);
                state->xds_enable = enable;
        }
        if (!enable)
                return 0;
 
-       v4l_dbg(2, debug, client, "XDS data: %04x\n", xds);
-       saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
-       saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+       v4l2_dbg(2, debug, sd, "XDS data: %04x\n", xds);
+       saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+       saa7127_write(sd, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
        state->xds_data = xds;
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+static int saa7127_set_wss(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
        int enable = (data->line != 0);
 
        if (enable && (data->field != 0 || data->line != 23))
                return -EINVAL;
        if (state->wss_enable != enable) {
-               v4l_dbg(1, debug, client, "Turn WSS %s\n", enable ? "on" : "off");
-               saa7127_write(client, 0x27, enable << 7);
+               v4l2_dbg(1, debug, sd, "Turn WSS %s\n", enable ? "on" : "off");
+               saa7127_write(sd, 0x27, enable << 7);
                state->wss_enable = enable;
        }
        if (!enable)
                return 0;
 
-       saa7127_write(client, 0x26, data->data[0]);
-       saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
-       v4l_dbg(1, debug, client,
+       saa7127_write(sd, 0x26, data->data[0]);
+       saa7127_write(sd, 0x27, 0x80 | (data->data[1] & 0x3f));
+       v4l2_dbg(1, debug, sd,
                "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
        state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
        return 0;
@@ -426,18 +435,18 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_video_enable(struct i2c_client *client, int enable)
+static int saa7127_set_video_enable(struct v4l2_subdev *sd, int enable)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
 
        if (enable) {
-               v4l_dbg(1, debug, client, "Enable Video Output\n");
-               saa7127_write(client, 0x2d, state->reg_2d);
-               saa7127_write(client, 0x61, state->reg_61);
+               v4l2_dbg(1, debug, sd, "Enable Video Output\n");
+               saa7127_write(sd, 0x2d, state->reg_2d);
+               saa7127_write(sd, 0x61, state->reg_61);
        } else {
-               v4l_dbg(1, debug, client, "Disable Video Output\n");
-               saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
-               saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
+               v4l2_dbg(1, debug, sd, "Disable Video Output\n");
+               saa7127_write(sd, 0x2d, (state->reg_2d & 0xf0));
+               saa7127_write(sd, 0x61, (state->reg_61 | 0xc0));
        }
        state->video_enable = enable;
        return 0;
@@ -445,32 +454,32 @@ static int saa7127_set_video_enable(struct i2c_client *client, int enable)
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
+static int saa7127_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
        const struct i2c_reg_value *inittab;
 
        if (std & V4L2_STD_525_60) {
-               v4l_dbg(1, debug, client, "Selecting 60 Hz video Standard\n");
+               v4l2_dbg(1, debug, sd, "Selecting 60 Hz video Standard\n");
                inittab = saa7127_init_config_60hz;
                state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
        } else {
-               v4l_dbg(1, debug, client, "Selecting 50 Hz video Standard\n");
+               v4l2_dbg(1, debug, sd, "Selecting 50 Hz video Standard\n");
                inittab = saa7127_init_config_50hz;
                state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
        }
 
        /* Write Table */
-       saa7127_write_inittab(client, inittab);
+       saa7127_write_inittab(sd, inittab);
        state->std = std;
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_output_type(struct i2c_client *client, int output)
+static int saa7127_set_output_type(struct v4l2_subdev *sd, int output)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
 
        switch (output) {
        case SAA7127_OUTPUT_TYPE_RGB:
@@ -506,165 +515,195 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
        default:
                return -EINVAL;
        }
-       v4l_dbg(1, debug, client,
+       v4l2_dbg(1, debug, sd,
                "Selecting %s output type\n", output_strs[output]);
 
        /* Configure Encoder */
-       saa7127_write(client, 0x2d, state->reg_2d);
-       saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+       saa7127_write(sd, 0x2d, state->reg_2d);
+       saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
        state->output_type = output;
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_set_input_type(struct i2c_client *client, int input)
+static int saa7127_set_input_type(struct v4l2_subdev *sd, int input)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
+       struct saa7127_state *state = to_state(sd);
 
        switch (input) {
        case SAA7127_INPUT_TYPE_NORMAL: /* avia */
-               v4l_dbg(1, debug, client, "Selecting Normal Encoder Input\n");
+               v4l2_dbg(1, debug, sd, "Selecting Normal Encoder Input\n");
                state->reg_3a_cb = 0;
                break;
 
        case SAA7127_INPUT_TYPE_TEST_IMAGE:     /* color bar */
-               v4l_dbg(1, debug, client, "Selecting Color Bar generator\n");
+               v4l2_dbg(1, debug, sd, "Selecting Color Bar generator\n");
                state->reg_3a_cb = 0x80;
                break;
 
        default:
                return -EINVAL;
        }
-       saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+       saa7127_write(sd, 0x3a, state->reg_3a | state->reg_3a_cb);
        state->input_type = input;
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_command(struct i2c_client *client,
-                          unsigned int cmd, void *arg)
+static int saa7127_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct saa7127_state *state = i2c_get_clientdata(client);
-       struct v4l2_format *fmt = arg;
-       struct v4l2_routing *route = arg;
-
-       switch (cmd) {
-       case VIDIOC_INT_S_STD_OUTPUT:
-               if (state->std == *(v4l2_std_id *)arg)
-                       break;
-               return saa7127_set_std(client, *(v4l2_std_id *)arg);
-
-       case VIDIOC_INT_G_STD_OUTPUT:
-               *(v4l2_std_id *)arg = state->std;
-               break;
+       struct saa7127_state *state = to_state(sd);
 
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = state->input_type;
-               route->output = state->output_type;
-               break;
+       if (state->std == std)
+               return 0;
+       return saa7127_set_std(sd, std);
+}
 
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-       {
-               int rc = 0;
+static int saa7127_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct saa7127_state *state = to_state(sd);
+       int rc = 0;
+
+       if (state->input_type != route->input)
+               rc = saa7127_set_input_type(sd, route->input);
+       if (rc == 0 && state->output_type != route->output)
+               rc = saa7127_set_output_type(sd, route->output);
+       return rc;
+}
 
-               if (state->input_type != route->input)
-                       rc = saa7127_set_input_type(client, route->input);
-               if (rc == 0 && state->output_type != route->output)
-                       rc = saa7127_set_output_type(client, route->output);
-               return rc;
-       }
+static int saa7127_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct saa7127_state *state = to_state(sd);
 
-       case VIDIOC_STREAMON:
-       case VIDIOC_STREAMOFF:
-               if (state->video_enable == (cmd == VIDIOC_STREAMON))
-                       break;
-               return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON);
-
-       case VIDIOC_G_FMT:
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-                       return -EINVAL;
-
-               memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
-               if (state->vps_enable)
-                       fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
-               if (state->wss_enable)
-                       fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
-               if (state->cc_enable) {
-                       fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
-                       fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
-               }
-               fmt->fmt.sliced.service_set =
-                       (state->vps_enable ? V4L2_SLICED_VPS : 0) |
-                       (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
-                       (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
-               break;
+       if (state->video_enable == enable)
+               return 0;
+       return saa7127_set_video_enable(sd, enable);
+}
 
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
-               v4l_info(client, "Input:    %s\n", state->input_type ?  "color bars" : "normal");
-               v4l_info(client, "Output:   %s\n", state->video_enable ?
-                       output_strs[state->output_type] : "disabled");
-               v4l_info(client, "WSS:      %s\n", state->wss_enable ?
-                       wss_strs[state->wss_mode] : "disabled");
-               v4l_info(client, "VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
-               v4l_info(client, "CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
-               break;
+static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct saa7127_state *state = to_state(sd);
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client,
-                                       reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = saa7127_read(client, reg->reg & 0xff);
-               else
-                       saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
-               break;
-       }
-#endif
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               return -EINVAL;
 
-       case VIDIOC_INT_S_VBI_DATA:
-       {
-               struct v4l2_sliced_vbi_data *data = arg;
-
-               switch (data->id) {
-               case V4L2_SLICED_WSS_625:
-                       return saa7127_set_wss(client, data);
-               case V4L2_SLICED_VPS:
-                       return saa7127_set_vps(client, data);
-               case V4L2_SLICED_CAPTION_525:
-                       if (data->field == 0)
-                               return saa7127_set_cc(client, data);
-                       return saa7127_set_xds(client, data);
-               default:
-                       return -EINVAL;
-               }
-               break;
+       memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
+       if (state->vps_enable)
+               fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
+       if (state->wss_enable)
+               fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+       if (state->cc_enable) {
+               fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+               fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
        }
+       fmt->fmt.sliced.service_set =
+               (state->vps_enable ? V4L2_SLICED_VPS : 0) |
+               (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+               (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+       return 0;
+}
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0);
-
+static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
+{
+       switch (data->id) {
+       case V4L2_SLICED_WSS_625:
+               return saa7127_set_wss(sd, data);
+       case V4L2_SLICED_VPS:
+               return saa7127_set_vps(sd, data);
+       case V4L2_SLICED_CAPTION_525:
+               if (data->field == 0)
+                       return saa7127_set_cc(sd, data);
+               return saa7127_set_xds(sd, data);
        default:
                return -EINVAL;
        }
        return 0;
 }
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = saa7127_read(sd, reg->reg & 0xff);
+       return 0;
+}
+
+static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       saa7127_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
+}
+#endif
+
+static int saa7127_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct saa7127_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, state->ident, 0);
+}
+
+static int saa7127_log_status(struct v4l2_subdev *sd)
+{
+       struct saa7127_state *state = to_state(sd);
+
+       v4l2_info(sd, "Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+       v4l2_info(sd, "Input:    %s\n", state->input_type ?  "color bars" : "normal");
+       v4l2_info(sd, "Output:   %s\n", state->video_enable ?
+                       output_strs[state->output_type] : "disabled");
+       v4l2_info(sd, "WSS:      %s\n", state->wss_enable ?
+                       wss_strs[state->wss_mode] : "disabled");
+       v4l2_info(sd, "VPS:      %s\n", state->vps_enable ? "enabled" : "disabled");
+       v4l2_info(sd, "CC:       %s\n", state->cc_enable ? "enabled" : "disabled");
+       return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa7127_core_ops = {
+       .log_status = saa7127_log_status,
+       .g_chip_ident = saa7127_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = saa7127_g_register,
+       .s_register = saa7127_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops saa7127_video_ops = {
+       .s_vbi_data = saa7127_s_vbi_data,
+       .g_fmt = saa7127_g_fmt,
+       .s_std_output = saa7127_s_std_output,
+       .s_routing = saa7127_s_routing,
+       .s_stream = saa7127_s_stream,
+};
+
+static const struct v4l2_subdev_ops saa7127_ops = {
+       .core = &saa7127_core_ops,
+       .video = &saa7127_video_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 static int saa7127_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct saa7127_state *state;
+       struct v4l2_subdev *sd;
        struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
 
        /* Check if the adapter supports the needed features */
@@ -674,40 +713,42 @@ static int saa7127_probe(struct i2c_client *client,
        v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
                        client->addr << 1);
 
+       state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+       if (state == NULL)
+               return -ENOMEM;
+
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa7127_ops);
+
        /* First test register 0: Bits 5-7 are a version ID (should be 0),
           and bit 2 should also be 0.
           This is rather general, so the second test is more specific and
           looks at the 'ending point of burst in clock cycles' which is
           0x1d after a reset and not expected to ever change. */
-       if ((saa7127_read(client, 0) & 0xe4) != 0 ||
-                       (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
-               v4l_dbg(1, debug, client, "saa7127 not found\n");
+       if ((saa7127_read(sd, 0) & 0xe4) != 0 ||
+                       (saa7127_read(sd, 0x29) & 0x3f) != 0x1d) {
+               v4l2_dbg(1, debug, sd, "saa7127 not found\n");
+               kfree(state);
                return -ENODEV;
        }
-       state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
-
-       if (state == NULL)
-               return -ENOMEM;
-
-       i2c_set_clientdata(client, state);
 
        /* Configure Encoder */
 
-       v4l_dbg(1, debug, client, "Configuring encoder\n");
-       saa7127_write_inittab(client, saa7127_init_config_common);
-       saa7127_set_std(client, V4L2_STD_NTSC);
-       saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
-       saa7127_set_vps(client, &vbi);
-       saa7127_set_wss(client, &vbi);
-       saa7127_set_cc(client, &vbi);
-       saa7127_set_xds(client, &vbi);
+       v4l2_dbg(1, debug, sd, "Configuring encoder\n");
+       saa7127_write_inittab(sd, saa7127_init_config_common);
+       saa7127_set_std(sd, V4L2_STD_NTSC);
+       saa7127_set_output_type(sd, SAA7127_OUTPUT_TYPE_BOTH);
+       saa7127_set_vps(sd, &vbi);
+       saa7127_set_wss(sd, &vbi);
+       saa7127_set_cc(sd, &vbi);
+       saa7127_set_xds(sd, &vbi);
        if (test_image == 1)
                /* The Encoder has an internal Colorbar generator */
                /* This can be used for debugging */
-               saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
+               saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_TEST_IMAGE);
        else
-               saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
-       saa7127_set_video_enable(client, 1);
+               saa7127_set_input_type(sd, SAA7127_INPUT_TYPE_NORMAL);
+       saa7127_set_video_enable(sd, 1);
 
        if (id->driver_data) {  /* Chip type is already known */
                state->ident = id->driver_data;
@@ -715,10 +756,10 @@ static int saa7127_probe(struct i2c_client *client,
                int read_result;
 
                /* Detect if it's an saa7129 */
-               read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
-               saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
-               if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
-                       saa7127_write(client, SAA7129_REG_FADE_KEY_COL2,
+               read_result = saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2);
+               saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+               if (saa7127_read(sd, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+                       saa7127_write(sd, SAA7129_REG_FADE_KEY_COL2,
                                        read_result);
                        state->ident = V4L2_IDENT_SAA7129;
                        strlcpy(client->name, "saa7129", I2C_NAME_SIZE);
@@ -728,10 +769,10 @@ static int saa7127_probe(struct i2c_client *client,
                }
        }
 
-       v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+       v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
                        client->addr << 1, client->adapter->name);
        if (state->ident == V4L2_IDENT_SAA7129)
-               saa7127_write_inittab(client, saa7129_init_config_extra);
+               saa7127_write_inittab(sd, saa7129_init_config_extra);
        return 0;
 }
 
@@ -739,9 +780,12 @@ static int saa7127_probe(struct i2c_client *client,
 
 static int saa7127_remove(struct i2c_client *client)
 {
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
        /* Turn off TV output */
-       saa7127_set_video_enable(client, 0);
-       kfree(i2c_get_clientdata(client));
+       saa7127_set_video_enable(sd, 0);
+       kfree(to_state(sd));
        return 0;
 }
 
@@ -760,7 +804,6 @@ MODULE_DEVICE_TABLE(i2c, saa7127_id);
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "saa7127",
        .driverid = I2C_DRIVERID_SAA7127,
-       .command = saa7127_command,
        .probe = saa7127_probe,
        .remove = saa7127_remove,
        .id_table = saa7127_id,
index ddc5402c5fb071c1db008c77e506d009fbcd4915..a2e3f6729c5b1ad709fc9749d17054a93c3188e4 100644 (file)
@@ -4606,6 +4606,43 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio   = 0x0200000,
                },
        },
+       [SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = {
+               .name           = "Kworld Plus TV Analog Lite PCI",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_YMEC_TVF_5533MF,
+               .radio_type     = TUNER_TEA5767,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .gpiomask       = 0x80000700,
+               .inputs = { {
+                       .name   = name_tv,
+                       .vmux   = 1,
+                       .amux   = LINE2,
+                       .tv     = 1,
+                       .gpio   = 0x100,
+               }, {
+                       .name   = name_comp1,
+                       .vmux   = 3,
+                       .amux   = LINE1,
+                       .gpio   = 0x200,
+               }, {
+                       .name   = name_svideo,
+                       .vmux   = 8,
+                       .amux   = LINE1,
+                       .gpio   = 0x200,
+               } },
+               .radio = {
+                       .name   = name_radio,
+                       .vmux   = 1,
+                       .amux   = LINE1,
+                       .gpio   = 0x100,
+               },
+               .mute = {
+                       .name = name_mute,
+                       .vmux = 8,
+                       .amux = 2,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4735,6 +4772,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0x0003,
                .driver_data  = SAA7134_BOARD_MD7134,
        },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */
+               .subdevice    = 0x5000, /* only analog TV and DVB-T for now */
+               .driver_data  = SAA7134_BOARD_MD7134,
+       }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                .subvendor    = 0x1048,
@@ -5652,6 +5695,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1043,
                .subdevice    = 0x4878, /* REV:1.02G */
                .driver_data  = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x17de,
+               .subdevice    = 0x7128,
+               .driver_data  = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG,
        }, {
                /* --- boards without eeprom + subsystem ID --- */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -5880,6 +5929,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_507_9FM:
        case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
        case SAA7134_BOARD_REAL_ANGEL_220:
+       case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
                dev->has_remote = SAA7134_REMOTE_GPIO;
                break;
        case SAA7134_BOARD_FLYDVBS_LR300:
@@ -6048,7 +6098,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
                struct v4l2_priv_tun_config  xc2028_cfg;
                struct xc2028_ctrl           ctl;
 
-               memset(&xc2028_cfg, 0, sizeof(ctl));
+               memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
                memset(&ctl, 0, sizeof(ctl));
 
                ctl.fname   = XC2028_DEFAULT_FIRMWARE;
index 8c46115d4c7980a34f672ec75a4179848a11d3d7..d9a5652595b525d16827da87af1bf9de56a88a57 100644 (file)
@@ -954,20 +954,14 @@ static int dvb_init(struct saa7134_dev *dev)
        /* FIXME: add support for multi-frontend */
        mutex_init(&dev->frontends.lock);
        INIT_LIST_HEAD(&dev->frontends.felist);
-       dev->frontends.active_fe_id = 0;
 
        printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
-
-       if (videobuf_dvb_alloc_frontend(&dev->frontends, 1) == NULL) {
+       fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
+       if (!fe0) {
                printk(KERN_ERR "%s() failed to alloc\n", __func__);
                return -ENOMEM;
        }
 
-       /* Get the first frontend */
-       fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
-       if (!fe0)
-               return -EINVAL;
-
        /* init struct videobuf_dvb */
        dev->ts.nr_bufs    = 32;
        dev->ts.nr_packets = 32*4;
@@ -1376,7 +1370,7 @@ static int dvb_init(struct saa7134_dev *dev)
                };
 
                if (!fe0->dvb.frontend)
-                       return -1;
+                       goto dettach_frontend;
 
                fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
                if (!fe) {
@@ -1388,7 +1382,7 @@ static int dvb_init(struct saa7134_dev *dev)
 
        if (NULL == fe0->dvb.frontend) {
                printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
-               return -1;
+               goto dettach_frontend;
        }
        /* define general-purpose callback pointer */
        fe0->dvb.frontend->callback = saa7134_tuner_callback;
@@ -1411,11 +1405,8 @@ static int dvb_init(struct saa7134_dev *dev)
        return ret;
 
 dettach_frontend:
-       if (fe0->dvb.frontend)
-               dvb_frontend_detach(fe0->dvb.frontend);
-       fe0->dvb.frontend = NULL;
-
-       return -1;
+       videobuf_dvb_dealloc_frontends(&dev->frontends);
+       return -EINVAL;
 }
 
 static int dvb_fini(struct saa7134_dev *dev)
@@ -1454,8 +1445,7 @@ static int dvb_fini(struct saa7134_dev *dev)
                        }
                }
        }
-       if (fe0->dvb.frontend)
-               videobuf_dvb_unregister_bus(&dev->frontends);
+       videobuf_dvb_unregister_bus(&dev->frontends);
        return 0;
 }
 
index c53fd5f9f6b553bac073483b5c69ced28f7d6967..d2124f64e4e2339a6d140e0bc83a72b011c0c766 100644 (file)
@@ -97,6 +97,15 @@ static int build_key(struct saa7134_dev *dev)
        dprintk("build_key gpio=0x%x mask=0x%x data=%d\n",
                gpio, ir->mask_keycode, data);
 
+       switch (dev->board) {
+       case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+               if (data == ir->mask_keycode)
+                       ir_input_nokey(ir->dev, &ir->ir);
+               else
+                       ir_input_keydown(ir->dev, &ir->ir, data, data);
+               return 0;
+       }
+
        if (ir->polling) {
                if ((ir->mask_keydown  &&  (0 != (gpio & ir->mask_keydown))) ||
                    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
@@ -586,6 +595,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
                mask_keyup   = 0x4000;
                polling = 50; /* ms */
                break;
+       case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+               ir_codes     = ir_codes_kworld_plus_tv_analog;
+               mask_keycode = 0x7f;
+               polling = 40; /* ms */
+               break;
        }
        if (NULL == ir_codes) {
                printk("%s: Oops: IR config error [card=%d]\n",
index c5d0b44c179e02e8b8f66b4cafbb0346771300f3..76b16407b01e89ac3b7e0ef8cb8cd94869da0a03 100644 (file)
@@ -159,7 +159,7 @@ static struct saa7134_tvaudio tvaudio[] = {
                .mode          = TVAUDIO_FM_MONO,
        }
 };
-#define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio))
+#define TVAUDIO ARRAY_SIZE(tvaudio)
 
 /* ------------------------------------------------------------------ */
 
index 24096d6e1ef8071037148334ce2948b736b09d54..f6c1fcc720701cc04c74fe6029a0b0f3acfff942 100644 (file)
@@ -275,8 +275,9 @@ struct saa7134_format {
 #define SAA7134_BOARD_REAL_ANGEL_220     150
 #define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI  151
 #define SAA7134_BOARD_ASUSTeK_TIGER         152
+#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
 
-#define SAA7134_MAXBOARDS 8
+#define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
 
 /* ----------------------------------------------------------- */
index af60ede5310d2bcc9acf0f7e12088e759e242d90..9befca65905e0e6dee10882f240fac2d361b1b99 100644 (file)
@@ -37,7 +37,7 @@
 
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
@@ -54,6 +54,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
  */
 
 struct saa717x_state {
+       struct v4l2_subdev sd;
        v4l2_std_id std;
        int input;
        int enable;
@@ -75,6 +76,11 @@ struct saa717x_state {
        int audio_input;
 };
 
+static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct saa717x_state, sd);
+}
+
 /* ----------------------------------------------------------------------- */
 
 /* for audio mode */
@@ -88,8 +94,9 @@ struct saa717x_state {
 
 /* ----------------------------------------------------------------------- */
 
-static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
+static int saa717x_write(struct v4l2_subdev *sd, u32 reg, u32 value)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct i2c_adapter *adap = client->adapter;
        int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
        unsigned char mm1[6];
@@ -109,20 +116,21 @@ static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
        }
        msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
        msg.buf = mm1;
-       v4l_dbg(2, debug, client, "wrote:  reg 0x%03x=%08x\n", reg, value);
+       v4l2_dbg(2, debug, sd, "wrote:  reg 0x%03x=%08x\n", reg, value);
        return i2c_transfer(adap, &msg, 1) == 1;
 }
 
-static void saa717x_write_regs(struct i2c_client *client, u32 *data)
+static void saa717x_write_regs(struct v4l2_subdev *sd, u32 *data)
 {
        while (data[0] || data[1]) {
-               saa717x_write(client, data[0], data[1]);
+               saa717x_write(sd, data[0], data[1]);
                data += 2;
        }
 }
 
-static u32 saa717x_read(struct i2c_client *client, u32 reg)
+static u32 saa717x_read(struct v4l2_subdev *sd, u32 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct i2c_adapter *adap = client->adapter;
        int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
        unsigned char mm1[2];
@@ -146,7 +154,7 @@ static u32 saa717x_read(struct i2c_client *client, u32 reg)
        else
                value = mm2[0] & 0xff;
 
-       v4l_dbg(2, debug, client, "read:  reg 0x%03x=0x%08x\n", reg, value);
+       v4l2_dbg(2, debug, sd, "read:  reg 0x%03x=0x%08x\n", reg, value);
        return value;
 }
 
@@ -680,7 +688,7 @@ static u32 reg_set_audio_template[4][2] =
 
 
 /* Get detected audio flags (from saa7134 driver) */
-static void get_inf_dev_status(struct i2c_client *client,
+static void get_inf_dev_status(struct v4l2_subdev *sd,
                int *dual_flag, int *stereo_flag)
 {
        u32 reg_data3;
@@ -719,13 +727,13 @@ static void get_inf_dev_status(struct i2c_client *client,
        /* (demdec status: 0x528) */
 
        /* read current status */
-       reg_data3 = saa717x_read(client, 0x0528);
+       reg_data3 = saa717x_read(sd, 0x0528);
 
-       v4l_dbg(1, debug, client, "tvaudio thread status: 0x%x [%s%s%s]\n",
+       v4l2_dbg(1, debug, sd, "tvaudio thread status: 0x%x [%s%s%s]\n",
                reg_data3, stdres[reg_data3 & 0x1f],
                (reg_data3 & 0x000020) ? ",stereo" : "",
                (reg_data3 & 0x000040) ? ",dual"   : "");
-       v4l_dbg(1, debug, client, "detailed status: "
+       v4l2_dbg(1, debug, sd, "detailed status: "
                "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
                (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone "     : "",
                (reg_data3 & 0x000100) ? " A2/EIAJ dual "           : "",
@@ -746,51 +754,51 @@ static void get_inf_dev_status(struct i2c_client *client,
                (reg_data3 & 0x100000) ? " init done "              : "");
 
        if (reg_data3 & 0x000220) {
-               v4l_dbg(1, debug, client, "ST!!!\n");
+               v4l2_dbg(1, debug, sd, "ST!!!\n");
                *stereo_flag = 1;
        }
 
        if (reg_data3 & 0x000140) {
-               v4l_dbg(1, debug, client, "DUAL!!!\n");
+               v4l2_dbg(1, debug, sd, "DUAL!!!\n");
                *dual_flag = 1;
        }
 }
 
 /* regs write to set audio mode */
-static void set_audio_mode(struct i2c_client *client, int audio_mode)
+static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
 {
-       v4l_dbg(1, debug, client, "writing registers to set audio mode by set %d\n",
+       v4l2_dbg(1, debug, sd, "writing registers to set audio mode by set %d\n",
                        audio_mode);
 
-       saa717x_write(client, 0x46c, reg_set_audio_template[audio_mode][0]);
-       saa717x_write(client, 0x470, reg_set_audio_template[audio_mode][1]);
+       saa717x_write(sd, 0x46c, reg_set_audio_template[audio_mode][0]);
+       saa717x_write(sd, 0x470, reg_set_audio_template[audio_mode][1]);
 }
 
 /* write regs to video output level (bright,contrast,hue,sat) */
-static void set_video_output_level_regs(struct i2c_client *client,
+static void set_video_output_level_regs(struct v4l2_subdev *sd,
                struct saa717x_state *decoder)
 {
        /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
-       saa717x_write(client, 0x10a, decoder->bright);
+       saa717x_write(sd, 0x10a, decoder->bright);
 
        /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
           0h (luminance off) 40: i2c dump
           c0h (-1.0 inverse chrominance)
           80h (-2.0 inverse chrominance) */
-       saa717x_write(client, 0x10b, decoder->contrast);
+       saa717x_write(sd, 0x10b, decoder->contrast);
 
        /* saturation? 7fh(max)-40h(ITU)-0h(color off)
           c0h (-1.0 inverse chrominance)
           80h (-2.0 inverse chrominance) */
-       saa717x_write(client, 0x10c, decoder->sat);
+       saa717x_write(sd, 0x10c, decoder->sat);
 
        /* color hue (phase) control
           7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
-       saa717x_write(client, 0x10d, decoder->hue);
+       saa717x_write(sd, 0x10d, decoder->hue);
 }
 
 /* write regs to set audio volume, bass and treble */
-static int set_audio_regs(struct i2c_client *client,
+static int set_audio_regs(struct v4l2_subdev *sd,
                struct saa717x_state *decoder)
 {
        u8 mute = 0xac; /* -84 dB */
@@ -798,8 +806,8 @@ static int set_audio_regs(struct i2c_client *client,
        unsigned int work_l, work_r;
 
        /* set SIF analog I/O select */
-       saa717x_write(client, 0x0594, decoder->audio_input);
-       v4l_dbg(1, debug, client, "set audio input %d\n",
+       saa717x_write(sd, 0x0594, decoder->audio_input);
+       v4l2_dbg(1, debug, sd, "set audio input %d\n",
                        decoder->audio_input);
 
        /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
@@ -819,17 +827,17 @@ static int set_audio_regs(struct i2c_client *client,
                        ((u8)decoder->audio_main_vol_r << 8);
        }
 
-       saa717x_write(client, 0x480, val);
+       saa717x_write(sd, 0x480, val);
 
        /* bass and treble; go to another function */
        /* set bass and treble */
        val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
-       saa717x_write(client, 0x488, val);
+       saa717x_write(sd, 0x488, val);
        return 0;
 }
 
 /********** scaling staff ***********/
-static void set_h_prescale(struct i2c_client *client,
+static void set_h_prescale(struct v4l2_subdev *sd,
                int task, int prescale)
 {
        static const struct {
@@ -862,107 +870,101 @@ static void set_h_prescale(struct i2c_client *client,
                return;
 
        /* horizonal prescaling */
-       saa717x_write(client, 0x60 + task_shift, vals[i].xpsc);
+       saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc);
        /* accumulation length */
-       saa717x_write(client, 0x61 + task_shift, vals[i].xacl);
+       saa717x_write(sd, 0x61 + task_shift, vals[i].xacl);
        /* level control */
-       saa717x_write(client, 0x62 + task_shift,
+       saa717x_write(sd, 0x62 + task_shift,
                        (vals[i].xc2_1 << 3) | vals[i].xdcg);
        /*FIR prefilter control */
-       saa717x_write(client, 0x63 + task_shift,
+       saa717x_write(sd, 0x63 + task_shift,
                        (vals[i].vpfy << 2) | vals[i].vpfy);
 }
 
 /********** scaling staff ***********/
-static void set_v_scale(struct i2c_client *client, int task, int yscale)
+static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
 {
        int task_shift;
 
        task_shift = task * 0x40;
        /* Vertical scaling ratio (LOW) */
-       saa717x_write(client, 0x70 + task_shift, yscale & 0xff);
+       saa717x_write(sd, 0x70 + task_shift, yscale & 0xff);
        /* Vertical scaling ratio (HI) */
-       saa717x_write(client, 0x71 + task_shift, yscale >> 8);
-}
-
-static int saa717x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
-{
-       /* not yet implament, so saa717x_cfg_??hz_??_audio is not defined. */
-       return 0;
+       saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
 }
 
-static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct saa717x_state *state = i2c_get_clientdata(client);
+       struct saa717x_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                if (ctrl->value < 0 || ctrl->value > 255) {
-                       v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->bright = ctrl->value;
-               v4l_dbg(1, debug, client, "bright:%d\n", state->bright);
-               saa717x_write(client, 0x10a, state->bright);
+               v4l2_dbg(1, debug, sd, "bright:%d\n", state->bright);
+               saa717x_write(sd, 0x10a, state->bright);
                break;
 
        case V4L2_CID_CONTRAST:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->contrast = ctrl->value;
-               v4l_dbg(1, debug, client, "contrast:%d\n", state->contrast);
-               saa717x_write(client, 0x10b, state->contrast);
+               v4l2_dbg(1, debug, sd, "contrast:%d\n", state->contrast);
+               saa717x_write(sd, 0x10b, state->contrast);
                break;
 
        case V4L2_CID_SATURATION:
                if (ctrl->value < 0 || ctrl->value > 127) {
-                       v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->sat = ctrl->value;
-               v4l_dbg(1, debug, client, "sat:%d\n", state->sat);
-               saa717x_write(client, 0x10c, state->sat);
+               v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
+               saa717x_write(sd, 0x10c, state->sat);
                break;
 
        case V4L2_CID_HUE:
                if (ctrl->value < -127 || ctrl->value > 127) {
-                       v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+                       v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
                        return -ERANGE;
                }
 
                state->hue = ctrl->value;
-               v4l_dbg(1, debug, client, "hue:%d\n", state->hue);
-               saa717x_write(client, 0x10d, state->hue);
+               v4l2_dbg(1, debug, sd, "hue:%d\n", state->hue);
+               saa717x_write(sd, 0x10d, state->hue);
                break;
 
        case V4L2_CID_AUDIO_MUTE:
                state->audio_main_mute = ctrl->value;
-               set_audio_regs(client, state);
+               set_audio_regs(sd, state);
                break;
 
        case V4L2_CID_AUDIO_VOLUME:
                state->audio_main_volume = ctrl->value;
-               set_audio_regs(client, state);
+               set_audio_regs(sd, state);
                break;
 
        case V4L2_CID_AUDIO_BALANCE:
                state->audio_main_balance = ctrl->value;
-               set_audio_regs(client, state);
+               set_audio_regs(sd, state);
                break;
 
        case V4L2_CID_AUDIO_TREBLE:
                state->audio_main_treble = ctrl->value;
-               set_audio_regs(client, state);
+               set_audio_regs(sd, state);
                break;
 
        case V4L2_CID_AUDIO_BASS:
                state->audio_main_bass = ctrl->value;
-               set_audio_regs(client, state);
+               set_audio_regs(sd, state);
                break;
 
        default:
@@ -972,9 +974,9 @@ static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
        return 0;
 }
 
-static int saa717x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct saa717x_state *state = i2c_get_clientdata(client);
+       struct saa717x_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -1103,13 +1105,15 @@ static struct v4l2_queryctrl saa717x_qctrl[] = {
        },
 };
 
-static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_state *decoder, int inp)
+static int saa717x_s_video_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
+       struct saa717x_state *decoder = to_state(sd);
+       int inp = route->input;
        int is_tuner = inp & 0x80;  /* tuner input flag */
 
        inp &= 0x7f;
 
-       v4l_dbg(1, debug, client, "decoder set input (%d)\n", inp);
+       v4l2_dbg(1, debug, sd, "decoder set input (%d)\n", inp);
        /* inputs from 0-9 are available*/
        /* saa717x have mode0-mode9 but mode5 is reserved. */
        if (inp < 0 || inp > 9 || inp == 5)
@@ -1119,222 +1123,197 @@ static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_sta
                int input_line = inp;
 
                decoder->input = input_line;
-               v4l_dbg(1, debug, client,  "now setting %s input %d\n",
+               v4l2_dbg(1, debug, sd,  "now setting %s input %d\n",
                                input_line >= 6 ? "S-Video" : "Composite",
                                input_line);
 
                /* select mode */
-               saa717x_write(client, 0x102,
-                               (saa717x_read(client, 0x102) & 0xf0) |
+               saa717x_write(sd, 0x102,
+                               (saa717x_read(sd, 0x102) & 0xf0) |
                                input_line);
 
                /* bypass chrominance trap for modes 6..9 */
-               saa717x_write(client, 0x109,
-                               (saa717x_read(client, 0x109) & 0x7f) |
+               saa717x_write(sd, 0x109,
+                               (saa717x_read(sd, 0x109) & 0x7f) |
                                (input_line < 6 ? 0x0 : 0x80));
 
                /* change audio_mode */
                if (is_tuner) {
                        /* tuner */
-                       set_audio_mode(client, decoder->tuner_audio_mode);
+                       set_audio_mode(sd, decoder->tuner_audio_mode);
                } else {
                        /* Force to STEREO mode if Composite or
                         * S-Video were chosen */
-                       set_audio_mode(client, TUNER_AUDIO_STEREO);
+                       set_audio_mode(sd, TUNER_AUDIO_STEREO);
                }
                /* change initialize procedure (Composite/S-Video) */
                if (is_tuner)
-                       saa717x_write_regs(client, reg_init_tuner_input);
+                       saa717x_write_regs(sd, reg_init_tuner_input);
                else if (input_line >= 6)
-                       saa717x_write_regs(client, reg_init_svideo_input);
+                       saa717x_write_regs(sd, reg_init_svideo_input);
                else
-                       saa717x_write_regs(client, reg_init_composite_input);
+                       saa717x_write_regs(sd, reg_init_composite_input);
        }
 
        return 0;
 }
 
-static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
-       struct saa717x_state *decoder = i2c_get_clientdata(client);
-
-       v4l_dbg(1, debug, client, "IOCTL: %08x\n", cmd);
+       int i;
 
-       switch (cmd) {
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               return saa717x_set_audio_clock_freq(client, *(u32 *)arg);
+       for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
+               if (qc->id && qc->id == saa717x_qctrl[i].id) {
+                       memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
+                       return 0;
+               }
+       return -EINVAL;
+}
 
-       case VIDIOC_G_CTRL:
-               return saa717x_get_v4lctrl(client, (struct v4l2_control *)arg);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_S_CTRL:
-               return saa717x_set_v4lctrl(client, (struct v4l2_control *)arg);
+       if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = saa717x_read(sd, reg->reg);
+       return 0;
+}
 
-       case VIDIOC_QUERYCTRL: {
-               struct v4l2_queryctrl *qc = arg;
-               int i;
+static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 addr = reg->reg & 0xffff;
+       u8 val = reg->val & 0xff;
 
-               for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
-                       if (qc->id && qc->id == saa717x_qctrl[i].id) {
-                               memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
-                               return 0;
-                       }
+       if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
                return -EINVAL;
-       }
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER: {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               reg->val = saa717x_read(client, reg->reg);
-               break;
-       }
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       saa717x_write(sd, addr, val);
+       return 0;
+}
+#endif
 
-       case VIDIOC_DBG_S_REGISTER: {
-               struct v4l2_register *reg = arg;
-               u16 addr = reg->reg & 0xffff;
-               u8 val = reg->val & 0xff;
+static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct v4l2_pix_format *pix;
+       int prescale, h_scale, v_scale;
 
-               if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               saa717x_write(client, addr, val);
-               break;
-       }
-#endif
+       pix = &fmt->fmt.pix;
+       v4l2_dbg(1, debug, sd, "decoder set size\n");
 
-       case VIDIOC_S_FMT: {
-               struct v4l2_format *fmt = (struct v4l2_format *)arg;
-               struct v4l2_pix_format *pix;
-               int prescale, h_scale, v_scale;
-
-               pix = &fmt->fmt.pix;
-               v4l_dbg(1, debug, client, "decoder set size\n");
-
-               /* FIXME need better bounds checking here */
-               if (pix->width < 1 || pix->width > 1440)
-                       return -EINVAL;
-               if (pix->height < 1 || pix->height > 960)
-                       return -EINVAL;
-
-               /* scaling setting */
-               /* NTSC and interlace only */
-               prescale = SAA717X_NTSC_WIDTH / pix->width;
-               if (prescale == 0)
-                       prescale = 1;
-               h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
-               /* interlace */
-               v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
-
-               /* Horizontal prescaling etc */
-               set_h_prescale(client, 0, prescale);
-               set_h_prescale(client, 1, prescale);
-
-               /* Horizontal scaling increment */
-               /* TASK A */
-               saa717x_write(client, 0x6C, (u8)(h_scale & 0xFF));
-               saa717x_write(client, 0x6D, (u8)((h_scale >> 8) & 0xFF));
-               /* TASK B */
-               saa717x_write(client, 0xAC, (u8)(h_scale & 0xFF));
-               saa717x_write(client, 0xAD, (u8)((h_scale >> 8) & 0xFF));
-
-               /* Vertical prescaling etc */
-               set_v_scale(client, 0, v_scale);
-               set_v_scale(client, 1, v_scale);
-
-               /* set video output size */
-               /* video number of pixels at output */
-               /* TASK A */
-               saa717x_write(client, 0x5C, (u8)(pix->width & 0xFF));
-               saa717x_write(client, 0x5D, (u8)((pix->width >> 8) & 0xFF));
-               /* TASK B */
-               saa717x_write(client, 0x9C, (u8)(pix->width & 0xFF));
-               saa717x_write(client, 0x9D, (u8)((pix->width >> 8) & 0xFF));
-
-               /* video number of lines at output */
-               /* TASK A */
-               saa717x_write(client, 0x5E, (u8)(pix->height & 0xFF));
-               saa717x_write(client, 0x5F, (u8)((pix->height >> 8) & 0xFF));
-               /* TASK B */
-               saa717x_write(client, 0x9E, (u8)(pix->height & 0xFF));
-               saa717x_write(client, 0x9F, (u8)((pix->height >> 8) & 0xFF));
-               break;
-       }
+       /* FIXME need better bounds checking here */
+       if (pix->width < 1 || pix->width > 1440)
+               return -EINVAL;
+       if (pix->height < 1 || pix->height > 960)
+               return -EINVAL;
 
-       case AUDC_SET_RADIO:
-               decoder->radio = 1;
-               break;
+       /* scaling setting */
+       /* NTSC and interlace only */
+       prescale = SAA717X_NTSC_WIDTH / pix->width;
+       if (prescale == 0)
+               prescale = 1;
+       h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+       /* interlace */
+       v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+
+       /* Horizontal prescaling etc */
+       set_h_prescale(sd, 0, prescale);
+       set_h_prescale(sd, 1, prescale);
+
+       /* Horizontal scaling increment */
+       /* TASK A */
+       saa717x_write(sd, 0x6C, (u8)(h_scale & 0xFF));
+       saa717x_write(sd, 0x6D, (u8)((h_scale >> 8) & 0xFF));
+       /* TASK B */
+       saa717x_write(sd, 0xAC, (u8)(h_scale & 0xFF));
+       saa717x_write(sd, 0xAD, (u8)((h_scale >> 8) & 0xFF));
+
+       /* Vertical prescaling etc */
+       set_v_scale(sd, 0, v_scale);
+       set_v_scale(sd, 1, v_scale);
+
+       /* set video output size */
+       /* video number of pixels at output */
+       /* TASK A */
+       saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF));
+       saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF));
+       /* TASK B */
+       saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
+       saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+
+       /* video number of lines at output */
+       /* TASK A */
+       saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF));
+       saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF));
+       /* TASK B */
+       saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
+       saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+       return 0;
+}
 
-       case VIDIOC_S_STD: {
-               v4l2_std_id std = *(v4l2_std_id *) arg;
+static int saa717x_s_radio(struct v4l2_subdev *sd)
+{
+       struct saa717x_state *decoder = to_state(sd);
 
-               v4l_dbg(1, debug, client, "decoder set norm ");
-               v4l_dbg(1, debug, client, "(not yet implementd)\n");
+       decoder->radio = 1;
+       return 0;
+}
 
-               decoder->radio = 0;
-               decoder->std = std;
-               break;
-       }
+static int saa717x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct saa717x_state *decoder = to_state(sd);
 
-       case VIDIOC_INT_G_AUDIO_ROUTING: {
-               struct v4l2_routing *route = arg;
+       v4l2_dbg(1, debug, sd, "decoder set norm ");
+       v4l2_dbg(1, debug, sd, "(not yet implementd)\n");
 
-               route->input = decoder->audio_input;
-               route->output = 0;
-               break;
-       }
+       decoder->radio = 0;
+       decoder->std = std;
+       return 0;
+}
 
-       case VIDIOC_INT_S_AUDIO_ROUTING: {
-               struct v4l2_routing *route = arg;
+static int saa717x_s_audio_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct saa717x_state *decoder = to_state(sd);
 
-               if (route->input < 3) { /* FIXME! --tadachi */
-                       decoder->audio_input = route->input;
-                       v4l_dbg(1, debug, client,
+       if (route->input < 3) { /* FIXME! --tadachi */
+               decoder->audio_input = route->input;
+               v4l2_dbg(1, debug, sd,
                                "set decoder audio input to %d\n",
                                decoder->audio_input);
-                       set_audio_regs(client, decoder);
-                       break;
-               }
-               return -ERANGE;
-       }
-
-       case VIDIOC_INT_S_VIDEO_ROUTING: {
-               struct v4l2_routing *route = arg;
-               int inp = route->input;
-
-               return saa717x_set_video_input(client, decoder, inp);
+               set_audio_regs(sd, decoder);
+               return 0;
        }
+       return -ERANGE;
+}
 
-       case VIDIOC_STREAMON: {
-               v4l_dbg(1, debug, client, "decoder enable output\n");
-               decoder->enable = 1;
-               saa717x_write(client, 0x193, 0xa6);
-               break;
-       }
+static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct saa717x_state *decoder = to_state(sd);
 
-       case VIDIOC_STREAMOFF: {
-               v4l_dbg(1, debug, client, "decoder disable output\n");
-               decoder->enable = 0;
-               saa717x_write(client, 0x193, 0x26); /* right? FIXME!--tadachi */
-               break;
-       }
+       v4l2_dbg(1, debug, sd, "decoder %s output\n",
+                       enable ? "enable" : "disable");
+       decoder->enable = enable;
+       saa717x_write(sd, 0x193, enable ? 0xa6 : 0x26);
+       return 0;
+}
 
-               /* change audio mode */
-       case VIDIOC_S_TUNER: {
-               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
-               int audio_mode;
-               char *mes[4] = {
-                       "MONO", "STEREO", "LANG1", "LANG2/SAP"
-               };
+/* change audio mode */
+static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct saa717x_state *decoder = to_state(sd);
+       int audio_mode;
+       char *mes[4] = {
+               "MONO", "STEREO", "LANG1", "LANG2/SAP"
+       };
 
-               audio_mode = V4L2_TUNER_MODE_STEREO;
+       audio_mode = V4L2_TUNER_MODE_STEREO;
 
-               switch (vt->audmode) {
+       switch (vt->audmode) {
                case V4L2_TUNER_MODE_MONO:
                        audio_mode = TUNER_AUDIO_MONO;
                        break;
@@ -1347,70 +1326,101 @@ static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
                case V4L2_TUNER_MODE_LANG1:
                        audio_mode = TUNER_AUDIO_LANG1;
                        break;
-               }
-
-               v4l_dbg(1, debug, client, "change audio mode to %s\n",
-                               mes[audio_mode]);
-               decoder->tuner_audio_mode = audio_mode;
-               /* The registers are not changed here. */
-               /* See DECODER_ENABLE_OUTPUT section. */
-               set_audio_mode(client, decoder->tuner_audio_mode);
-               break;
        }
 
-       case VIDIOC_G_TUNER: {
-               struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
-               int dual_f, stereo_f;
+       v4l2_dbg(1, debug, sd, "change audio mode to %s\n",
+                       mes[audio_mode]);
+       decoder->tuner_audio_mode = audio_mode;
+       /* The registers are not changed here. */
+       /* See DECODER_ENABLE_OUTPUT section. */
+       set_audio_mode(sd, decoder->tuner_audio_mode);
+       return 0;
+}
 
-               if (decoder->radio)
-                       break;
-               get_inf_dev_status(client, &dual_f, &stereo_f);
+static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct saa717x_state *decoder = to_state(sd);
+       int dual_f, stereo_f;
 
-               v4l_dbg(1, debug, client, "DETECT==st:%d dual:%d\n",
-                               stereo_f, dual_f);
+       if (decoder->radio)
+               return 0;
+       get_inf_dev_status(sd, &dual_f, &stereo_f);
 
-               /* mono */
-               if ((dual_f == 0) && (stereo_f == 0)) {
-                       vt->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       v4l_dbg(1, debug, client, "DETECT==MONO\n");
-               }
+       v4l2_dbg(1, debug, sd, "DETECT==st:%d dual:%d\n",
+                       stereo_f, dual_f);
 
-               /* stereo */
-               if (stereo_f == 1) {
-                       if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
-                           vt->audmode == V4L2_TUNER_MODE_LANG1) {
-                               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                               v4l_dbg(1, debug, client, "DETECT==ST(ST)\n");
-                       } else {
-                               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
-                               v4l_dbg(1, debug, client, "DETECT==ST(MONO)\n");
-                       }
-               }
+       /* mono */
+       if ((dual_f == 0) && (stereo_f == 0)) {
+               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+               v4l2_dbg(1, debug, sd, "DETECT==MONO\n");
+       }
 
-               /* dual */
-               if (dual_f == 1) {
-                       if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
-                               vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
-                               v4l_dbg(1, debug, client, "DETECT==DUAL1\n");
-                       } else {
-                               vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
-                               v4l_dbg(1, debug, client, "DETECT==DUAL2\n");
-                       }
+       /* stereo */
+       if (stereo_f == 1) {
+               if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
+                               vt->audmode == V4L2_TUNER_MODE_LANG1) {
+                       vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+                       v4l2_dbg(1, debug, sd, "DETECT==ST(ST)\n");
+               } else {
+                       vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+                       v4l2_dbg(1, debug, sd, "DETECT==ST(MONO)\n");
                }
-               break;
        }
 
-       case VIDIOC_LOG_STATUS:
-               /* not yet implemented */
-               break;
-
-       default:
-               return -EINVAL;
+       /* dual */
+       if (dual_f == 1) {
+               if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
+                       vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
+                       v4l2_dbg(1, debug, sd, "DETECT==DUAL1\n");
+               } else {
+                       vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
+                       v4l2_dbg(1, debug, sd, "DETECT==DUAL2\n");
+               }
        }
-
        return 0;
 }
 
+static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops saa717x_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = saa717x_g_register,
+       .s_register = saa717x_s_register,
+#endif
+       .queryctrl = saa717x_queryctrl,
+       .g_ctrl = saa717x_g_ctrl,
+       .s_ctrl = saa717x_s_ctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
+       .g_tuner = saa717x_g_tuner,
+       .s_tuner = saa717x_s_tuner,
+       .s_std = saa717x_s_std,
+       .s_radio = saa717x_s_radio,
+};
+
+static const struct v4l2_subdev_video_ops saa717x_video_ops = {
+       .s_routing = saa717x_s_video_routing,
+       .s_fmt = saa717x_s_fmt,
+       .s_stream = saa717x_s_stream,
+};
+
+static const struct v4l2_subdev_audio_ops saa717x_audio_ops = {
+       .s_routing = saa717x_s_audio_routing,
+};
+
+static const struct v4l2_subdev_ops saa717x_ops = {
+       .core = &saa717x_core_ops,
+       .tuner = &saa717x_tuner_ops,
+       .audio = &saa717x_audio_ops,
+       .video = &saa717x_video_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 
@@ -1421,6 +1431,7 @@ static int saa717x_probe(struct i2c_client *client,
                         const struct i2c_device_id *did)
 {
        struct saa717x_state *decoder;
+       struct v4l2_subdev *sd;
        u8 id = 0;
        char *p = "";
 
@@ -1428,13 +1439,21 @@ static int saa717x_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       if (saa717x_write(client, 0x5a4, 0xfe) &&
-                       saa717x_write(client, 0x5a5, 0x0f) &&
-                       saa717x_write(client, 0x5a6, 0x00) &&
-                       saa717x_write(client, 0x5a7, 0x01))
-               id = saa717x_read(client, 0x5a0);
+       decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+       if (decoder == NULL)
+               return -ENOMEM;
+
+       sd = &decoder->sd;
+       v4l2_i2c_subdev_init(sd, client, &saa717x_ops);
+
+       if (saa717x_write(sd, 0x5a4, 0xfe) &&
+                       saa717x_write(sd, 0x5a5, 0x0f) &&
+                       saa717x_write(sd, 0x5a6, 0x00) &&
+                       saa717x_write(sd, 0x5a7, 0x01))
+               id = saa717x_read(sd, 0x5a0);
        if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
-               v4l_dbg(1, debug, client, "saa717x not found (id=%02x)\n", id);
+               v4l2_dbg(1, debug, sd, "saa717x not found (id=%02x)\n", id);
+               kfree(decoder);
                return -ENODEV;
        }
        if (id == 0xc2)
@@ -1445,14 +1464,8 @@ static int saa717x_probe(struct i2c_client *client,
                p = "saa7174HL";
        else
                p = "saa7171";
-       v4l_info(client, "%s found @ 0x%x (%s)\n", p,
+       v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
                        client->addr << 1, client->adapter->name);
-
-       decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
-       i2c_set_clientdata(client, decoder);
-
-       if (decoder == NULL)
-               return -ENOMEM;
        decoder->std = V4L2_STD_NTSC;
        decoder->input = -1;
        decoder->enable = 1;
@@ -1481,15 +1494,15 @@ static int saa717x_probe(struct i2c_client *client,
        decoder->audio_main_volume =
                (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
 
-       v4l_dbg(1, debug, client, "writing init values\n");
+       v4l2_dbg(1, debug, sd, "writing init values\n");
 
        /* FIXME!! */
-       saa717x_write_regs(client, reg_init_initialize);
-       set_video_output_level_regs(client, decoder);
+       saa717x_write_regs(sd, reg_init_initialize);
+       set_video_output_level_regs(sd, decoder);
        /* set bass,treble to 0db 20041101 K.Ohta */
        decoder->audio_main_bass = 0;
        decoder->audio_main_treble = 0;
-       set_audio_regs(client, decoder);
+       set_audio_regs(sd, decoder);
 
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(2*HZ);
@@ -1498,7 +1511,10 @@ static int saa717x_probe(struct i2c_client *client,
 
 static int saa717x_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index 044a2e94c34dc5e5708d6e3f0c4deb944a8ff263..d652f25eef0edc9b5aef4a23c0928246588116b6 100644 (file)
@@ -975,8 +975,7 @@ static int se401_close(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int se401_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
+static int se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = file->private_data;
        struct usb_se401 *se401 = (struct usb_se401 *)vdev;
@@ -1142,7 +1141,7 @@ static int se401_do_ioctl(struct inode *inode, struct file *file,
 static int se401_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);
+       return video_usercopy(file, cmd, arg, se401_do_ioctl);
 }
 
 static ssize_t se401_read(struct file *file, char __user *buf,
index 536b1a9b310ca602aa256493e742290c915f5674..9a2586b07a05c610728de368efe637baddd2778a 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/version.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
-#include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/clk.h>
 
@@ -75,8 +74,6 @@
 #define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */
 #define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */
 
-static DEFINE_MUTEX(camera_lock);
-
 /* per video frame buffer */
 struct sh_mobile_ceu_buffer {
        struct videobuf_buffer vb; /* v4l buffer must be first */
@@ -97,18 +94,20 @@ struct sh_mobile_ceu_dev {
        spinlock_t lock;
        struct list_head capture;
        struct videobuf_buffer *active;
+       int is_interlace;
 
        struct sh_mobile_ceu_info *pdata;
+
+       const struct soc_camera_data_format *camera_fmt;
 };
 
 static void ceu_write(struct sh_mobile_ceu_dev *priv,
-                     unsigned long reg_offs, unsigned long data)
+                     unsigned long reg_offs, u32 data)
 {
        iowrite32(data, priv->base + reg_offs);
 }
 
-static unsigned long ceu_read(struct sh_mobile_ceu_dev *priv,
-                             unsigned long reg_offs)
+static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs)
 {
        return ioread32(priv->base + reg_offs);
 }
@@ -156,21 +155,52 @@ static void free_buffer(struct videobuf_queue *vq,
        buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
+#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
+#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
+#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
+#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */
+
+
 static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
 {
-       ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~1);
-       ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & 0x0317f313);
-       ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | 1);
-
-       ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~0x10000);
+       struct soc_camera_device *icd = pcdev->icd;
+       dma_addr_t phys_addr_top, phys_addr_bottom;
 
-       ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);
+       /* The hardware is _very_ picky about this sequence. Especially
+        * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
+        * several not-so-well documented interrupt sources in CETCR.
+        */
+       ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_CPEIE);
+       ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & CEU_CETCR_MAGIC);
+       ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_CPEIE);
+       ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
+       ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
+
+       if (!pcdev->active)
+               return;
+
+       phys_addr_top = videobuf_to_dma_contig(pcdev->active);
+       ceu_write(pcdev, CDAYR, phys_addr_top);
+       if (pcdev->is_interlace) {
+               phys_addr_bottom = phys_addr_top + icd->width;
+               ceu_write(pcdev, CDBYR, phys_addr_bottom);
+       }
 
-       if (pcdev->active) {
-               pcdev->active->state = VIDEOBUF_ACTIVE;
-               ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));
-               ceu_write(pcdev, CAPSR, 0x1); /* start capture */
+       switch (icd->current_fmt->fourcc) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               phys_addr_top += icd->width * icd->height;
+               ceu_write(pcdev, CDACR, phys_addr_top);
+               if (pcdev->is_interlace) {
+                       phys_addr_bottom = phys_addr_top + icd->width;
+                       ceu_write(pcdev, CDBCR, phys_addr_bottom);
+               }
        }
+
+       pcdev->active->state = VIDEOBUF_ACTIVE;
+       ceu_write(pcdev, CAPSR, 0x1); /* start capture */
 }
 
 static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
@@ -292,14 +322,13 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/* Called with .video_lock held */
 static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
        int ret = -EBUSY;
 
-       mutex_lock(&camera_lock);
-
        if (pcdev->icd)
                goto err;
 
@@ -319,11 +348,10 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd)
 
        pcdev->icd = icd;
 err:
-       mutex_unlock(&camera_lock);
-
        return ret;
 }
 
+/* Called with .video_lock held */
 static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -362,8 +390,9 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
-       int ret, buswidth, width, cfszr_width, cdwdr_width;
+       int ret, buswidth, width, height, cfszr_width, cdwdr_width;
        unsigned long camera_flags, common_flags, value;
+       int yuv_mode, yuv_lineskip;
 
        camera_flags = icd->ops->query_bus_param(icd);
        common_flags = soc_camera_bus_param_compatible(camera_flags,
@@ -389,27 +418,71 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
        ceu_write(pcdev, CRCNTR, 0);
        ceu_write(pcdev, CRCMPR, 0);
 
-       value = 0x00000010;
-       value |= (common_flags & SOCAM_VSYNC_ACTIVE_LOW) ? (1 << 1) : 0;
-       value |= (common_flags & SOCAM_HSYNC_ACTIVE_LOW) ? (1 << 0) : 0;
-       value |= (buswidth == 16) ? (1 << 12) : 0;
+       value = 0x00000010; /* data fetch by default */
+       yuv_mode = yuv_lineskip = 0;
+
+       switch (icd->current_fmt->fourcc) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+               yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */
+               /* fall-through */
+       case V4L2_PIX_FMT_NV16:
+       case V4L2_PIX_FMT_NV61:
+               yuv_mode = 1;
+               switch (pcdev->camera_fmt->fourcc) {
+               case V4L2_PIX_FMT_UYVY:
+                       value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
+                       break;
+               case V4L2_PIX_FMT_VYUY:
+                       value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
+                       break;
+               case V4L2_PIX_FMT_YUYV:
+                       value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
+                       break;
+               case V4L2_PIX_FMT_YVYU:
+                       value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
+                       break;
+               default:
+                       BUG();
+               }
+       }
+
+       if (icd->current_fmt->fourcc == V4L2_PIX_FMT_NV21 ||
+           icd->current_fmt->fourcc == V4L2_PIX_FMT_NV61)
+               value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */
+
+       value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
+       value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
+       value |= buswidth == 16 ? 1 << 12 : 0;
        ceu_write(pcdev, CAMCR, value);
 
        ceu_write(pcdev, CAPCR, 0x00300000);
-       ceu_write(pcdev, CAIFR, 0);
+       ceu_write(pcdev, CAIFR, (pcdev->is_interlace) ? 0x101 : 0);
 
        mdelay(1);
 
-       width = icd->width * (icd->current_fmt->depth / 8);
-       width = (buswidth == 16) ? width / 2 : width;
-       cfszr_width = (buswidth == 8) ? width / 2 : width;
-       cdwdr_width = (buswidth == 16) ? width * 2 : width;
+       if (yuv_mode) {
+               width = icd->width * 2;
+               width = buswidth == 16 ? width / 2 : width;
+               cfszr_width = cdwdr_width = icd->width;
+       } else {
+               width = icd->width * ((icd->current_fmt->depth + 7) >> 3);
+               width = buswidth == 16 ? width / 2 : width;
+               cfszr_width = buswidth == 8 ? width / 2 : width;
+               cdwdr_width = buswidth == 16 ? width * 2 : width;
+       }
+
+       height = icd->height;
+       if (pcdev->is_interlace) {
+               height /= 2;
+               cdwdr_width *= 2;
+       }
 
        ceu_write(pcdev, CAMOR, 0);
-       ceu_write(pcdev, CAPWR, (icd->height << 16) | width);
-       ceu_write(pcdev, CFLCR, 0); /* data fetch mode - no scaling */
-       ceu_write(pcdev, CFSZR, (icd->height << 16) | cfszr_width);
-       ceu_write(pcdev, CLFCR, 0); /* data fetch mode - no lowpass filter */
+       ceu_write(pcdev, CAPWR, (height << 16) | width);
+       ceu_write(pcdev, CFLCR, 0); /* no scaling */
+       ceu_write(pcdev, CFSZR, (height << 16) | cfszr_width);
+       ceu_write(pcdev, CLFCR, 0); /* no lowpass filter */
 
        /* A few words about byte order (observed in Big Endian mode)
         *
@@ -423,19 +496,20 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
         * using 7 we swap the data bytes to match the incoming order:
         * D0, D1, D2, D3, D4, D5, D6, D7
         */
-       ceu_write(pcdev, CDOCR, 0x00000017);
+       value = 0x00000017;
+       if (yuv_lineskip)
+               value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */
+
+       ceu_write(pcdev, CDOCR, value);
 
        ceu_write(pcdev, CDWDR, cdwdr_width);
        ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */
 
        /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */
-       /* in data fetch mode: no need for CDACR, CDBYR, CDBCR */
-
        return 0;
 }
 
-static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
-                                      __u32 pixfmt)
+static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -450,15 +524,123 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
        return 0;
 }
 
-static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
-                                    __u32 pixfmt, struct v4l2_rect *rect)
+static const struct soc_camera_data_format sh_mobile_ceu_formats[] = {
+       {
+               .name           = "NV12",
+               .depth          = 12,
+               .fourcc         = V4L2_PIX_FMT_NV12,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               .name           = "NV21",
+               .depth          = 12,
+               .fourcc         = V4L2_PIX_FMT_NV21,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               .name           = "NV16",
+               .depth          = 16,
+               .fourcc         = V4L2_PIX_FMT_NV16,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+       {
+               .name           = "NV61",
+               .depth          = 16,
+               .fourcc         = V4L2_PIX_FMT_NV61,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+       },
+};
+
+static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+                                    struct soc_camera_format_xlate *xlate)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       int ret, k, n;
+       int formats = 0;
+
+       ret = sh_mobile_ceu_try_bus_param(icd);
+       if (ret < 0)
+               return 0;
+
+       switch (icd->formats[idx].fourcc) {
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_VYUY:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_YVYU:
+               n = ARRAY_SIZE(sh_mobile_ceu_formats);
+               formats += n;
+               for (k = 0; xlate && k < n; k++) {
+                       xlate->host_fmt = &sh_mobile_ceu_formats[k];
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = icd->formats[idx].depth;
+                       xlate++;
+                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                               sh_mobile_ceu_formats[k].name,
+                               icd->formats[idx].name);
+               }
+       default:
+               /* Generic pass-through */
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = icd->formats + idx;
+                       xlate->cam_fmt = icd->formats + idx;
+                       xlate->buswidth = icd->formats[idx].depth;
+                       xlate++;
+                       dev_dbg(&ici->dev,
+                               "Providing format %s in pass-through mode\n",
+                               icd->formats[idx].name);
+               }
+       }
+
+       return formats;
+}
+
+static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
+                                __u32 pixfmt, struct v4l2_rect *rect)
 {
-       return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       const struct soc_camera_format_xlate *xlate;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
+       switch (pixfmt) {
+       case 0:                         /* Only geometry change */
+               ret = icd->ops->set_fmt(icd, pixfmt, rect);
+               break;
+       default:
+               ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
+       }
+
+       if (pixfmt && !ret) {
+               icd->buswidth = xlate->buswidth;
+               icd->current_fmt = xlate->host_fmt;
+               pcdev->camera_fmt = xlate->cam_fmt;
+       }
+
+       return ret;
 }
 
-static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
-                                    struct v4l2_format *f)
+static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
+                                struct v4l2_format *f)
 {
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct sh_mobile_ceu_dev *pcdev = ici->priv;
+       const struct soc_camera_format_xlate *xlate;
+       __u32 pixfmt = f->fmt.pix.pixelformat;
+       int ret;
+
+       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+       if (!xlate) {
+               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               return -EINVAL;
+       }
+
        /* FIXME: calculate using depth and bus width */
 
        if (f->fmt.pix.height < 4)
@@ -472,8 +654,31 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
        f->fmt.pix.width &= ~0x01;
        f->fmt.pix.height &= ~0x03;
 
+       f->fmt.pix.bytesperline = f->fmt.pix.width *
+               DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
        /* limit to sensor capabilities */
-       return icd->ops->try_fmt_cap(icd, f);
+       ret = icd->ops->try_fmt(icd, f);
+       if (ret < 0)
+               return ret;
+
+       switch (f->fmt.pix.field) {
+       case V4L2_FIELD_INTERLACED:
+               pcdev->is_interlace = 1;
+               break;
+       case V4L2_FIELD_ANY:
+               f->fmt.pix.field = V4L2_FIELD_NONE;
+               /* fall-through */
+       case V4L2_FIELD_NONE:
+               pcdev->is_interlace = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
 }
 
 static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
@@ -532,7 +737,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
                                       &sh_mobile_ceu_videobuf_ops,
                                       &ici->dev, &pcdev->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                                      V4L2_FIELD_NONE,
+                                      V4L2_FIELD_ANY,
                                       sizeof(struct sh_mobile_ceu_buffer),
                                       icd);
 }
@@ -541,12 +746,12 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
        .owner          = THIS_MODULE,
        .add            = sh_mobile_ceu_add_device,
        .remove         = sh_mobile_ceu_remove_device,
-       .set_fmt_cap    = sh_mobile_ceu_set_fmt_cap,
-       .try_fmt_cap    = sh_mobile_ceu_try_fmt_cap,
+       .get_formats    = sh_mobile_ceu_get_formats,
+       .set_fmt        = sh_mobile_ceu_set_fmt,
+       .try_fmt        = sh_mobile_ceu_try_fmt,
        .reqbufs        = sh_mobile_ceu_reqbufs,
        .poll           = sh_mobile_ceu_poll,
        .querycap       = sh_mobile_ceu_querycap,
-       .try_bus_param  = sh_mobile_ceu_try_bus_param,
        .set_bus_param  = sh_mobile_ceu_set_bus_param,
        .init_videobuf  = sh_mobile_ceu_init_videobuf,
 };
@@ -616,7 +821,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
 
        /* request irq */
        err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED,
-                         pdev->dev.bus_id, pcdev);
+                         dev_name(&pdev->dev), pcdev);
        if (err) {
                dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");
                goto exit_release_mem;
@@ -633,8 +838,8 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        pcdev->ici.priv = pcdev;
        pcdev->ici.dev.parent = &pdev->dev;
        pcdev->ici.nr = pdev->id;
-       pcdev->ici.drv_name = pdev->dev.bus_id,
-       pcdev->ici.ops = &sh_mobile_ceu_host_ops,
+       pcdev->ici.drv_name = dev_name(&pdev->dev);
+       pcdev->ici.ops = &sh_mobile_ceu_host_ops;
 
        err = soc_camera_host_register(&pcdev->ici);
        if (err)
index fcd2b62f92c43506456437fa3b46f7469fc4d25c..01a8efb8deb156f274ad54e514be0082783df6f2 100644 (file)
@@ -2162,7 +2162,7 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
 
        strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
        if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+               strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
                        sizeof(cap.bus_info));
 
        if (copy_to_user(arg, &cap, sizeof(cap)))
index e23734f6d6e2255535875b297204585ebb8d0478..8cb3457e778d0d30d408f454071e2bbc2ea4dea0 100644 (file)
@@ -55,7 +55,9 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
+#endif
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
        { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
@@ -91,10 +93,14 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
        /* SN9C105 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
+#endif
        { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
+#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), },
        { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
@@ -113,7 +119,9 @@ static const struct usb_device_id sn9c102_id_table[] = {
        { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
 /*     { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
        { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
+#endif
        { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
        { SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
index 66ebe5956a878ef45cb0a591d88cb2496bea3bc2..90077cb4fe667fed105771fbb379ac3024dac480 100644 (file)
 static LIST_HEAD(hosts);
 static LIST_HEAD(devices);
 static DEFINE_MUTEX(list_lock);
-static DEFINE_MUTEX(video_lock);
 
-const static struct soc_camera_data_format*
-format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
+const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+       struct soc_camera_device *icd, unsigned int fourcc)
 {
        unsigned int i;
 
@@ -45,67 +44,87 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
                        return icd->formats + i;
        return NULL;
 }
+EXPORT_SYMBOL(soc_camera_format_by_fourcc);
 
-static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
-                                 struct v4l2_format *f)
+const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+       struct soc_camera_device *icd, unsigned int fourcc)
 {
-       struct soc_camera_file *icf = file->private_data;
-       struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
-       enum v4l2_field field;
-       const struct soc_camera_data_format *fmt;
-       int ret;
+       unsigned int i;
 
-       WARN_ON(priv != file->private_data);
+       for (i = 0; i < icd->num_user_formats; i++)
+               if (icd->user_formats[i].host_fmt->fourcc == fourcc)
+                       return icd->user_formats + i;
+       return NULL;
+}
+EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
 
-       fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
-       if (!fmt) {
-               dev_dbg(&icd->dev, "invalid format 0x%08x\n",
-                       f->fmt.pix.pixelformat);
-               return -EINVAL;
-       }
+/**
+ * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
+ * @icl:       camera platform parameters
+ * @flags:     flags to be inverted according to platform configuration
+ * @return:    resulting flags
+ */
+unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
+                                           unsigned long flags)
+{
+       unsigned long f;
 
-       dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
+       /* If only one of the two polarities is supported, switch to the opposite */
+       if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
+               f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
+               if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW)
+                       flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW;
+       }
 
-       field = f->fmt.pix.field;
+       if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
+               f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
+               if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW)
+                       flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW;
+       }
 
-       if (field == V4L2_FIELD_ANY) {
-               field = V4L2_FIELD_NONE;
-       } else if (V4L2_FIELD_NONE != field) {
-               dev_err(&icd->dev, "Field type invalid.\n");
-               return -EINVAL;
+       if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
+               f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
+               if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING)
+                       flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING;
        }
 
-       /* test physical bus parameters */
-       ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);
-       if (ret)
-               return ret;
+       return flags;
+}
+EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
 
-       /* limit format to hardware capabilities */
-       ret = ici->ops->try_fmt_cap(icd, f);
+static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
+                                     struct v4l2_format *f)
+{
+       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = icf->icd;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
-       /* calculate missing fields */
-       f->fmt.pix.field = field;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * fmt->depth) >> 3;
-       f->fmt.pix.sizeimage =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       WARN_ON(priv != file->private_data);
 
-       return ret;
+       /* limit format to hardware capabilities */
+       return ici->ops->try_fmt(icd, f);
 }
 
 static int soc_camera_enum_input(struct file *file, void *priv,
                                 struct v4l2_input *inp)
 {
+       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = icf->icd;
+       int ret = 0;
+
        if (inp->index != 0)
                return -EINVAL;
 
-       inp->type = V4L2_INPUT_TYPE_CAMERA;
-       inp->std = V4L2_STD_UNKNOWN;
-       strcpy(inp->name, "Camera");
+       if (icd->ops->enum_input)
+               ret = icd->ops->enum_input(icd, inp);
+       else {
+               /* default is camera */
+               inp->type = V4L2_INPUT_TYPE_CAMERA;
+               inp->std  = V4L2_STD_UNKNOWN;
+               strcpy(inp->name, "Camera");
+       }
 
-       return 0;
+       return ret;
 }
 
 static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
@@ -125,7 +144,14 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
 
 static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
 {
-       return 0;
+       struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = icf->icd;
+       int ret = 0;
+
+       if (icd->ops->set_std)
+               ret = icd->ops->set_std(icd, a);
+
+       return ret;
 }
 
 static int soc_camera_reqbufs(struct file *file, void *priv,
@@ -134,8 +160,7 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
        int ret;
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -178,6 +203,59 @@ static int soc_camera_dqbuf(struct file *file, void *priv,
        return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
 }
 
+static int soc_camera_init_user_formats(struct soc_camera_device *icd)
+{
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       int i, fmts = 0;
+
+       if (!ici->ops->get_formats)
+               /*
+                * Fallback mode - the host will have to serve all
+                * sensor-provided formats one-to-one to the user
+                */
+               fmts = icd->num_formats;
+       else
+               /*
+                * First pass - only count formats this host-sensor
+                * configuration can provide
+                */
+               for (i = 0; i < icd->num_formats; i++)
+                       fmts += ici->ops->get_formats(icd, i, NULL);
+
+       if (!fmts)
+               return -ENXIO;
+
+       icd->user_formats =
+               vmalloc(fmts * sizeof(struct soc_camera_format_xlate));
+       if (!icd->user_formats)
+               return -ENOMEM;
+
+       icd->num_user_formats = fmts;
+       fmts = 0;
+
+       dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
+
+       /* Second pass - actually fill data formats */
+       for (i = 0; i < icd->num_formats; i++)
+               if (!ici->ops->get_formats) {
+                       icd->user_formats[i].host_fmt = icd->formats + i;
+                       icd->user_formats[i].cam_fmt = icd->formats + i;
+                       icd->user_formats[i].buswidth = icd->formats[i].depth;
+               } else {
+                       fmts += ici->ops->get_formats(icd, i,
+                                                     &icd->user_formats[fmts]);
+               }
+
+       icd->current_fmt = icd->user_formats[0].host_fmt;
+
+       return 0;
+}
+
+static void soc_camera_free_user_formats(struct soc_camera_device *icd)
+{
+       vfree(icd->user_formats);
+}
+
 static int soc_camera_open(struct inode *inode, struct file *file)
 {
        struct video_device *vdev;
@@ -190,8 +268,10 @@ static int soc_camera_open(struct inode *inode, struct file *file)
        if (!icf)
                return -ENOMEM;
 
-       /* Protect against icd->remove() until we module_get() both drivers. */
-       mutex_lock(&video_lock);
+       /*
+        * It is safe to dereference these pointers now as long as a user has
+        * the video device open - we are protected by the held cdev reference.
+        */
 
        vdev = video_devdata(file);
        icd = container_of(vdev->parent, struct soc_camera_device, dev);
@@ -209,20 +289,25 @@ static int soc_camera_open(struct inode *inode, struct file *file)
                goto emgi;
        }
 
+       /* Protect against icd->remove() until we module_get() both drivers. */
+       mutex_lock(&icd->video_lock);
+
        icf->icd = icd;
        icd->use_count++;
 
        /* Now we really have to activate the camera */
        if (icd->use_count == 1) {
+               ret = soc_camera_init_user_formats(icd);
+               if (ret < 0)
+                       goto eiufmt;
                ret = ici->ops->add(icd);
                if (ret < 0) {
                        dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
-                       icd->use_count--;
                        goto eiciadd;
                }
        }
 
-       mutex_unlock(&video_lock);
+       mutex_unlock(&icd->video_lock);
 
        file->private_data = icf;
        dev_dbg(&icd->dev, "camera device open\n");
@@ -231,13 +316,16 @@ static int soc_camera_open(struct inode *inode, struct file *file)
 
        return 0;
 
-       /* All errors are entered with the video_lock held */
+       /* First two errors are entered with the .video_lock held */
 eiciadd:
+       soc_camera_free_user_formats(icd);
+eiufmt:
+       icd->use_count--;
+       mutex_unlock(&icd->video_lock);
        module_put(ici->ops->owner);
 emgi:
        module_put(icd->ops->owner);
 emgd:
-       mutex_unlock(&video_lock);
        vfree(icf);
        return ret;
 }
@@ -249,13 +337,16 @@ static int soc_camera_close(struct inode *inode, struct file *file)
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct video_device *vdev = icd->vdev;
 
-       mutex_lock(&video_lock);
+       mutex_lock(&icd->video_lock);
        icd->use_count--;
-       if (!icd->use_count)
+       if (!icd->use_count) {
                ici->ops->remove(icd);
+               soc_camera_free_user_formats(icd);
+       }
+       mutex_unlock(&icd->video_lock);
+
        module_put(icd->ops->owner);
        module_put(ici->ops->owner);
-       mutex_unlock(&video_lock);
 
        vfree(icf);
 
@@ -265,7 +356,7 @@ static int soc_camera_close(struct inode *inode, struct file *file)
 }
 
 static ssize_t soc_camera_read(struct file *file, char __user *buf,
-                          size_t count, loff_t *ppos)
+                              size_t count, loff_t *ppos)
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
@@ -299,8 +390,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        if (list_empty(&icf->vb_vidq.stream)) {
                dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
@@ -310,7 +400,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
        return ici->ops->poll(file, pt);
 }
 
-
 static struct file_operations soc_camera_fops = {
        .owner          = THIS_MODULE,
        .open           = soc_camera_open,
@@ -322,44 +411,50 @@ static struct file_operations soc_camera_fops = {
        .llseek         = no_llseek,
 };
 
-
 static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
+                                   struct v4l2_format *f)
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       __u32 pixfmt = pix->pixelformat;
        int ret;
        struct v4l2_rect rect;
-       const static struct soc_camera_data_format *data_fmt;
 
        WARN_ON(priv != file->private_data);
 
-       data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
-       if (!data_fmt)
-               return -EINVAL;
-
-       /* buswidth may be further adjusted by the ici */
-       icd->buswidth = data_fmt->depth;
-
-       ret = soc_camera_try_fmt_vid_cap(file, icf, f);
+       ret = soc_camera_try_fmt_vid_cap(file, priv, f);
        if (ret < 0)
                return ret;
 
+       mutex_lock(&icf->vb_vidq.vb_lock);
+
+       if (videobuf_queue_is_busy(&icf->vb_vidq)) {
+               dev_err(&icd->dev, "S_FMT denied: queue busy\n");
+               ret = -EBUSY;
+               goto unlock;
+       }
+
        rect.left       = icd->x_current;
        rect.top        = icd->y_current;
-       rect.width      = f->fmt.pix.width;
-       rect.height     = f->fmt.pix.height;
-       ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
-       if (ret < 0)
-               return ret;
+       rect.width      = pix->width;
+       rect.height     = pix->height;
+       ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect);
+       if (ret < 0) {
+               goto unlock;
+       } else if (!icd->current_fmt ||
+                  icd->current_fmt->fourcc != pixfmt) {
+               dev_err(&ici->dev,
+                       "Host driver hasn't set up current format correctly!\n");
+               ret = -EINVAL;
+               goto unlock;
+       }
 
-       icd->current_fmt        = data_fmt;
        icd->width              = rect.width;
        icd->height             = rect.height;
-       icf->vb_vidq.field      = f->fmt.pix.field;
-       if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+       icf->vb_vidq.field      = pix->field;
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
                         f->type);
 
@@ -367,11 +462,16 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
                icd->width, icd->height);
 
        /* set physical bus parameters */
-       return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
+       ret = ici->ops->set_bus_param(icd, pixfmt);
+
+unlock:
+       mutex_unlock(&icf->vb_vidq.vb_lock);
+
+       return ret;
 }
 
 static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                  struct v4l2_fmtdesc *f)
+                                      struct v4l2_fmtdesc *f)
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
@@ -379,10 +479,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
 
        WARN_ON(priv != file->private_data);
 
-       if (f->index >= icd->num_formats)
+       if (f->index >= icd->num_user_formats)
                return -EINVAL;
 
-       format = &icd->formats[f->index];
+       format = icd->user_formats[f->index].host_fmt;
 
        strlcpy(f->description, format->name, sizeof(f->description));
        f->pixelformat = format->fourcc;
@@ -390,21 +490,21 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
 }
 
 static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
-                               struct v4l2_format *f)
+                                   struct v4l2_format *f)
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
 
        WARN_ON(priv != file->private_data);
 
-       f->fmt.pix.width        = icd->width;
-       f->fmt.pix.height       = icd->height;
-       f->fmt.pix.field        = icf->vb_vidq.field;
-       f->fmt.pix.pixelformat  = icd->current_fmt->fourcc;
-       f->fmt.pix.bytesperline =
-               (f->fmt.pix.width * icd->current_fmt->depth) >> 3;
-       f->fmt.pix.sizeimage    =
-               f->fmt.pix.height * f->fmt.pix.bytesperline;
+       pix->width              = icd->width;
+       pix->height             = icd->height;
+       pix->field              = icf->vb_vidq.field;
+       pix->pixelformat        = icd->current_fmt->fourcc;
+       pix->bytesperline       = pix->width *
+               DIV_ROUND_UP(icd->current_fmt->depth, 8);
+       pix->sizeimage          = pix->height * pix->bytesperline;
        dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
                icd->current_fmt->fourcc);
        return 0;
@@ -415,8 +515,7 @@ static int soc_camera_querycap(struct file *file, void  *priv,
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
 
        WARN_ON(priv != file->private_data);
 
@@ -429,6 +528,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
+       int ret;
 
        WARN_ON(priv != file->private_data);
 
@@ -437,10 +537,16 @@ static int soc_camera_streamon(struct file *file, void *priv,
        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
+       mutex_lock(&icd->video_lock);
+
        icd->ops->start_capture(icd);
 
        /* This calls buf_queue from host driver's videobuf_queue_ops */
-       return videobuf_streamon(&icf->vb_vidq);
+       ret = videobuf_streamon(&icf->vb_vidq);
+
+       mutex_unlock(&icd->video_lock);
+
+       return ret;
 }
 
 static int soc_camera_streamoff(struct file *file, void *priv,
@@ -456,12 +562,16 @@ static int soc_camera_streamoff(struct file *file, void *priv,
        if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
+       mutex_lock(&icd->video_lock);
+
        /* This calls buf_release from host driver's videobuf_queue_ops for all
         * remaining buffers. When the last buffer is freed, stop capture */
        videobuf_streamoff(&icf->vb_vidq);
 
        icd->ops->stop_capture(icd);
 
+       mutex_unlock(&icd->video_lock);
+
        return 0;
 }
 
@@ -567,14 +677,16 @@ static int soc_camera_s_crop(struct file *file, void *fh,
 {
        struct soc_camera_file *icf = file->private_data;
        struct soc_camera_device *icd = icf->icd;
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        int ret;
 
        if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
                return -EINVAL;
 
-       ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
+       /* Cropping is allowed during a running capture, guard consistency */
+       mutex_lock(&icf->vb_vidq.vb_lock);
+
+       ret = ici->ops->set_fmt(icd, 0, &a->c);
        if (!ret) {
                icd->width      = a->c.width;
                icd->height     = a->c.height;
@@ -582,6 +694,8 @@ static int soc_camera_s_crop(struct file *file, void *fh,
                icd->y_current  = a->c.top;
        }
 
+       mutex_unlock(&icf->vb_vidq.vb_lock);
+
        return ret;
 }
 
@@ -692,18 +806,35 @@ static int scan_add_device(struct soc_camera_device *icd)
 static int soc_camera_probe(struct device *dev)
 {
        struct soc_camera_device *icd = to_soc_camera_dev(dev);
-       struct soc_camera_host *ici =
-               to_soc_camera_host(icd->dev.parent);
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        int ret;
 
-       if (!icd->ops->probe)
-               return -ENODEV;
+       /*
+        * Possible race scenario:
+        * modprobe <camera-host-driver> triggers __func__
+        * at this moment respective <camera-sensor-driver> gets rmmod'ed
+        * to protect take module references.
+        */
+
+       if (!try_module_get(icd->ops->owner)) {
+               dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
+               ret = -EINVAL;
+               goto emgd;
+       }
+
+       if (!try_module_get(ici->ops->owner)) {
+               dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+               ret = -EINVAL;
+               goto emgi;
+       }
+
+       mutex_lock(&icd->video_lock);
 
        /* We only call ->add() here to activate and probe the camera.
         * We shall ->remove() and deactivate it immediately afterwards. */
        ret = ici->ops->add(icd);
        if (ret < 0)
-               return ret;
+               goto eiadd;
 
        ret = icd->ops->probe(icd);
        if (ret >= 0) {
@@ -717,6 +848,12 @@ static int soc_camera_probe(struct device *dev)
        }
        ici->ops->remove(icd);
 
+eiadd:
+       mutex_unlock(&icd->video_lock);
+       module_put(ici->ops->owner);
+emgi:
+       module_put(icd->ops->owner);
+emgd:
        return ret;
 }
 
@@ -779,11 +916,20 @@ int soc_camera_host_register(struct soc_camera_host *ici)
        int ret;
        struct soc_camera_host *ix;
 
-       if (!ici->ops->init_videobuf || !ici->ops->add || !ici->ops->remove)
+       if (!ici || !ici->ops ||
+           !ici->ops->try_fmt ||
+           !ici->ops->set_fmt ||
+           !ici->ops->set_bus_param ||
+           !ici->ops->querycap ||
+           !ici->ops->init_videobuf ||
+           !ici->ops->reqbufs ||
+           !ici->ops->add ||
+           !ici->ops->remove ||
+           !ici->ops->poll)
                return -EINVAL;
 
        /* Number might be equal to the platform device ID */
-       sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
+       dev_set_name(&ici->dev, "camera_host%d", ici->nr);
 
        mutex_lock(&list_lock);
        list_for_each_entry(ix, &hosts, list) {
@@ -847,7 +993,16 @@ int soc_camera_device_register(struct soc_camera_device *icd)
        struct soc_camera_device *ix;
        int num = -1, i;
 
-       if (!icd)
+       if (!icd || !icd->ops ||
+           !icd->ops->probe ||
+           !icd->ops->init ||
+           !icd->ops->release ||
+           !icd->ops->start_capture ||
+           !icd->ops->stop_capture ||
+           !icd->ops->set_fmt ||
+           !icd->ops->try_fmt ||
+           !icd->ops->query_bus_param ||
+           !icd->ops->set_bus_param)
                return -EINVAL;
 
        for (i = 0; i < 256 && num < 0; i++) {
@@ -867,10 +1022,12 @@ int soc_camera_device_register(struct soc_camera_device *icd)
 
        icd->devnum = num;
        icd->dev.bus = &soc_camera_bus_type;
-       snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id),
-                "%u-%u", icd->iface, icd->devnum);
+       dev_set_name(&icd->dev, "%u-%u", icd->iface, icd->devnum);
 
-       icd->dev.release = dummy_release;
+       icd->dev.release        = dummy_release;
+       icd->use_count          = 0;
+       icd->host_priv          = NULL;
+       mutex_init(&icd->video_lock);
 
        return scan_add_device(icd);
 }
@@ -917,6 +1074,10 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
 #endif
 };
 
+/*
+ * Usually called from the struct soc_camera_ops .probe() method, i.e., from
+ * soc_camera_probe() above with .video_lock held
+ */
 int soc_camera_video_start(struct soc_camera_device *icd)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
@@ -932,7 +1093,7 @@ int soc_camera_video_start(struct soc_camera_device *icd)
        dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
 
        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
-       /* Maybe better &ici->dev */
+
        vdev->parent            = &icd->dev;
        vdev->current_norm      = V4L2_STD_UNKNOWN;
        vdev->fops              = &soc_camera_fops;
@@ -941,8 +1102,6 @@ int soc_camera_video_start(struct soc_camera_device *icd)
        vdev->minor             = -1;
        vdev->tvnorms           = V4L2_STD_UNKNOWN,
 
-       icd->current_fmt = &icd->formats[0];
-
        err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
        if (err < 0) {
                dev_err(vdev->parent, "video_register_device failed\n");
@@ -968,10 +1127,10 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
        if (!icd->dev.parent || !vdev)
                return;
 
-       mutex_lock(&video_lock);
+       mutex_lock(&icd->video_lock);
        video_unregister_device(vdev);
        icd->vdev = NULL;
-       mutex_unlock(&video_lock);
+       mutex_unlock(&icd->video_lock);
 }
 EXPORT_SYMBOL(soc_camera_video_stop);
 
index bb7a9d480e8f3ff94058f7521da413463da661d9..013ab06e318042c39369bcf380fa709234b6b227 100644 (file)
@@ -79,19 +79,20 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
        return p->bus_param;
 }
 
-static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd,
-                                          __u32 pixfmt, struct v4l2_rect *rect)
+static int soc_camera_platform_set_fmt(struct soc_camera_device *icd,
+                                      __u32 pixfmt, struct v4l2_rect *rect)
 {
        return 0;
 }
 
-static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd,
-                                          struct v4l2_format *f)
+static int soc_camera_platform_try_fmt(struct soc_camera_device *icd,
+                                      struct v4l2_format *f)
 {
        struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
 
-       f->fmt.pix.width = p->format.width;
-       f->fmt.pix.height = p->format.height;
+       pix->width = p->format.width;
+       pix->height = p->format.height;
        return 0;
 }
 
@@ -124,8 +125,8 @@ static struct soc_camera_ops soc_camera_platform_ops = {
        .release                = soc_camera_platform_release,
        .start_capture          = soc_camera_platform_start_capture,
        .stop_capture           = soc_camera_platform_stop_capture,
-       .set_fmt_cap            = soc_camera_platform_set_fmt_cap,
-       .try_fmt_cap            = soc_camera_platform_try_fmt_cap,
+       .set_fmt                = soc_camera_platform_set_fmt,
+       .try_fmt                = soc_camera_platform_try_fmt,
        .set_bus_param          = soc_camera_platform_set_bus_param,
        .query_bus_param        = soc_camera_platform_query_bus_param,
 };
index e9eb6d754d5c85db037e9d41fa398a1e2589830a..f9516d0f3c1121ee2122cb01ef51b9e6465434f3 100644 (file)
@@ -1262,6 +1262,25 @@ static int stk_vidioc_g_parm(struct file *filp,
        return 0;
 }
 
+static int stk_vidioc_enum_framesizes(struct file *filp,
+               void *priv, struct v4l2_frmsizeenum *frms)
+{
+       if (frms->index >= ARRAY_SIZE(stk_sizes))
+               return -EINVAL;
+       switch (frms->pixel_format) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_UYVY:
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_SBGGR8:
+               frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               frms->discrete.width = stk_sizes[frms->index].w;
+               frms->discrete.height = stk_sizes[frms->index].h;
+               return 0;
+       default: return -EINVAL;
+       }
+}
+
 static struct file_operations v4l_stk_fops = {
        .owner = THIS_MODULE,
        .open = v4l_stk_open,
@@ -1296,6 +1315,7 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
        .vidioc_g_ctrl = stk_vidioc_g_ctrl,
        .vidioc_s_ctrl = stk_vidioc_s_ctrl,
        .vidioc_g_parm = stk_vidioc_g_parm,
+       .vidioc_enum_framesizes = stk_vidioc_enum_framesizes,
 };
 
 static void stk_v4l_dev_release(struct video_device *vd)
@@ -1376,12 +1396,9 @@ static int stk_camera_probe(struct usb_interface *interface,
                endpoint = &iface_desc->endpoint[i].desc;
 
                if (!dev->isoc_ep
-                       && ((endpoint->bEndpointAddress
-                               & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-                       && ((endpoint->bmAttributes
-                               & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) {
+                       && usb_endpoint_is_isoc_in(endpoint)) {
                        /* we found an isoc in endpoint */
-                       dev->isoc_ep = (endpoint->bEndpointAddress & 0xF);
+                       dev->isoc_ep = usb_endpoint_num(endpoint);
                        break;
                }
        }
index 328c41b1517d1a0d0897a17baad51c0fe08c3a40..42acc92c182da708c3cdf0ed315996a11a74ea16 100644 (file)
@@ -1132,8 +1132,7 @@ static int stv_close (struct inode *inode, struct file *file)
        return 0;
 }
 
-static int stv680_do_ioctl (struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg)
+static int stv680_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = file->private_data;
        struct usb_stv *stv680 = video_get_drvdata(vdev);
@@ -1303,7 +1302,7 @@ static int stv680_do_ioctl (struct inode *inode, struct file *file,
 static int stv680_ioctl(struct inode *inode, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl);
+       return video_usercopy(file, cmd, arg, stv680_do_ioctl);
 }
 
 static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
index 4963d4264880f6fd8a3d2bc34224c8ad1e6aadb1..0c020585fffbc02f4cb49865868cb690f4122555 100644 (file)
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
 
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/i2c-addr.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
 # define VIDEO_AUDIO_BALANCE 32
@@ -79,6 +80,7 @@ I2C_CLIENT_INSMOD;
 /* Structure of address and subaddresses for the tda7432 */
 
 struct tda7432 {
+       struct v4l2_subdev sd;
        int addr;
        int input;
        int volume;
@@ -86,10 +88,12 @@ struct tda7432 {
        int bass, treble;
        int lf, lr, rf, rr;
        int loud;
-       struct i2c_client c;
 };
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+
+static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct tda7432, sd);
+}
 
 /* The TDA7432 is made by STS-Thompson
  * http://www.st.com
@@ -224,32 +228,33 @@ static struct i2c_client client_template;
 
 /* Begin code */
 
-static int tda7432_write(struct i2c_client *client, int subaddr, int val)
+static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        unsigned char buffer[2];
-       v4l_dbg(2, debug,client,"In tda7432_write\n");
-       v4l_dbg(1, debug,client,"Writing %d 0x%x\n", subaddr, val);
+
+       v4l2_dbg(2, debug, sd, "In tda7432_write\n");
+       v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
        buffer[0] = subaddr;
        buffer[1] = val;
-       if (2 != i2c_master_send(client,buffer,2)) {
-               v4l_err(client,"I/O error, trying (write %d 0x%x)\n",
+       if (2 != i2c_master_send(client, buffer, 2)) {
+               v4l2_err(sd, "I/O error, trying (write %d 0x%x)\n",
                       subaddr, val);
                return -1;
        }
        return 0;
 }
 
-/* I don't think we ever actually _read_ the chip... */
-
-static int tda7432_set(struct i2c_client *client)
+static int tda7432_set(struct v4l2_subdev *sd)
 {
-       struct tda7432 *t = i2c_get_clientdata(client);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tda7432 *t = to_state(sd);
        unsigned char buf[16];
-       v4l_dbg(2, debug,client,"In tda7432_set\n");
 
-       v4l_dbg(1, debug,client,
+       v4l2_dbg(1, debug, sd,
                "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
-               t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
+               t->input, t->volume, t->bass, t->treble, t->lf, t->lr,
+               t->rf, t->rr, t->loud);
        buf[0]  = TDA7432_IN;
        buf[1]  = t->input;
        buf[2]  = t->volume;
@@ -260,18 +265,19 @@ static int tda7432_set(struct i2c_client *client)
        buf[7]  = t->rf;
        buf[8]  = t->rr;
        buf[9]  = t->loud;
-       if (10 != i2c_master_send(client,buf,10)) {
-               v4l_err(client,"I/O error, trying tda7432_set\n");
+       if (10 != i2c_master_send(client, buf, 10)) {
+               v4l2_err(sd, "I/O error, trying tda7432_set\n");
                return -1;
        }
 
        return 0;
 }
 
-static void do_tda7432_init(struct i2c_client *client)
+static void do_tda7432_init(struct v4l2_subdev *sd)
 {
-       struct tda7432 *t = i2c_get_clientdata(client);
-       v4l_dbg(2, debug,client,"In tda7432_init\n");
+       struct tda7432 *t = to_state(sd);
+
+       v4l2_dbg(2, debug, sd, "In tda7432_init\n");
 
        t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
                    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
@@ -288,57 +294,12 @@ static void do_tda7432_init(struct i2c_client *client)
        t->rr     = TDA7432_ATTEN_0DB;   /* 0dB attenuation       */
        t->loud   = loudness;            /* insmod parameter      */
 
-       tda7432_set(client);
+       tda7432_set(sd);
 }
 
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda7432_attach(struct i2c_adapter *adap, int addr, int kind)
+static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct tda7432 *t;
-       struct i2c_client *client;
-
-       t = kzalloc(sizeof *t,GFP_KERNEL);
-       if (!t)
-               return -ENOMEM;
-
-       client = &t->c;
-       memcpy(client,&client_template,sizeof(struct i2c_client));
-       client->adapter = adap;
-       client->addr = addr;
-       i2c_set_clientdata(client, t);
-
-       do_tda7432_init(client);
-       i2c_attach_client(client);
-
-       v4l_info(client, "chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-       return 0;
-}
-
-static int tda7432_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, tda7432_attach);
-       return 0;
-}
-
-static int tda7432_detach(struct i2c_client *client)
-{
-       struct tda7432 *t  = i2c_get_clientdata(client);
-
-       do_tda7432_init(client);
-       i2c_detach_client(client);
-
-       kfree(t);
-       return 0;
-}
-
-static int tda7432_get_ctrl(struct i2c_client *client,
-                           struct v4l2_control *ctrl)
-{
-       struct tda7432 *t = i2c_get_clientdata(client);
+       struct tda7432 *t = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -382,10 +343,9 @@ static int tda7432_get_ctrl(struct i2c_client *client,
        return -EINVAL;
 }
 
-static int tda7432_set_ctrl(struct i2c_client *client,
-                           struct v4l2_control *ctrl)
+static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct tda7432 *t = i2c_get_clientdata(client);
+       struct tda7432 *t = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -400,7 +360,7 @@ static int tda7432_set_ctrl(struct i2c_client *client,
                if (loudness)           /* Turn on the loudness bit */
                        t->volume |= TDA7432_LD_ON;
 
-               tda7432_write(client,TDA7432_VL, t->volume);
+               tda7432_write(sd, TDA7432_VL, t->volume);
                return 0;
        case V4L2_CID_AUDIO_BALANCE:
                if (ctrl->value < 32768) {
@@ -428,14 +388,14 @@ static int tda7432_set_ctrl(struct i2c_client *client,
                if(t->bass>= 0x8)
                                t->bass = (~t->bass & 0xf) + 0x8 ;
 
-               tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+               tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
                return 0;
        case V4L2_CID_AUDIO_TREBLE:
                t->treble= ctrl->value >> 12;
                if(t->treble>= 0x8)
                                t->treble = (~t->treble & 0xf) + 0x8 ;
 
-               tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+               tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
                return 0;
        default:
                return -EINVAL;
@@ -445,92 +405,102 @@ static int tda7432_set_ctrl(struct i2c_client *client,
        if (t->muted)
        {
                /* Mute & update balance*/
-               tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
-               tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
-               tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
-               tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+               tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE);
+               tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE);
+               tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE);
+               tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE);
        } else {
-               tda7432_write(client,TDA7432_LF, t->lf);
-               tda7432_write(client,TDA7432_LR, t->lr);
-               tda7432_write(client,TDA7432_RF, t->rf);
-               tda7432_write(client,TDA7432_RR, t->rr);
+               tda7432_write(sd, TDA7432_LF, t->lf);
+               tda7432_write(sd, TDA7432_LR, t->lr);
+               tda7432_write(sd, TDA7432_RF, t->rf);
+               tda7432_write(sd, TDA7432_RR, t->rr);
        }
        return 0;
 }
 
-static int tda7432_command(struct i2c_client *client,
-                          unsigned int cmd, void *arg)
+static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
-       v4l_dbg(2, debug,client,"In tda7432_command\n");
-       if (debug>1)
-               v4l_i2c_print_ioctl(client,cmd);
-
-       switch (cmd) {
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-
-               switch (qc->id) {
-                       case V4L2_CID_AUDIO_MUTE:
-                       case V4L2_CID_AUDIO_VOLUME:
-                       case V4L2_CID_AUDIO_BALANCE:
-                       case V4L2_CID_AUDIO_BASS:
-                       case V4L2_CID_AUDIO_TREBLE:
-                       default:
-                               return -EINVAL;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
                return v4l2_ctrl_query_fill_std(qc);
        }
-       case VIDIOC_S_CTRL:
-               return tda7432_set_ctrl(client, arg);
-
-       case VIDIOC_G_CTRL:
-               return tda7432_get_ctrl(client, arg);
-
-       } /* end of (cmd) switch */
+       return -EINVAL;
+}
 
-       return 0;
+static int tda7432_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
 }
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name    = "tda7432",
-       },
-       .id              = I2C_DRIVERID_TDA7432,
-       .attach_adapter  = tda7432_probe,
-       .detach_client   = tda7432_detach,
-       .command         = tda7432_command,
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tda7432_core_ops = {
+       .queryctrl = tda7432_queryctrl,
+       .g_ctrl = tda7432_g_ctrl,
+       .s_ctrl = tda7432_s_ctrl,
 };
 
-static struct i2c_client client_template =
-{
-       .name       = "tda7432",
-       .driver     = &driver,
+static const struct v4l2_subdev_ops tda7432_ops = {
+       .core = &tda7432_core_ops,
 };
 
-static int __init tda7432_init(void)
+/* ----------------------------------------------------------------------- */
+
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
+
+static int tda7432_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       if ( (loudness < 0) || (loudness > 15) ) {
-               printk(KERN_ERR "loudness parameter must be between 0 and 15\n");
-               return -EINVAL;
+       struct tda7432 *t;
+       struct v4l2_subdev *sd;
+
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+       sd = &t->sd;
+       v4l2_i2c_subdev_init(sd, client, &tda7432_ops);
+       if (loudness < 0 || loudness > 15) {
+               v4l2_warn(sd, "loudness parameter must be between 0 and 15\n");
+               if (loudness < 0)
+                       loudness = 0;
+               if (loudness > 15)
+                       loudness = 15;
        }
 
-       return i2c_add_driver(&driver);
+       do_tda7432_init(sd);
+       return 0;
 }
 
-static void __exit tda7432_fini(void)
+static int tda7432_remove(struct i2c_client *client)
 {
-       i2c_del_driver(&driver);
-}
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-module_init(tda7432_init);
-module_exit(tda7432_fini);
+       do_tda7432_init(sd);
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
+       return 0;
+}
 
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+static const struct i2c_device_id tda7432_id[] = {
+       { "tda7432", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tda7432_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tda7432",
+       .driverid = I2C_DRIVERID_TDA7432,
+       .command = tda7432_command,
+       .probe = tda7432_probe,
+       .remove = tda7432_remove,
+       .id_table = tda7432_id,
+};
index 1c391f0328fd195c1f977956cae06d5ab02428fa..2644e0dc925139dab0e8a7f4881257c3cf44ef05 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 #include "tda9840.h"
 
@@ -62,85 +62,89 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END };
 /* magic definition of all other variables and things */
 I2C_CLIENT_INSMOD;
 
-static void tda9840_write(struct i2c_client *client, u8 reg, u8 val)
+static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
        if (i2c_smbus_write_byte_data(client, reg, val))
-               v4l_dbg(1, debug, client, "error writing %02x to %02x\n",
+               v4l2_dbg(1, debug, sd, "error writing %02x to %02x\n",
                                val, reg);
 }
 
-static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
 {
-       int byte = *(int *)arg;
-
-       switch (cmd) {
-       case VIDIOC_S_TUNER: {
-               struct v4l2_tuner *t = arg;
-               int byte;
+       int byte;
 
-               if (t->index)
-                       return -EINVAL;
+       if (t->index)
+               return -EINVAL;
 
-               switch (t->audmode) {
-               case V4L2_TUNER_MODE_STEREO:
-                       byte = TDA9840_SET_STEREO;
-                       break;
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       byte = TDA9840_SET_BOTH;
-                       break;
-               case V4L2_TUNER_MODE_LANG1:
-                       byte = TDA9840_SET_LANG1;
-                       break;
-               case V4L2_TUNER_MODE_LANG2:
-                       byte = TDA9840_SET_LANG2;
-                       break;
-               default:
-                       byte = TDA9840_SET_MONO;
-                       break;
-               }
-               v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte);
-               tda9840_write(client, SWITCH, byte);
+       switch (t->audmode) {
+       case V4L2_TUNER_MODE_STEREO:
+               byte = TDA9840_SET_STEREO;
                break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               byte = TDA9840_SET_BOTH;
+               break;
+       case V4L2_TUNER_MODE_LANG1:
+               byte = TDA9840_SET_LANG1;
+               break;
+       case V4L2_TUNER_MODE_LANG2:
+               byte = TDA9840_SET_LANG2;
+               break;
+       default:
+               byte = TDA9840_SET_MONO;
+               break;
+       }
+       v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
+       tda9840_write(sd, SWITCH, byte);
+       return 0;
+}
+
+static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 byte;
+
+       t->rxsubchans = V4L2_TUNER_SUB_MONO;
+       if (1 != i2c_master_recv(client, &byte, 1)) {
+               v4l2_dbg(1, debug, sd,
+                       "i2c_master_recv() failed\n");
+               return -EIO;
+       }
+
+       if (byte & 0x80) {
+               v4l2_dbg(1, debug, sd,
+                       "TDA9840_DETECT: register contents invalid\n");
+               return -EINVAL;
        }
 
-       case VIDIOC_G_TUNER: {
-               struct v4l2_tuner *t = arg;
-               u8 byte;
+       v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);
 
+       switch (byte & 0x60) {
+       case 0x00:
                t->rxsubchans = V4L2_TUNER_SUB_MONO;
-               if (1 != i2c_master_recv(client, &byte, 1)) {
-                       v4l_dbg(1, debug, client,
-                               "i2c_master_recv() failed\n");
-                       return -EIO;
-               }
-
-               if (byte & 0x80) {
-                       v4l_dbg(1, debug, client,
-                               "TDA9840_DETECT: register contents invalid\n");
-                       return -EINVAL;
-               }
-
-               v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte);
-
-               switch (byte & 0x60) {
-               case 0x00:
-                       t->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       break;
-               case 0x20:
-                       t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
-                       break;
-               case 0x40:
-                       t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-                       break;
-               default: /* Incorrect detect */
-                       t->rxsubchans = V4L2_TUNER_MODE_MONO;
-                       break;
-               }
+               break;
+       case 0x20:
+               t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+               break;
+       case 0x40:
+               t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+               break;
+       default: /* Incorrect detect */
+               t->rxsubchans = V4L2_TUNER_MODE_MONO;
                break;
        }
+       return 0;
+}
 
+static int tda9840_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+{
+       int byte;
+
+       switch (cmd) {
        case TDA9840_LEVEL_ADJUST:
-               v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte);
+               byte = *(int *)arg;
+               v4l2_dbg(1, debug, sd, "TDA9840_LEVEL_ADJUST: %d\n", byte);
 
                /* check for correct range */
                if (byte > 25 || byte < -20)
@@ -152,11 +156,12 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
                        byte += 0x8;
                else
                        byte = -byte;
-               tda9840_write(client, LEVEL_ADJUST, byte);
+               tda9840_write(sd, LEVEL_ADJUST, byte);
                break;
 
        case TDA9840_STEREO_ADJUST:
-               v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte);
+               byte = *(int *)arg;
+               v4l2_dbg(1, debug, sd, "TDA9840_STEREO_ADJUST: %d\n", byte);
 
                /* check for correct range */
                if (byte > 25 || byte < -24)
@@ -169,18 +174,41 @@ static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
                else
                        byte = -byte;
 
-               tda9840_write(client, STEREO_ADJUST, byte);
+               tda9840_write(sd, STEREO_ADJUST, byte);
                break;
        default:
                return -ENOIOCTLCMD;
        }
-
        return 0;
 }
 
+static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tda9840_core_ops = {
+       .ioctl = tda9840_ioctl,
+};
+
+static const struct v4l2_subdev_tuner_ops tda9840_tuner_ops = {
+       .s_tuner = tda9840_s_tuner,
+       .g_tuner = tda9840_g_tuner,
+};
+
+static const struct v4l2_subdev_ops tda9840_ops = {
+       .core = &tda9840_core_ops,
+       .tuner = &tda9840_tuner_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
 static int tda9840_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
+       struct v4l2_subdev *sd;
        int result;
        int byte;
 
@@ -188,23 +216,38 @@ static int tda9840_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter,
                        I2C_FUNC_SMBUS_READ_BYTE_DATA |
                        I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-               return 0;
+               return -EIO;
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
+       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(sd, client, &tda9840_ops);
+
        /* set initial values for level & stereo - adjustment, mode */
        byte = 0;
-       result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte);
-       result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte);
-       tda9840_write(client, SWITCH, TDA9840_SET_STEREO);
+       result = tda9840_ioctl(sd, TDA9840_LEVEL_ADJUST, &byte);
+       result |= tda9840_ioctl(sd, TDA9840_STEREO_ADJUST, &byte);
+       tda9840_write(sd, SWITCH, TDA9840_SET_STEREO);
        if (result) {
-               v4l_dbg(1, debug, client, "could not initialize tda9840\n");
+               v4l2_dbg(1, debug, sd, "could not initialize tda9840\n");
+               kfree(sd);
                return -ENODEV;
        }
        return 0;
 }
 
+static int tda9840_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
+       return 0;
+}
+
 static int tda9840_legacy_probe(struct i2c_adapter *adapter)
 {
        /* Let's see whether this is a known adapter we can attach to.
@@ -222,6 +265,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .driverid = I2C_DRIVERID_TDA9840,
        .command = tda9840_command,
        .probe = tda9840_probe,
+       .remove = tda9840_remove,
        .legacy_probe = tda9840_legacy_probe,
        .id_table = tda9840_id,
 };
index 792f0b079909c31513f06a89bc3183972bb908d8..56f0c0eb500facd70b7657f5f05cc8d432a25671 100644 (file)
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
-
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/i2c-addr.h>
 
 static int debug; /* insmod parameter */
@@ -46,13 +45,15 @@ I2C_CLIENT_INSMOD;
 
 /* This is a superset of the TDA9875 */
 struct tda9875 {
+       struct v4l2_subdev sd;
        int rvol, lvol;
        int bass, treble;
-       struct i2c_client c;
 };
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
+static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct tda9875, sd);
+}
 
 #define dprintk  if (debug) printk
 
@@ -105,15 +106,16 @@ static struct i2c_client client_template;
 
 /* Begin code */
 
-static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char val)
+static int tda9875_write(struct v4l2_subdev *sd, int subaddr, unsigned char val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        unsigned char buffer[2];
-       dprintk("In tda9875_write\n");
-       dprintk("Writing %d 0x%x\n", subaddr, val);
+
+       v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val);
        buffer[0] = subaddr;
        buffer[1] = val;
-       if (2 != i2c_master_send(client,buffer,2)) {
-               printk(KERN_WARNING "tda9875: I/O error, trying (write %d 0x%x)\n",
+       if (2 != i2c_master_send(client, buffer, 2)) {
+               v4l2_warn(sd, "I/O error, trying (write %d 0x%x)\n",
                       subaddr, val);
                return -1;
        }
@@ -121,7 +123,7 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v
 }
 
 
-static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
+static int i2c_read_register(struct i2c_client *client, int addr, int reg)
 {
        unsigned char write[1];
        unsigned char read[1];
@@ -129,150 +131,83 @@ static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
                { addr, 0,        1, write },
                { addr, I2C_M_RD, 1, read  }
        };
+
        write[0] = reg;
 
-       if (2 != i2c_transfer(adap,msgs,2)) {
-               printk(KERN_WARNING "tda9875: I/O error (read2)\n");
+       if (2 != i2c_transfer(client->adapter, msgs, 2)) {
+               v4l_warn(client, "I/O error (read2)\n");
                return -1;
        }
-       dprintk("tda9875: chip_read2: reg%d=0x%x\n",reg,read[0]);
+       v4l_dbg(1, debug, client, "chip_read2: reg%d=0x%x\n", reg, read[0]);
        return read[0];
 }
 
-static void tda9875_set(struct i2c_client *client)
+static void tda9875_set(struct v4l2_subdev *sd)
 {
-       struct tda9875 *tda = i2c_get_clientdata(client);
+       struct tda9875 *tda = to_state(sd);
        unsigned char a;
 
-       dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",
-               tda->lvol,tda->rvol,tda->bass,tda->treble);
-
+       v4l2_dbg(1, debug, sd, "tda9875_set(%04x,%04x,%04x,%04x)\n",
+               tda->lvol, tda->rvol, tda->bass, tda->treble);
 
        a = tda->lvol & 0xff;
-       tda9875_write(client, TDA9875_MVL, a);
+       tda9875_write(sd, TDA9875_MVL, a);
        a =tda->rvol & 0xff;
-       tda9875_write(client, TDA9875_MVR, a);
+       tda9875_write(sd, TDA9875_MVR, a);
        a =tda->bass & 0xff;
-       tda9875_write(client, TDA9875_MBA, a);
+       tda9875_write(sd, TDA9875_MBA, a);
        a =tda->treble  & 0xff;
-       tda9875_write(client, TDA9875_MTR, a);
+       tda9875_write(sd, TDA9875_MTR, a);
 }
 
-static void do_tda9875_init(struct i2c_client *client)
+static void do_tda9875_init(struct v4l2_subdev *sd)
 {
-       struct tda9875 *t = i2c_get_clientdata(client);
-       dprintk("In tda9875_init\n");
-       tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
-       tda9875_write(client, TDA9875_MSR, 0x03 );    /* Monitor 0b00000XXX*/
-       tda9875_write(client, TDA9875_C1MSB, 0x00 );  /*Car1(FM) MSB XMHz*/
-       tda9875_write(client, TDA9875_C1MIB, 0x00 );  /*Car1(FM) MIB XMHz*/
-       tda9875_write(client, TDA9875_C1LSB, 0x00 );  /*Car1(FM) LSB XMHz*/
-       tda9875_write(client, TDA9875_C2MSB, 0x00 );  /*Car2(NICAM) MSB XMHz*/
-       tda9875_write(client, TDA9875_C2MIB, 0x00 );  /*Car2(NICAM) MIB XMHz*/
-       tda9875_write(client, TDA9875_C2LSB, 0x00 );  /*Car2(NICAM) LSB XMHz*/
-       tda9875_write(client, TDA9875_DCR, 0x00 );    /*Demod config 0x00*/
-       tda9875_write(client, TDA9875_DEEM, 0x44 );   /*DE-Emph 0b0100 0100*/
-       tda9875_write(client, TDA9875_FMAT, 0x00 );   /*FM Matrix reg 0x00*/
-       tda9875_write(client, TDA9875_SC1, 0x00 );    /* SCART 1 (SC1)*/
-       tda9875_write(client, TDA9875_SC2, 0x01 );    /* SCART 2 (sc2)*/
-
-       tda9875_write(client, TDA9875_CH1V, 0x10 );  /* Channel volume 1 mute*/
-       tda9875_write(client, TDA9875_CH2V, 0x10 );  /* Channel volume 2 mute */
-       tda9875_write(client, TDA9875_DACOS, 0x02 ); /* sig DAC i/o(in:nicam)*/
-       tda9875_write(client, TDA9875_ADCIS, 0x6f ); /* sig ADC input(in:mono)*/
-       tda9875_write(client, TDA9875_LOSR, 0x00 );  /* line out (in:mono)*/
-       tda9875_write(client, TDA9875_AER, 0x00 );   /*06 Effect (AVL+PSEUDO) */
-       tda9875_write(client, TDA9875_MCS, 0x44 );   /* Main ch select (DAC) */
-       tda9875_write(client, TDA9875_MVL, 0x03 );   /* Vol Main left 10dB */
-       tda9875_write(client, TDA9875_MVR, 0x03 );   /* Vol Main right 10dB*/
-       tda9875_write(client, TDA9875_MBA, 0x00 );   /* Main Bass Main 0dB*/
-       tda9875_write(client, TDA9875_MTR, 0x00 );   /* Main Treble Main 0dB*/
-       tda9875_write(client, TDA9875_ACS, 0x44 );   /* Aux chan select (dac)*/
-       tda9875_write(client, TDA9875_AVL, 0x00 );   /* Vol Aux left 0dB*/
-       tda9875_write(client, TDA9875_AVR, 0x00 );   /* Vol Aux right 0dB*/
-       tda9875_write(client, TDA9875_ABA, 0x00 );   /* Aux Bass Main 0dB*/
-       tda9875_write(client, TDA9875_ATR, 0x00 );   /* Aux Aigus Main 0dB*/
-
-       tda9875_write(client, TDA9875_MUT, 0xcc );   /* General mute  */
-
-       t->lvol=t->rvol =0;     /* 0dB */
-       t->bass=0;                      /* 0dB */
-       t->treble=0;            /* 0dB */
-       tda9875_set(client);
-
+       struct tda9875 *t = to_state(sd);
+
+       v4l2_dbg(1, debug, sd, "In tda9875_init\n");
+       tda9875_write(sd, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
+       tda9875_write(sd, TDA9875_MSR, 0x03);    /* Monitor 0b00000XXX*/
+       tda9875_write(sd, TDA9875_C1MSB, 0x00);  /*Car1(FM) MSB XMHz*/
+       tda9875_write(sd, TDA9875_C1MIB, 0x00);  /*Car1(FM) MIB XMHz*/
+       tda9875_write(sd, TDA9875_C1LSB, 0x00);  /*Car1(FM) LSB XMHz*/
+       tda9875_write(sd, TDA9875_C2MSB, 0x00);  /*Car2(NICAM) MSB XMHz*/
+       tda9875_write(sd, TDA9875_C2MIB, 0x00);  /*Car2(NICAM) MIB XMHz*/
+       tda9875_write(sd, TDA9875_C2LSB, 0x00);  /*Car2(NICAM) LSB XMHz*/
+       tda9875_write(sd, TDA9875_DCR, 0x00);    /*Demod config 0x00*/
+       tda9875_write(sd, TDA9875_DEEM, 0x44);   /*DE-Emph 0b0100 0100*/
+       tda9875_write(sd, TDA9875_FMAT, 0x00);   /*FM Matrix reg 0x00*/
+       tda9875_write(sd, TDA9875_SC1, 0x00);    /* SCART 1 (SC1)*/
+       tda9875_write(sd, TDA9875_SC2, 0x01);    /* SCART 2 (sc2)*/
+
+       tda9875_write(sd, TDA9875_CH1V, 0x10);  /* Channel volume 1 mute*/
+       tda9875_write(sd, TDA9875_CH2V, 0x10);  /* Channel volume 2 mute */
+       tda9875_write(sd, TDA9875_DACOS, 0x02); /* sig DAC i/o(in:nicam)*/
+       tda9875_write(sd, TDA9875_ADCIS, 0x6f); /* sig ADC input(in:mono)*/
+       tda9875_write(sd, TDA9875_LOSR, 0x00);  /* line out (in:mono)*/
+       tda9875_write(sd, TDA9875_AER, 0x00);   /*06 Effect (AVL+PSEUDO) */
+       tda9875_write(sd, TDA9875_MCS, 0x44);   /* Main ch select (DAC) */
+       tda9875_write(sd, TDA9875_MVL, 0x03);   /* Vol Main left 10dB */
+       tda9875_write(sd, TDA9875_MVR, 0x03);   /* Vol Main right 10dB*/
+       tda9875_write(sd, TDA9875_MBA, 0x00);   /* Main Bass Main 0dB*/
+       tda9875_write(sd, TDA9875_MTR, 0x00);   /* Main Treble Main 0dB*/
+       tda9875_write(sd, TDA9875_ACS, 0x44);   /* Aux chan select (dac)*/
+       tda9875_write(sd, TDA9875_AVL, 0x00);   /* Vol Aux left 0dB*/
+       tda9875_write(sd, TDA9875_AVR, 0x00);   /* Vol Aux right 0dB*/
+       tda9875_write(sd, TDA9875_ABA, 0x00);   /* Aux Bass Main 0dB*/
+       tda9875_write(sd, TDA9875_ATR, 0x00);   /* Aux Aigus Main 0dB*/
+
+       tda9875_write(sd, TDA9875_MUT, 0xcc);   /* General mute  */
+
+       t->lvol = t->rvol = 0;          /* 0dB */
+       t->bass = 0;                    /* 0dB */
+       t->treble = 0;                  /* 0dB */
+       tda9875_set(sd);
 }
 
 
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda9875_checkit(struct i2c_adapter *adap, int addr)
-{
-       int dic,rev;
-
-       dic=i2c_read_register(adap,addr,254);
-       rev=i2c_read_register(adap,addr,255);
-
-       if(dic==0 || dic==2) { // tda9875 and tda9875A
-               printk("tda9875: TDA9875%s Rev.%d detected at 0x%x\n",
-               dic==0?"":"A", rev,addr<<1);
-               return 1;
-       }
-       printk("tda9875: no such chip at 0x%x (dic=0x%x rev=0x%x)\n",addr<<1,dic,rev);
-       return(0);
-}
-
-static int tda9875_attach(struct i2c_adapter *adap, int addr, int kind)
+static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct tda9875 *t;
-       struct i2c_client *client;
-       dprintk("In tda9875_attach\n");
-
-       t = kzalloc(sizeof *t,GFP_KERNEL);
-       if (!t)
-               return -ENOMEM;
-
-       client = &t->c;
-       memcpy(client,&client_template,sizeof(struct i2c_client));
-       client->adapter = adap;
-       client->addr = addr;
-       i2c_set_clientdata(client, t);
-
-       if(!tda9875_checkit(adap,addr)) {
-               kfree(t);
-               return 1;
-       }
-
-       do_tda9875_init(client);
-       printk(KERN_INFO "tda9875: init\n");
-
-       i2c_attach_client(client);
-       return 0;
-}
-
-static int tda9875_probe(struct i2c_adapter *adap)
-{
-       if (adap->class & I2C_CLASS_TV_ANALOG)
-               return i2c_probe(adap, &addr_data, tda9875_attach);
-       return 0;
-}
-
-static int tda9875_detach(struct i2c_client *client)
-{
-       struct tda9875 *t  = i2c_get_clientdata(client);
-
-       do_tda9875_init(client);
-       i2c_detach_client(client);
-
-       kfree(t);
-       return 0;
-}
-
-static int tda9875_get_ctrl(struct i2c_client *client,
-                           struct v4l2_control *ctrl)
-{
-       struct tda9875 *t = i2c_get_clientdata(client);
+       struct tda9875 *t = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_VOLUME:
@@ -304,10 +239,9 @@ static int tda9875_get_ctrl(struct i2c_client *client,
        return -EINVAL;
 }
 
-static int tda9875_set_ctrl(struct i2c_client *client,
-                           struct v4l2_control *ctrl)
+static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct tda9875 *t = i2c_get_clientdata(client);
+       struct tda9875 *t = to_state(sd);
        int chvol=0, volume, balance, left, right;
 
        switch (ctrl->id) {
@@ -371,85 +305,105 @@ static int tda9875_set_ctrl(struct i2c_client *client,
                        t->rvol = -84 & 0xff;
        }
 
-//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
-
-       tda9875_set(client);
-
+       tda9875_set(sd);
        return 0;
 }
 
-
-static int tda9875_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
+static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
 {
-       dprintk("In tda9875_command...\n");
-
-       switch (cmd) {
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-
-               switch (qc->id) {
-                       case V4L2_CID_AUDIO_VOLUME:
-                       case V4L2_CID_AUDIO_BASS:
-                       case V4L2_CID_AUDIO_TREBLE:
-                       default:
-                               return -EINVAL;
-               }
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
                return v4l2_ctrl_query_fill_std(qc);
        }
-       case VIDIOC_S_CTRL:
-               return tda9875_set_ctrl(client, arg);
+       return -EINVAL;
+}
 
-       case VIDIOC_G_CTRL:
-               return tda9875_get_ctrl(client, arg);
+static int tda9875_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
 
-       default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
+/* ----------------------------------------------------------------------- */
 
-               /* nothing */
-               dprintk("Default\n");
+static const struct v4l2_subdev_core_ops tda9875_core_ops = {
+       .queryctrl = tda9875_queryctrl,
+       .g_ctrl = tda9875_g_ctrl,
+       .s_ctrl = tda9875_s_ctrl,
+};
 
-       } /* end of (cmd) switch */
+static const struct v4l2_subdev_ops tda9875_ops = {
+       .core = &tda9875_core_ops,
+};
 
-       return 0;
-}
+/* ----------------------------------------------------------------------- */
 
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "tda9875",
-       },
-       .id             = I2C_DRIVERID_TDA9875,
-       .attach_adapter = tda9875_probe,
-       .detach_client  = tda9875_detach,
-       .command        = tda9875_command,
-};
+/* *********************** *
+ * i2c interface functions *
+ * *********************** */
 
-static struct i2c_client client_template =
+static int tda9875_checkit(struct i2c_client *client, int addr)
 {
-       .name      = "tda9875",
-       .driver    = &driver,
-};
+       int dic, rev;
 
-static int __init tda9875_init(void)
-{
-       return i2c_add_driver(&driver);
+       dic = i2c_read_register(client, addr, 254);
+       rev = i2c_read_register(client, addr, 255);
+
+       if (dic == 0 || dic == 2) { /* tda9875 and tda9875A */
+               v4l_info(client, "tda9875%s rev. %d detected at 0x%02x\n",
+                       dic == 0 ? "" : "A", rev, addr << 1);
+               return 1;
+       }
+       v4l_info(client, "no such chip at 0x%02x (dic=0x%x rev=0x%x)\n",
+                       addr << 1, dic, rev);
+       return 0;
 }
 
-static void __exit tda9875_fini(void)
+static int tda9875_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
-       i2c_del_driver(&driver);
+       struct tda9875 *t;
+       struct v4l2_subdev *sd;
+
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       if (!tda9875_checkit(client, client->addr))
+               return -ENODEV;
+
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+       sd = &t->sd;
+       v4l2_i2c_subdev_init(sd, client, &tda9875_ops);
+
+       do_tda9875_init(sd);
+       return 0;
 }
 
-module_init(tda9875_init);
-module_exit(tda9875_fini);
+static int tda9875_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+       do_tda9875_init(sd);
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
+       return 0;
+}
 
+static const struct i2c_device_id tda9875_id[] = {
+       { "tda9875", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tda9875_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tda9875",
+       .driverid = I2C_DRIVERID_TDA9875,
+       .command = tda9875_command,
+       .probe = tda9875_probe,
+       .remove = tda9875_remove,
+       .id_table = tda9875_id,
+};
index cde092adbb5abffdd1aafaf0b21d2b566ff20bcd..31dde86f2df4f6f187fe97eea6c8358efef22f1a 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 #include "tea6415c.h"
 
@@ -122,31 +122,57 @@ static int switch_matrix(struct i2c_client *client, int i, int o)
        return ret;
 }
 
-static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int tea6415c_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
 {
-       struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
-       int result = 0;
+       if (cmd == TEA6415C_SWITCH) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg;
 
-       switch (cmd) {
-       case TEA6415C_SWITCH:
-               result = switch_matrix(client, v->in, v->out);
-               break;
-       default:
-               return -ENOIOCTLCMD;
+               return switch_matrix(client, v->in, v->out);
        }
-       return result;
+       return -ENOIOCTLCMD;
 }
 
+static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tea6415c_core_ops = {
+       .ioctl = tea6415c_ioctl,
+};
+
+static const struct v4l2_subdev_ops tea6415c_ops = {
+       .core = &tea6415c_core_ops,
+};
+
 /* this function is called by i2c_probe */
 static int tea6415c_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
+       struct v4l2_subdev *sd;
+
        /* let's see whether this adapter can support what we need */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
                return 0;
 
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
+       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(sd, client, &tea6415c_ops);
+       return 0;
+}
+
+static int tea6415c_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
        return 0;
 }
 
@@ -168,6 +194,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .driverid = I2C_DRIVERID_TEA6415C,
        .command = tea6415c_command,
        .probe = tea6415c_probe,
+       .remove = tea6415c_remove,
        .legacy_probe = tea6415c_legacy_probe,
        .id_table = tea6415c_id,
 };
index e50820969e6485f5bde152e43bcc0f741df685ac..38e519f04bdeac9241ca12e7d70a3da598d7321d 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/module.h>
 #include <linux/ioctl.h>
 #include <linux/i2c.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 #include "tea6420.h"
 
@@ -90,26 +90,37 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g)
        return 0;
 }
 
-static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int tea6420_ioctl(struct v4l2_subdev *sd, unsigned cmd, void *arg)
 {
-       struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
-       int result = 0;
+       if (cmd == TEA6420_SWITCH) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg;
 
-       switch (cmd) {
-       case TEA6420_SWITCH:
-               result = tea6420_switch(client, a->in, a->out, a->gain);
-               break;
-       default:
-               return -ENOIOCTLCMD;
+               return tea6420_switch(client, a->in, a->out, a->gain);
        }
+       return -ENOIOCTLCMD;
+}
 
-       return result;
+static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
 }
 
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tea6420_core_ops = {
+       .ioctl = tea6420_ioctl,
+};
+
+static const struct v4l2_subdev_ops tea6420_ops = {
+       .core = &tea6420_core_ops,
+};
+
 /* this function is called by i2c_probe */
 static int tea6420_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
+       struct v4l2_subdev *sd;
        int err, i;
 
        /* let's see whether this adapter can support what we need */
@@ -126,9 +137,22 @@ static int tea6420_probe(struct i2c_client *client,
        }
        if (err) {
                v4l_dbg(1, debug, client, "could not initialize tea6420\n");
-               kfree(client);
                return -ENODEV;
        }
+
+       sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+       v4l2_i2c_subdev_init(sd, client, &tea6420_ops);
+       return 0;
+}
+
+static int tea6420_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
        return 0;
 }
 
@@ -150,6 +174,7 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .driverid = I2C_DRIVERID_TEA6420,
        .command = tea6420_command,
        .probe = tea6420_probe,
+       .remove = tea6420_remove,
        .legacy_probe = tea6420_legacy_probe,
        .id_table = tea6420_id,
 };
index 281065b9dd2df877d0c5425949b729b881f6aa17..5c95ecd09dc2bbaff772073c8d2f650739868faf 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
@@ -44,15 +44,22 @@ I2C_CLIENT_INSMOD;
 /* ----------------------------------------------------------------------- */
 
 struct tlv320aic23b_state {
+       struct v4l2_subdev sd;
        u8 muted;
 };
 
-static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
 {
+       return container_of(sd, struct tlv320aic23b_state, sd);
+}
+
+static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int i;
 
        if ((reg < 0 || reg > 9) && (reg != 15)) {
-               v4l_err(client, "Invalid register R%d\n", reg);
+               v4l2_err(sd, "Invalid register R%d\n", reg);
                return -1;
        }
 
@@ -60,61 +67,82 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
                if (i2c_smbus_write_byte_data(client,
                                (reg << 1) | (val >> 8), val & 0xff) == 0)
                        return 0;
-       v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+       v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
 
-static int tlv320aic23b_command(struct i2c_client *client,
-                               unsigned int cmd, void *arg)
+static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 {
-       struct tlv320aic23b_state *state = i2c_get_clientdata(client);
-       struct v4l2_control *ctrl = arg;
-       u32 *freq = arg;
-
-       switch (cmd) {
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-               switch (*freq) {
-               case 32000: /* set sample rate to 32 kHz */
-                       tlv320aic23b_write(client, 8, 0x018);
-                       break;
-               case 44100: /* set sample rate to 44.1 kHz */
-                       tlv320aic23b_write(client, 8, 0x022);
-                       break;
-               case 48000: /* set sample rate to 48 kHz */
-                       tlv320aic23b_write(client, 8, 0x000);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-
-       case VIDIOC_G_CTRL:
-               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               ctrl->value = state->muted;
+       switch (freq) {
+       case 32000: /* set sample rate to 32 kHz */
+               tlv320aic23b_write(sd, 8, 0x018);
                break;
-
-       case VIDIOC_S_CTRL:
-               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               state->muted = ctrl->value;
-               tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
-               /* set gain on both channels to +3.0 dB */
-               if (!state->muted)
-                       tlv320aic23b_write(client, 0, 0x119);
+       case 44100: /* set sample rate to 44.1 kHz */
+               tlv320aic23b_write(sd, 8, 0x022);
                break;
-
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Input: %s\n",
-                           state->muted ? "muted" : "active");
+       case 48000: /* set sample rate to 48 kHz */
+               tlv320aic23b_write(sd, 8, 0x000);
                break;
-
        default:
                return -EINVAL;
        }
        return 0;
 }
 
+static int tlv320aic23b_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct tlv320aic23b_state *state = to_state(sd);
+
+       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       ctrl->value = state->muted;
+       return 0;
+}
+
+static int tlv320aic23b_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct tlv320aic23b_state *state = to_state(sd);
+
+       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       state->muted = ctrl->value;
+       tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
+       /* set gain on both channels to +3.0 dB */
+       if (!state->muted)
+               tlv320aic23b_write(sd, 0, 0x119);
+       return 0;
+}
+
+static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
+{
+       struct tlv320aic23b_state *state = to_state(sd);
+
+       v4l2_info(sd, "Input: %s\n", state->muted ? "muted" : "active");
+       return 0;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
+       .log_status = tlv320aic23b_log_status,
+       .g_ctrl = tlv320aic23b_g_ctrl,
+       .s_ctrl = tlv320aic23b_s_ctrl,
+};
+
+static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
+       .s_clock_freq = tlv320aic23b_s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops tlv320aic23b_ops = {
+       .core = &tlv320aic23b_core_ops,
+       .audio = &tlv320aic23b_audio_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 /* i2c implementation */
@@ -128,6 +156,7 @@ static int tlv320aic23b_probe(struct i2c_client *client,
                              const struct i2c_device_id *id)
 {
        struct tlv320aic23b_state *state;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -136,32 +165,36 @@ static int tlv320aic23b_probe(struct i2c_client *client,
        v4l_info(client, "chip found @ 0x%x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
-       state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+       state = kzalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops);
        state->muted = 0;
-       i2c_set_clientdata(client, state);
 
        /* Initialize tlv320aic23b */
 
        /* RESET */
-       tlv320aic23b_write(client, 15, 0x000);
+       tlv320aic23b_write(sd, 15, 0x000);
        /* turn off DAC & mic input */
-       tlv320aic23b_write(client, 6, 0x00A);
+       tlv320aic23b_write(sd, 6, 0x00A);
        /* left-justified, 24-bit, master mode */
-       tlv320aic23b_write(client, 7, 0x049);
+       tlv320aic23b_write(sd, 7, 0x049);
        /* set gain on both channels to +3.0 dB */
-       tlv320aic23b_write(client, 0, 0x119);
+       tlv320aic23b_write(sd, 0, 0x119);
        /* set sample rate to 48 kHz */
-       tlv320aic23b_write(client, 8, 0x000);
+       tlv320aic23b_write(sd, 8, 0x000);
        /* activate digital interface */
-       tlv320aic23b_write(client, 9, 0x001);
+       tlv320aic23b_write(sd, 9, 0x001);
        return 0;
 }
 
 static int tlv320aic23b_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index 4a7735c6c1a65e022c11689c8b6ef4b1a8f86406..97d7509d212f67602526b21a5656794be0656d90 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/videodev.h>
 #include <media/tuner.h>
 #include <media/tuner-types.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 #include "mt20xx.h"
@@ -78,6 +78,7 @@ struct tuner {
        /* device */
        struct dvb_frontend fe;
        struct i2c_client   *i2c;
+       struct v4l2_subdev  sd;
        struct list_head    list;
        unsigned int        using_v4l2:1;
 
@@ -95,6 +96,11 @@ struct tuner {
        const char          *name;
 };
 
+static inline struct tuner *to_tuner(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct tuner, sd);
+}
+
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
 #if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
@@ -213,7 +219,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
 
 static void tuner_status(struct dvb_frontend *fe);
 
-static struct analog_demod_ops tuner_core_ops = {
+static struct analog_demod_ops tuner_analog_ops = {
        .set_params     = fe_set_params,
        .standby        = fe_standby,
        .has_signal     = fe_has_signal,
@@ -224,7 +230,7 @@ static struct analog_demod_ops tuner_core_ops = {
 /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        struct analog_parameters params = {
@@ -259,7 +265,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
        struct analog_parameters params = {
@@ -294,7 +300,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
 
        switch (t->mode) {
        case V4L2_TUNER_RADIO:
@@ -347,7 +353,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
                     unsigned int new_mode_mask, unsigned int new_config,
                     int (*tuner_callback) (void *dev, int component, int cmd, int arg))
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
        struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
        unsigned char buffer[4];
@@ -470,7 +476,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
                t->name = fe_tuner_ops->info.name;
 
                t->fe.analog_demod_priv = t;
-               memcpy(analog_ops, &tuner_core_ops,
+               memcpy(analog_ops, &tuner_analog_ops,
                       sizeof(struct analog_demod_ops));
 
        } else {
@@ -515,7 +521,7 @@ attach_failed:
 
 static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
 
        if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) &&
                (t->mode_mask & tun_setup->mode_mask))) ||
@@ -727,6 +733,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
        t->mode = mode;
 
        if (check_mode(t, cmd) == -EINVAL) {
+               tuner_dbg("Tuner doesn't support this mode. "
+                         "Putting tuner to sleep\n");
                t->mode = T_STANDBY;
                if (analog_ops->standby)
                        analog_ops->standby(&t->fe);
@@ -748,43 +756,58 @@ static inline int check_v4l2(struct tuner *t)
        return 0;
 }
 
-static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type)
 {
-       struct tuner *t = i2c_get_clientdata(client);
-       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
+                       type->type,
+                       type->addr,
+                       type->mode_mask,
+                       type->config);
+
+       set_addr(client, type);
+       return 0;
+}
+
+static int tuner_s_radio(struct v4l2_subdev *sd)
+{
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
+                       == -EINVAL)
+               return 0;
+       if (t->radio_freq)
+               set_freq(client, t->radio_freq);
+       return 0;
+}
+
+static int tuner_s_standby(struct v4l2_subdev *sd, u32 standby)
+{
+       struct tuner *t = to_tuner(sd);
        struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
-       if (tuner_debug > 1) {
-               v4l_i2c_print_ioctl(client,cmd);
-               printk("\n");
-       }
+       tuner_dbg("Putting tuner to sleep\n");
+
+       if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
+               return 0;
+       t->mode = T_STANDBY;
+       if (analog_ops->standby)
+               analog_ops->standby(&t->fe);
+       return 0;
+}
 
-       switch (cmd) {
-       /* --- configuration --- */
-       case TUNER_SET_TYPE_ADDR:
-               tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
-                               ((struct tuner_setup *)arg)->type,
-                               ((struct tuner_setup *)arg)->addr,
-                               ((struct tuner_setup *)arg)->mode_mask,
-                               ((struct tuner_setup *)arg)->config);
-
-               set_addr(client, (struct tuner_setup *)arg);
-               break;
-       case AUDC_SET_RADIO:
-               if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
-                               == -EINVAL)
-                       return 0;
-               if (t->radio_freq)
-                       set_freq(client, t->radio_freq);
-               break;
-       case TUNER_SET_STANDBY:
-               if (check_mode(t, "TUNER_SET_STANDBY") == -EINVAL)
-                       return 0;
-               t->mode = T_STANDBY;
-               if (analog_ops->standby)
-                       analog_ops->standby(&t->fe);
-               break;
 #ifdef CONFIG_VIDEO_ALLOW_V4L1
+static int tuner_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+       switch (cmd) {
        case VIDIOCSAUDIO:
                if (check_mode(t, "VIDIOCSAUDIO") == -EINVAL)
                        return 0;
@@ -897,149 +920,172 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
                        }
                        return 0;
                }
+       }
+       return -ENOIOCTLCMD;
+}
 #endif
-       case TUNER_SET_CONFIG:
-       {
-               struct v4l2_priv_tun_config *cfg = arg;
 
-               if (t->type != cfg->tuner)
-                       break;
+static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg)
+{
+       struct tuner *t = to_tuner(sd);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
-               if (analog_ops->set_config) {
-                       analog_ops->set_config(&t->fe, cfg->priv);
-                       break;
-               }
+       if (t->type != cfg->tuner)
+               return 0;
 
-               tuner_dbg("Tuner frontend module has no way to set config\n");
-               break;
+       if (analog_ops->set_config) {
+               analog_ops->set_config(&t->fe, cfg->priv);
+               return 0;
        }
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-          kernel pointer here... */
-       case VIDIOC_S_STD:
-               {
-                       v4l2_std_id *id = arg;
 
-                       if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
-                                       == -EINVAL)
-                               return 0;
+       tuner_dbg("Tuner frontend module has no way to set config\n");
+       return 0;
+}
 
-                       switch_v4l2();
+/* --- v4l ioctls --- */
+/* take care: bttv does userspace copying, we'll get a
+   kernel pointer here... */
+static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-                       t->std = *id;
-                       tuner_fixup_std(t);
-                       if (t->tv_freq)
-                               set_freq(client, t->tv_freq);
-                       break;
-               }
-       case VIDIOC_S_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
+       if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
+                       == -EINVAL)
+               return 0;
 
-                       if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
-                                       == -EINVAL)
-                               return 0;
-                       switch_v4l2();
-                       set_freq(client,f->frequency);
+       switch_v4l2();
 
-                       break;
-               }
-       case VIDIOC_G_FREQUENCY:
-               {
-                       struct v4l2_frequency *f = arg;
+       t->std = std;
+       tuner_fixup_std(t);
+       if (t->tv_freq)
+               set_freq(client, t->tv_freq);
+       return 0;
+}
 
-                       if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
-                               return 0;
-                       switch_v4l2();
-                       f->type = t->mode;
-                       if (fe_tuner_ops->get_frequency) {
-                               u32 abs_freq;
-
-                               fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
-                               f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
-                                       (abs_freq * 2 + 125/2) / 125 :
-                                       (abs_freq + 62500/2) / 62500;
-                               break;
-                       }
-                       f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
-                               t->radio_freq : t->tv_freq;
-                       break;
-               }
-       case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *tuner = arg;
+static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-                       if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
-                               return 0;
-                       switch_v4l2();
-
-                       tuner->type = t->mode;
-                       if (analog_ops->get_afc)
-                               tuner->afc = analog_ops->get_afc(&t->fe);
-                       if (t->mode == V4L2_TUNER_ANALOG_TV)
-                               tuner->capability |= V4L2_TUNER_CAP_NORM;
-                       if (t->mode != V4L2_TUNER_RADIO) {
-                               tuner->rangelow = tv_range[0] * 16;
-                               tuner->rangehigh = tv_range[1] * 16;
-                               break;
-                       }
+       if (set_mode(client, t, f->type, "VIDIOC_S_FREQUENCY")
+                       == -EINVAL)
+               return 0;
+       switch_v4l2();
+       set_freq(client, f->frequency);
 
-                       /* radio mode */
-                       tuner->rxsubchans =
-                               V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-                       if (fe_tuner_ops->get_status) {
-                               u32 tuner_status;
-
-                               fe_tuner_ops->get_status(&t->fe, &tuner_status);
-                               tuner->rxsubchans =
-                                       (tuner_status & TUNER_STATUS_STEREO) ?
-                                       V4L2_TUNER_SUB_STEREO :
-                                       V4L2_TUNER_SUB_MONO;
-                       } else {
-                               if (analog_ops->is_stereo) {
-                                       tuner->rxsubchans =
-                                               analog_ops->is_stereo(&t->fe) ?
-                                               V4L2_TUNER_SUB_STEREO :
-                                               V4L2_TUNER_SUB_MONO;
-                               }
-                       }
-                       if (analog_ops->has_signal)
-                               tuner->signal = analog_ops->has_signal(&t->fe);
-                       tuner->capability |=
-                           V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-                       tuner->audmode = t->audmode;
-                       tuner->rangelow = radio_range[0] * 16000;
-                       tuner->rangehigh = radio_range[1] * 16000;
-                       break;
-               }
-       case VIDIOC_S_TUNER:
-               {
-                       struct v4l2_tuner *tuner = arg;
+       return 0;
+}
 
-                       if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
-                               return 0;
+static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+{
+       struct tuner *t = to_tuner(sd);
+       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 
-                       switch_v4l2();
+       if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)
+               return 0;
+       switch_v4l2();
+       f->type = t->mode;
+       if (fe_tuner_ops->get_frequency) {
+               u32 abs_freq;
+
+               fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
+               f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+                       (abs_freq * 2 + 125/2) / 125 :
+                       (abs_freq + 62500/2) / 62500;
+               return 0;
+       }
+       f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+               t->radio_freq : t->tv_freq;
+       return 0;
+}
 
-                       /* do nothing unless we're a radio tuner */
-                       if (t->mode != V4L2_TUNER_RADIO)
-                               break;
-                       t->audmode = tuner->audmode;
-                       set_radio_freq(client, t->radio_freq);
-                       break;
+static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct tuner *t = to_tuner(sd);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+       struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+       if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)
+               return 0;
+       switch_v4l2();
+
+       vt->type = t->mode;
+       if (analog_ops->get_afc)
+               vt->afc = analog_ops->get_afc(&t->fe);
+       if (t->mode == V4L2_TUNER_ANALOG_TV)
+               vt->capability |= V4L2_TUNER_CAP_NORM;
+       if (t->mode != V4L2_TUNER_RADIO) {
+               vt->rangelow = tv_range[0] * 16;
+               vt->rangehigh = tv_range[1] * 16;
+               return 0;
+       }
+
+       /* radio mode */
+       vt->rxsubchans =
+               V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+       if (fe_tuner_ops->get_status) {
+               u32 tuner_status;
+
+               fe_tuner_ops->get_status(&t->fe, &tuner_status);
+               vt->rxsubchans =
+                       (tuner_status & TUNER_STATUS_STEREO) ?
+                       V4L2_TUNER_SUB_STEREO :
+                       V4L2_TUNER_SUB_MONO;
+       } else {
+               if (analog_ops->is_stereo) {
+                       vt->rxsubchans =
+                               analog_ops->is_stereo(&t->fe) ?
+                               V4L2_TUNER_SUB_STEREO :
+                               V4L2_TUNER_SUB_MONO;
                }
-       case VIDIOC_LOG_STATUS:
-               if (analog_ops->tuner_status)
-                       analog_ops->tuner_status(&t->fe);
-               break;
        }
+       if (analog_ops->has_signal)
+               vt->signal = analog_ops->has_signal(&t->fe);
+       vt->capability |=
+               V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+       vt->audmode = t->audmode;
+       vt->rangelow = radio_range[0] * 16000;
+       vt->rangehigh = radio_range[1] * 16000;
+       return 0;
+}
+
+static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct tuner *t = to_tuner(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
+       if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)
+               return 0;
+
+       switch_v4l2();
+
+       /* do nothing unless we're a radio tuner */
+       if (t->mode != V4L2_TUNER_RADIO)
+               return 0;
+       t->audmode = vt->audmode;
+       set_radio_freq(client, t->radio_freq);
        return 0;
 }
 
+static int tuner_log_status(struct v4l2_subdev *sd)
+{
+       struct tuner *t = to_tuner(sd);
+       struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+       if (analog_ops->tuner_status)
+               analog_ops->tuner_status(&t->fe);
+       return 0;
+}
+
+static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
 static int tuner_suspend(struct i2c_client *c, pm_message_t state)
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
 
        tuner_dbg("suspend\n");
        /* FIXME: power down ??? */
@@ -1048,7 +1094,7 @@ static int tuner_suspend(struct i2c_client *c, pm_message_t state)
 
 static int tuner_resume(struct i2c_client *c)
 {
-       struct tuner *t = i2c_get_clientdata(c);
+       struct tuner *t = to_tuner(i2c_get_clientdata(c));
 
        tuner_dbg("resume\n");
        if (V4L2_TUNER_RADIO == t->mode) {
@@ -1061,6 +1107,32 @@ static int tuner_resume(struct i2c_client *c)
        return 0;
 }
 
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tuner_core_ops = {
+       .log_status = tuner_log_status,
+       .s_standby = tuner_s_standby,
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
+       .ioctl = tuner_ioctl,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
+       .s_std = tuner_s_std,
+       .s_radio = tuner_s_radio,
+       .g_tuner = tuner_g_tuner,
+       .s_tuner = tuner_s_tuner,
+       .s_frequency = tuner_s_frequency,
+       .g_frequency = tuner_g_frequency,
+       .s_type_addr = tuner_s_type_addr,
+       .s_config = tuner_s_config,
+};
+
+static const struct v4l2_subdev_ops tuner_ops = {
+       .core = &tuner_core_ops,
+       .tuner = &tuner_tuner_ops,
+};
+
 /* ---------------------------------------------------------------------- */
 
 static LIST_HEAD(tuner_list);
@@ -1109,9 +1181,9 @@ static int tuner_probe(struct i2c_client *client,
        t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
        if (NULL == t)
                return -ENOMEM;
+       v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops);
        t->i2c = client;
        t->name = "(tuner unset)";
-       i2c_set_clientdata(client, t);
        t->type = UNSET;
        t->audmode = V4L2_TUNER_MODE_STEREO;
        t->mode_mask = T_UNINITIALIZED;
@@ -1261,8 +1333,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap)
 
 static int tuner_remove(struct i2c_client *client)
 {
-       struct tuner *t = i2c_get_clientdata(client);
+       struct tuner *t = to_tuner(i2c_get_clientdata(client));
 
+       v4l2_device_unregister_subdev(&t->sd);
        tuner_detach(&t->fe);
        t->fe.analog_demod_priv = NULL;
 
index 3720f0e03a16906efd339b0eefb89b5454499abf..d0c794da735b413eb8b83006e732c4e89117adda 100644 (file)
@@ -33,8 +33,7 @@
 #include <linux/freezer.h>
 
 #include <media/tvaudio.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 
@@ -110,7 +109,7 @@ struct CHIPDESC {
 
 /* current state of the chip */
 struct CHIPSTATE {
-       struct i2c_client *c;
+       struct v4l2_subdev sd;
 
        /* chip-specific description - should point to
           an entry at CHIPDESC table */
@@ -132,6 +131,11 @@ struct CHIPSTATE {
        int                  audmode;
 };
 
+static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct CHIPSTATE, sd);
+}
+
 /* ---------------------------------------------------------------------- */
 /* i2c addresses                                                          */
 
@@ -152,34 +156,34 @@ I2C_CLIENT_INSMOD;
 
 static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
        unsigned char buffer[2];
 
        if (subaddr < 0) {
-               v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
-                       chip->c->name, val);
+               v4l2_dbg(1, debug, sd, "chip_write: 0x%x\n", val);
                chip->shadow.bytes[1] = val;
                buffer[0] = val;
-               if (1 != i2c_master_send(chip->c,buffer,1)) {
-                       v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n",
-                               chip->c->name, val);
+               if (1 != i2c_master_send(c, buffer, 1)) {
+                       v4l2_warn(sd, "I/O error (write 0x%x)\n", val);
                        return -1;
                }
        } else {
                if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
-                       v4l_info(chip->c,
+                       v4l2_info(sd,
                                "Tried to access a non-existent register: %d\n",
                                subaddr);
                        return -EINVAL;
                }
 
-               v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
-                       chip->c->name, subaddr, val);
+               v4l2_dbg(1, debug, sd, "chip_write: reg%d=0x%x\n",
+                       subaddr, val);
                chip->shadow.bytes[subaddr+1] = val;
                buffer[0] = subaddr;
                buffer[1] = val;
-               if (2 != i2c_master_send(chip->c,buffer,2)) {
-                       v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n",
-                       chip->c->name, subaddr, val);
+               if (2 != i2c_master_send(c, buffer, 2)) {
+                       v4l2_warn(sd, "I/O error (write reg%d=0x%x)\n",
+                               subaddr, val);
                        return -1;
                }
        }
@@ -189,12 +193,14 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
 static int chip_write_masked(struct CHIPSTATE *chip,
                             int subaddr, int val, int mask)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+
        if (mask != 0) {
                if (subaddr < 0) {
                        val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
                } else {
                        if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
-                               v4l_info(chip->c,
+                               v4l2_info(sd,
                                        "Tried to access a non-existent register: %d\n",
                                        subaddr);
                                return -EINVAL;
@@ -208,45 +214,51 @@ static int chip_write_masked(struct CHIPSTATE *chip,
 
 static int chip_read(struct CHIPSTATE *chip)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
        unsigned char buffer;
 
-       if (1 != i2c_master_recv(chip->c,&buffer,1)) {
-               v4l_warn(chip->c, "%s: I/O error (read)\n",
-               chip->c->name);
+       if (1 != i2c_master_recv(c, &buffer, 1)) {
+               v4l2_warn(sd, "I/O error (read)\n");
                return -1;
        }
-       v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer);
+       v4l2_dbg(1, debug, sd, "chip_read: 0x%x\n", buffer);
        return buffer;
 }
 
 static int chip_read2(struct CHIPSTATE *chip, int subaddr)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
        unsigned char write[1];
        unsigned char read[1];
        struct i2c_msg msgs[2] = {
-               { chip->c->addr, 0,        1, write },
-               { chip->c->addr, I2C_M_RD, 1, read  }
+               { c->addr, 0,        1, write },
+               { c->addr, I2C_M_RD, 1, read  }
        };
+
        write[0] = subaddr;
 
-       if (2 != i2c_transfer(chip->c->adapter,msgs,2)) {
-               v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name);
+       if (2 != i2c_transfer(c->adapter, msgs, 2)) {
+               v4l2_warn(sd, "I/O error (read2)\n");
                return -1;
        }
-       v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n",
-               chip->c->name, subaddr,read[0]);
+       v4l2_dbg(1, debug, sd, "chip_read2: reg%d=0x%x\n",
+               subaddr, read[0]);
        return read[0];
 }
 
 static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
        int i;
 
        if (0 == cmd->count)
                return 0;
 
        if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
-               v4l_info(chip->c,
+               v4l2_info(sd,
                         "Tried to access a non-existent register range: %d to %d\n",
                         cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
                return -EINVAL;
@@ -255,19 +267,19 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
        /* FIXME: it seems that the shadow bytes are wrong bellow !*/
 
        /* update our shadow register set; print bytes if (debug > 0) */
-       v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
-               chip->c->name, name,cmd->bytes[0]);
+       v4l2_dbg(1, debug, sd, "chip_cmd(%s): reg=%d, data:",
+               name, cmd->bytes[0]);
        for (i = 1; i < cmd->count; i++) {
                if (debug)
-                       printk(" 0x%x",cmd->bytes[i]);
+                       printk(KERN_CONT " 0x%x", cmd->bytes[i]);
                chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
        }
        if (debug)
-               printk("\n");
+               printk(KERN_CONT "\n");
 
        /* send data to the chip */
-       if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) {
-               v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name);
+       if (cmd->count != i2c_master_send(c, cmd->bytes, cmd->count)) {
+               v4l2_warn(sd, "I/O error (%s)\n", name);
                return -1;
        }
        return 0;
@@ -290,9 +302,10 @@ static int chip_thread(void *data)
 {
        struct CHIPSTATE *chip = data;
        struct CHIPDESC  *desc = chip->desc;
+       struct v4l2_subdev *sd = &chip->sd;
        int mode;
 
-       v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
+       v4l2_dbg(1, debug, sd, "thread started\n");
        set_freezable();
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
@@ -302,7 +315,7 @@ static int chip_thread(void *data)
                try_to_freeze();
                if (kthread_should_stop())
                        break;
-               v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
+               v4l2_dbg(1, debug, sd, "thread wakeup\n");
 
                /* don't do anything for radio or if mode != auto */
                if (chip->radio || chip->mode != 0)
@@ -314,8 +327,7 @@ static int chip_thread(void *data)
                        continue;
 
                /* chip detected a new audio mode - set it */
-               v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n",
-                       chip->c->name);
+               v4l2_dbg(1, debug, sd, "thread checkmode\n");
 
                chip->prevmode = mode;
 
@@ -334,7 +346,7 @@ static int chip_thread(void *data)
                mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
        }
 
-       v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
+       v4l2_dbg(1, debug, sd, "thread exiting\n");
        return 0;
 }
 
@@ -363,6 +375,7 @@ static int chip_thread(void *data)
 
 static int tda9840_getmode(struct CHIPSTATE *chip)
 {
+       struct v4l2_subdev *sd = &chip->sd;
        int val, mode;
 
        val = chip_read(chip);
@@ -372,7 +385,7 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
        if (val & TDA9840_ST_STEREO)
                mode |= V4L2_TUNER_MODE_STEREO;
 
-       v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
+       v4l2_dbg(1, debug, sd, "tda9840_getmode(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
@@ -668,6 +681,7 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 
 static int tda9873_getmode(struct CHIPSTATE *chip)
 {
+       struct v4l2_subdev *sd = &chip->sd;
        int val,mode;
 
        val = chip_read(chip);
@@ -676,23 +690,24 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
                mode |= V4L2_TUNER_MODE_STEREO;
        if (val & TDA9873_DUAL)
                mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
-       v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
+       v4l2_dbg(1, debug, sd, "tda9873_getmode(): raw chip read: %d, return: %d\n",
                val, mode);
        return mode;
 }
 
 static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 {
+       struct v4l2_subdev *sd = &chip->sd;
        int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
        /*      int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
        if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-               v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n");
+               v4l2_dbg(1, debug, sd, "tda9873_setmode(): external input\n");
                return;
        }
 
-       v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-       v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
+       v4l2_dbg(1, debug, sd, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+       v4l2_dbg(1, debug, sd, "tda9873_setmode(): sw_data  = %d\n", sw_data);
 
        switch (mode) {
        case V4L2_TUNER_MODE_MONO:
@@ -713,7 +728,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        }
 
        chip_write(chip, TDA9873_SW, sw_data);
-       v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
+       v4l2_dbg(1, debug, sd, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
                mode, sw_data);
 }
 
@@ -822,6 +837,8 @@ static struct tda9874a_MODES {
 
 static int tda9874a_setup(struct CHIPSTATE *chip)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+
        chip_write(chip, TDA9874A_AGCGR, 0x00); /* 0 dB */
        chip_write(chip, TDA9874A_GCONR, tda9874a_GCONR);
        chip_write(chip, TDA9874A_MSR, (tda9874a_mode) ? 0x03:0x02);
@@ -852,13 +869,14 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
                chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
                chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
        }
-       v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n",
+       v4l2_dbg(1, debug, sd, "tda9874a_setup(): %s [0x%02X].\n",
                tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
        return 1;
 }
 
 static int tda9874a_getmode(struct CHIPSTATE *chip)
 {
+       struct v4l2_subdev *sd = &chip->sd;
        int dsr,nsr,mode;
        int necr; /* just for debugging */
 
@@ -895,16 +913,18 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
                        mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
        }
 
-       v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+       v4l2_dbg(1, debug, sd, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
                 dsr, nsr, necr, mode);
        return mode;
 }
 
 static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 {
+       struct v4l2_subdev *sd = &chip->sd;
+
        /* Disable/enable NICAM auto-muting (based on DSR.RSSF status bit). */
        /* If auto-muting is disabled, we can hear a signal of degrading quality. */
-       if(tda9874a_mode) {
+       if (tda9874a_mode) {
                if(chip->shadow.bytes[MAXREGS-2] & 0x20) /* DSR.RSSF=1 */
                        tda9874a_NCONR &= 0xfe; /* enable */
                else
@@ -941,7 +961,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                chip_write(chip, TDA9874A_AOSR, aosr);
                chip_write(chip, TDA9874A_MDACOSR, mdacosr);
 
-               v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+               v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
                        mode, aosr, mdacosr);
 
        } else { /* dic == 0x07 */
@@ -976,13 +996,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
                chip_write(chip, TDA9874A_FMMR, fmmr);
                chip_write(chip, TDA9874A_AOSR, aosr);
 
-               v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+               v4l2_dbg(1, debug, sd, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
                        mode, fmmr, aosr);
        }
 }
 
 static int tda9874a_checkit(struct CHIPSTATE *chip)
 {
+       struct v4l2_subdev *sd = &chip->sd;
        int dic,sic;    /* device id. and software id. codes */
 
        if(-1 == (dic = chip_read2(chip,TDA9874A_DIC)))
@@ -990,10 +1011,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
        if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
                return 0;
 
-       v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+       v4l2_dbg(1, debug, sd, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
 
        if((dic == 0x11)||(dic == 0x07)) {
-               v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+               v4l2_info(sd, "found tda9874%s.\n", (dic == 0x11) ? "a" : "h");
                tda9874a_dic = dic;     /* remember device id. */
                return 1;
        }
@@ -1113,12 +1134,12 @@ static int tda8425_shift12(int val) { return (val >> 12) | 0xf0; }
 static int tda8425_initialize(struct CHIPSTATE *chip)
 {
        struct CHIPDESC *desc = chip->desc;
+       struct i2c_client *c = v4l2_get_subdevdata(&chip->sd);
        int inputmap[4] = { /* tuner    */ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
                            /* extern   */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
 
-       if (chip->c->adapter->id == I2C_HW_B_RIVA) {
-               memcpy (desc->inputmap, inputmap, sizeof (inputmap));
-       }
+       if (c->adapter->id == I2C_HW_B_RIVA)
+               memcpy(desc->inputmap, inputmap, sizeof(inputmap));
        return 0;
 }
 
@@ -1215,9 +1236,11 @@ static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT
 
 static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 {
+       struct v4l2_subdev *sd = &chip->sd;
        int update = 1;
        audiocmd *t = NULL;
-       v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
+
+       v4l2_dbg(1, debug, sd, "ta8874z_setmode(): mode: 0x%02x\n", mode);
 
        switch(mode){
        case V4L2_TUNER_MODE_MONO:
@@ -1479,142 +1502,11 @@ static struct CHIPDESC chiplist[] = {
 
 
 /* ---------------------------------------------------------------------- */
-/* i2c registration                                                       */
-
-static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
-{
-       struct CHIPSTATE *chip;
-       struct CHIPDESC  *desc;
-
-       if (debug) {
-               printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
-               printk(KERN_INFO "tvaudio: known chips: ");
-               for (desc = chiplist; desc->name != NULL; desc++)
-                       printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
-               printk("\n");
-       }
-
-       chip = kzalloc(sizeof(*chip),GFP_KERNEL);
-       if (!chip)
-               return -ENOMEM;
-       chip->c = client;
-       i2c_set_clientdata(client, chip);
 
-       /* find description for the chip */
-       v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);
-       for (desc = chiplist; desc->name != NULL; desc++) {
-               if (0 == *(desc->insmodopt))
-                       continue;
-               if (client->addr < desc->addr_lo ||
-                   client->addr > desc->addr_hi)
-                       continue;
-               if (desc->checkit && !desc->checkit(chip))
-                       continue;
-               break;
-       }
-       if (desc->name == NULL) {
-               v4l_dbg(1, debug, client, "no matching chip description found\n");
-               kfree(chip);
-               return -EIO;
-       }
-       v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
-       if (desc->flags) {
-               v4l_dbg(1, debug, client, "matches:%s%s%s.\n",
-                       (desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
-                       (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
-                       (desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
-       }
-
-       /* fill required data structures */
-       if (!id)
-               strlcpy(client->name, desc->name, I2C_NAME_SIZE);
-       chip->desc = desc;
-       chip->shadow.count = desc->registers+1;
-       chip->prevmode = -1;
-       chip->audmode = V4L2_TUNER_MODE_LANG1;
-
-       /* initialization  */
-       if (desc->initialize != NULL)
-               desc->initialize(chip);
-       else
-               chip_cmd(chip,"init",&desc->init);
-
-       if (desc->flags & CHIP_HAS_VOLUME) {
-               if (!desc->volfunc) {
-                       /* This shouldn't be happen. Warn user, but keep working
-                          without volume controls
-                        */
-                       v4l_info(chip->c, "volume callback undefined!\n");
-                       desc->flags &= ~CHIP_HAS_VOLUME;
-               } else {
-                       chip->left  = desc->leftinit  ? desc->leftinit  : 65535;
-                       chip->right = desc->rightinit ? desc->rightinit : 65535;
-                       chip_write(chip, desc->leftreg,
-                                  desc->volfunc(chip->left));
-                       chip_write(chip, desc->rightreg,
-                                  desc->volfunc(chip->right));
-               }
-       }
-       if (desc->flags & CHIP_HAS_BASSTREBLE) {
-               if (!desc->bassfunc || !desc->treblefunc) {
-                       /* This shouldn't be happen. Warn user, but keep working
-                          without bass/treble controls
-                        */
-                       v4l_info(chip->c, "bass/treble callbacks undefined!\n");
-                       desc->flags &= ~CHIP_HAS_BASSTREBLE;
-               } else {
-                       chip->treble = desc->trebleinit ?
-                                               desc->trebleinit : 32768;
-                       chip->bass   = desc->bassinit   ?
-                                               desc->bassinit   : 32768;
-                       chip_write(chip, desc->bassreg,
-                                  desc->bassfunc(chip->bass));
-                       chip_write(chip, desc->treblereg,
-                                  desc->treblefunc(chip->treble));
-               }
-       }
-
-       chip->thread = NULL;
-       if (desc->flags & CHIP_NEED_CHECKMODE) {
-               if (!desc->getmode || !desc->setmode) {
-                       /* This shouldn't be happen. Warn user, but keep working
-                          without kthread
-                        */
-                       v4l_info(chip->c, "set/get mode callbacks undefined!\n");
-                       return 0;
-               }
-               /* start async thread */
-               init_timer(&chip->wt);
-               chip->wt.function = chip_thread_wake;
-               chip->wt.data     = (unsigned long)chip;
-               chip->thread = kthread_run(chip_thread, chip, chip->c->name);
-               if (IS_ERR(chip->thread)) {
-                       v4l_warn(chip->c, "%s: failed to create kthread\n",
-                              chip->c->name);
-                       chip->thread = NULL;
-               }
-       }
-       return 0;
-}
-
-static int chip_remove(struct i2c_client *client)
-{
-       struct CHIPSTATE *chip = i2c_get_clientdata(client);
-
-       del_timer_sync(&chip->wt);
-       if (chip->thread) {
-               /* shutdown async thread */
-               kthread_stop(chip->thread);
-               chip->thread = NULL;
-       }
-
-       kfree(chip);
-       return 0;
-}
-
-static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
+static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
                            struct v4l2_control *ctrl)
 {
+       struct CHIPSTATE *chip = to_state(sd);
        struct CHIPDESC *desc = chip->desc;
 
        switch (ctrl->id) {
@@ -1652,9 +1544,10 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
        return -EINVAL;
 }
 
-static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
+static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
                            struct v4l2_control *ctrl)
 {
+       struct CHIPSTATE *chip = to_state(sd);
        struct CHIPDESC *desc = chip->desc;
 
        switch (ctrl->id) {
@@ -1726,161 +1619,327 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
 /* ---------------------------------------------------------------------- */
 /* video4linux interface                                                  */
 
-static int chip_command(struct i2c_client *client,
-                       unsigned int cmd, void *arg)
+static int tvaudio_s_radio(struct v4l2_subdev *sd)
 {
-       struct CHIPSTATE *chip = i2c_get_clientdata(client);
-       struct CHIPDESC  *desc = chip->desc;
+       struct CHIPSTATE *chip = to_state(sd);
 
-       if (debug > 0) {
-               v4l_i2c_print_ioctl(chip->c, cmd);
-               printk("\n");
+       chip->radio = 1;
+       chip->watch_stereo = 0;
+       /* del_timer(&chip->wt); */
+       return 0;
+}
+
+static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       struct CHIPSTATE *chip = to_state(sd);
+       struct CHIPDESC *desc = chip->desc;
+
+       switch (qc->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               break;
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_AUDIO_BALANCE:
+               if (!(desc->flags & CHIP_HAS_VOLUME))
+                       return -EINVAL;
+               break;
+       case V4L2_CID_AUDIO_BASS:
+       case V4L2_CID_AUDIO_TREBLE:
+               if (!(desc->flags & CHIP_HAS_BASSTREBLE))
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
        }
+       return v4l2_ctrl_query_fill_std(qc);
+}
+
+static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
+{
+       struct CHIPSTATE *chip = to_state(sd);
+       struct CHIPDESC *desc = chip->desc;
 
-       switch (cmd) {
-       case AUDC_SET_RADIO:
-               chip->radio = 1;
+       if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
+               return -EINVAL;
+       /* There are four inputs: tuner, radio, extern and intern. */
+       chip->input = rt->input;
+       if (chip->muted)
+               return 0;
+       chip_write_masked(chip, desc->inputreg,
+                       desc->inputmap[chip->input], desc->inputmask);
+       return 0;
+}
+
+static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct CHIPSTATE *chip = to_state(sd);
+       struct CHIPDESC *desc = chip->desc;
+       int mode = 0;
+
+       if (chip->radio)
+               return 0;
+       switch (vt->audmode) {
+       case V4L2_TUNER_MODE_MONO:
+       case V4L2_TUNER_MODE_STEREO:
+       case V4L2_TUNER_MODE_LANG1:
+       case V4L2_TUNER_MODE_LANG2:
+               mode = vt->audmode;
+               break;
+       case V4L2_TUNER_MODE_LANG1_LANG2:
+               mode = V4L2_TUNER_MODE_STEREO;
+               break;
+       default:
+               return -EINVAL;
+       }
+       chip->audmode = vt->audmode;
+
+       if (desc->setmode && mode) {
                chip->watch_stereo = 0;
                /* del_timer(&chip->wt); */
-               break;
-       /* --- v4l ioctls --- */
-       /* take care: bttv does userspace copying, we'll get a
-       kernel pointer here... */
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-
-               switch (qc->id) {
-                       case V4L2_CID_AUDIO_MUTE:
-                               break;
-                       case V4L2_CID_AUDIO_VOLUME:
-                       case V4L2_CID_AUDIO_BALANCE:
-                               if (!(desc->flags & CHIP_HAS_VOLUME))
-                                       return -EINVAL;
-                               break;
-                       case V4L2_CID_AUDIO_BASS:
-                       case V4L2_CID_AUDIO_TREBLE:
-                               if (!(desc->flags & CHIP_HAS_BASSTREBLE))
-                                       return -EINVAL;
-                               break;
-                       default:
-                               return -EINVAL;
-               }
-               return v4l2_ctrl_query_fill_std(qc);
+               chip->mode = mode;
+               desc->setmode(chip, mode);
        }
-       case VIDIOC_S_CTRL:
-               return tvaudio_set_ctrl(chip, arg);
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-               return tvaudio_get_ctrl(chip, arg);
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-       {
-               struct v4l2_routing *rt = arg;
+static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct CHIPSTATE *chip = to_state(sd);
+       struct CHIPDESC *desc = chip->desc;
+       int mode = V4L2_TUNER_MODE_MONO;
 
-               rt->input = chip->input;
-               rt->output = 0;
-               break;
+       if (chip->radio)
+               return 0;
+       vt->audmode = chip->audmode;
+       vt->rxsubchans = 0;
+       vt->capability = V4L2_TUNER_CAP_STEREO |
+               V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+
+       if (desc->getmode)
+               mode = desc->getmode(chip);
+
+       if (mode & V4L2_TUNER_MODE_MONO)
+               vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
+       if (mode & V4L2_TUNER_MODE_STEREO)
+               vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+       /* Note: for SAP it should be mono/lang2 or stereo/lang2.
+          When this module is converted fully to v4l2, then this
+          should change for those chips that can detect SAP. */
+       if (mode & V4L2_TUNER_MODE_LANG1)
+               vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
+                       V4L2_TUNER_SUB_LANG2;
+       return 0;
+}
+
+static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct CHIPSTATE *chip = to_state(sd);
+
+       chip->radio = 0;
+       return 0;
+}
+
+static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+       struct CHIPSTATE *chip = to_state(sd);
+       struct CHIPDESC *desc = chip->desc;
+
+       chip->mode = 0; /* automatic */
+
+       /* For chips that provide getmode and setmode, and doesn't
+          automatically follows the stereo carrier, a kthread is
+          created to set the audio standard. In this case, when then
+          the video channel is changed, tvaudio starts on MONO mode.
+          After waiting for 2 seconds, the kernel thread is called,
+          to follow whatever audio standard is pointed by the
+          audio carrier.
+        */
+       if (chip->thread) {
+               desc->setmode(chip, V4L2_TUNER_MODE_MONO);
+               if (chip->prevmode != V4L2_TUNER_MODE_MONO)
+                       chip->prevmode = -1; /* reset previous mode */
+               mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
        }
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-       {
-               struct v4l2_routing *rt = arg;
+       return 0;
+}
 
-               if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
-                               return -EINVAL;
-               /* There are four inputs: tuner, radio, extern and intern. */
-               chip->input = rt->input;
-               if (chip->muted)
-                       break;
-               chip_write_masked(chip, desc->inputreg,
-                               desc->inputmap[chip->input], desc->inputmask);
-               break;
+static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVAUDIO, 0);
+}
+
+static int tvaudio_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
+       .g_chip_ident = tvaudio_g_chip_ident,
+       .queryctrl = tvaudio_queryctrl,
+       .g_ctrl = tvaudio_g_ctrl,
+       .s_ctrl = tvaudio_s_ctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = {
+       .s_radio = tvaudio_s_radio,
+       .s_frequency = tvaudio_s_frequency,
+       .s_std = tvaudio_s_std,
+       .s_tuner = tvaudio_s_tuner,
+       .s_tuner = tvaudio_g_tuner,
+};
+
+static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = {
+       .s_routing = tvaudio_s_routing,
+};
+
+static const struct v4l2_subdev_ops tvaudio_ops = {
+       .core = &tvaudio_core_ops,
+       .tuner = &tvaudio_tuner_ops,
+       .audio = &tvaudio_audio_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c registration                                                       */
+
+static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct CHIPSTATE *chip;
+       struct CHIPDESC  *desc;
+       struct v4l2_subdev *sd;
+
+       if (debug) {
+               printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+               printk(KERN_INFO "tvaudio: known chips: ");
+               for (desc = chiplist; desc->name != NULL; desc++)
+                       printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
+               printk("\n");
        }
-       case VIDIOC_S_TUNER:
-       {
-               struct v4l2_tuner *vt = arg;
-               int mode = 0;
 
-               if (chip->radio)
-                       break;
-               switch (vt->audmode) {
-               case V4L2_TUNER_MODE_MONO:
-               case V4L2_TUNER_MODE_STEREO:
-               case V4L2_TUNER_MODE_LANG1:
-               case V4L2_TUNER_MODE_LANG2:
-                       mode = vt->audmode;
-                       break;
-               case V4L2_TUNER_MODE_LANG1_LANG2:
-                       mode = V4L2_TUNER_MODE_STEREO;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               chip->audmode = vt->audmode;
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+       sd = &chip->sd;
+       v4l2_i2c_subdev_init(sd, client, &tvaudio_ops);
 
-               if (desc->setmode && mode) {
-                       chip->watch_stereo = 0;
-                       /* del_timer(&chip->wt); */
-                       chip->mode = mode;
-                       desc->setmode(chip, mode);
-               }
+       /* find description for the chip */
+       v4l2_dbg(1, debug, sd, "chip found @ 0x%x\n", client->addr<<1);
+       for (desc = chiplist; desc->name != NULL; desc++) {
+               if (0 == *(desc->insmodopt))
+                       continue;
+               if (client->addr < desc->addr_lo ||
+                   client->addr > desc->addr_hi)
+                       continue;
+               if (desc->checkit && !desc->checkit(chip))
+                       continue;
                break;
        }
-       case VIDIOC_G_TUNER:
-       {
-               struct v4l2_tuner *vt = arg;
-               int mode = V4L2_TUNER_MODE_MONO;
+       if (desc->name == NULL) {
+               v4l2_dbg(1, debug, sd, "no matching chip description found\n");
+               kfree(chip);
+               return -EIO;
+       }
+       v4l2_info(sd, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
+       if (desc->flags) {
+               v4l2_dbg(1, debug, sd, "matches:%s%s%s.\n",
+                       (desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
+                       (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
+                       (desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
+       }
 
-               if (chip->radio)
-                       break;
-               vt->audmode = chip->audmode;
-               vt->rxsubchans = 0;
-               vt->capability = V4L2_TUNER_CAP_STEREO |
-                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       /* fill required data structures */
+       if (!id)
+               strlcpy(client->name, desc->name, I2C_NAME_SIZE);
+       chip->desc = desc;
+       chip->shadow.count = desc->registers+1;
+       chip->prevmode = -1;
+       chip->audmode = V4L2_TUNER_MODE_LANG1;
 
-               if (desc->getmode)
-                       mode = desc->getmode(chip);
+       /* initialization  */
+       if (desc->initialize != NULL)
+               desc->initialize(chip);
+       else
+               chip_cmd(chip, "init", &desc->init);
 
-               if (mode & V4L2_TUNER_MODE_MONO)
-                       vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
-               if (mode & V4L2_TUNER_MODE_STEREO)
-                       vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
-               /* Note: for SAP it should be mono/lang2 or stereo/lang2.
-                  When this module is converted fully to v4l2, then this
-                  should change for those chips that can detect SAP. */
-               if (mode & V4L2_TUNER_MODE_LANG1)
-                       vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
-                                        V4L2_TUNER_SUB_LANG2;
-               break;
+       if (desc->flags & CHIP_HAS_VOLUME) {
+               if (!desc->volfunc) {
+                       /* This shouldn't be happen. Warn user, but keep working
+                          without volume controls
+                        */
+                       v4l2_info(sd, "volume callback undefined!\n");
+                       desc->flags &= ~CHIP_HAS_VOLUME;
+               } else {
+                       chip->left  = desc->leftinit  ? desc->leftinit  : 65535;
+                       chip->right = desc->rightinit ? desc->rightinit : 65535;
+                       chip_write(chip, desc->leftreg,
+                                  desc->volfunc(chip->left));
+                       chip_write(chip, desc->rightreg,
+                                  desc->volfunc(chip->right));
+               }
        }
-       case VIDIOC_S_STD:
-               chip->radio = 0;
-               break;
-       case VIDIOC_S_FREQUENCY:
-               chip->mode = 0; /* automatic */
-
-               /* For chips that provide getmode and setmode, and doesn't
-                  automatically follows the stereo carrier, a kthread is
-                  created to set the audio standard. In this case, when then
-                  the video channel is changed, tvaudio starts on MONO mode.
-                  After waiting for 2 seconds, the kernel thread is called,
-                  to follow whatever audio standard is pointed by the
-                  audio carrier.
-                */
-               if (chip->thread) {
-                       desc->setmode(chip,V4L2_TUNER_MODE_MONO);
-                       if (chip->prevmode != V4L2_TUNER_MODE_MONO)
-                               chip->prevmode = -1; /* reset previous mode */
-                       mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
+       if (desc->flags & CHIP_HAS_BASSTREBLE) {
+               if (!desc->bassfunc || !desc->treblefunc) {
+                       /* This shouldn't be happen. Warn user, but keep working
+                          without bass/treble controls
+                        */
+                       v4l2_info(sd, "bass/treble callbacks undefined!\n");
+                       desc->flags &= ~CHIP_HAS_BASSTREBLE;
+               } else {
+                       chip->treble = desc->trebleinit ?
+                                               desc->trebleinit : 32768;
+                       chip->bass   = desc->bassinit   ?
+                                               desc->bassinit   : 32768;
+                       chip_write(chip, desc->bassreg,
+                                  desc->bassfunc(chip->bass));
+                       chip_write(chip, desc->treblereg,
+                                  desc->treblefunc(chip->treble));
                }
-               break;
+       }
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0);
+       chip->thread = NULL;
+       if (desc->flags & CHIP_NEED_CHECKMODE) {
+               if (!desc->getmode || !desc->setmode) {
+                       /* This shouldn't be happen. Warn user, but keep working
+                          without kthread
+                        */
+                       v4l2_info(sd, "set/get mode callbacks undefined!\n");
+                       return 0;
+               }
+               /* start async thread */
+               init_timer(&chip->wt);
+               chip->wt.function = chip_thread_wake;
+               chip->wt.data     = (unsigned long)chip;
+               chip->thread = kthread_run(chip_thread, chip, client->name);
+               if (IS_ERR(chip->thread)) {
+                       v4l2_warn(sd, "failed to create kthread\n");
+                       chip->thread = NULL;
+               }
        }
        return 0;
 }
 
-static int chip_legacy_probe(struct i2c_adapter *adap)
+static int tvaudio_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct CHIPSTATE *chip = to_state(sd);
+
+       del_timer_sync(&chip->wt);
+       if (chip->thread) {
+               /* shutdown async thread */
+               kthread_stop(chip->thread);
+               chip->thread = NULL;
+       }
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(chip);
+       return 0;
+}
+
+static int tvaudio_legacy_probe(struct i2c_adapter *adap)
 {
        /* don't attach on saa7146 based cards,
           because dedicated drivers are used */
@@ -1894,18 +1953,18 @@ static int chip_legacy_probe(struct i2c_adapter *adap)
 /* This driver supports many devices and the idea is to let the driver
    detect which device is present. So rather than listing all supported
    devices here, we pretend to support a single, fake device type. */
-static const struct i2c_device_id chip_id[] = {
+static const struct i2c_device_id tvaudio_id[] = {
        { "tvaudio", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, chip_id);
+MODULE_DEVICE_TABLE(i2c, tvaudio_id);
 
 static struct v4l2_i2c_driver_data v4l2_i2c_data = {
        .name = "tvaudio",
        .driverid = I2C_DRIVERID_TVAUDIO,
-       .command = chip_command,
-       .probe = chip_probe,
-       .remove = chip_remove,
-       .legacy_probe = chip_legacy_probe,
-       .id_table = chip_id,
+       .command = tvaudio_command,
+       .probe = tvaudio_probe,
+       .remove = tvaudio_remove,
+       .legacy_probe = tvaudio_legacy_probe,
+       .id_table = tvaudio_id,
 };
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
new file mode 100644 (file)
index 0000000..ac9aa40
--- /dev/null
@@ -0,0 +1,1569 @@
+/*
+ * drivers/media/video/tvp514x.c
+ *
+ * TI TVP5146/47 decoder driver
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ *     Sivaraj R <sivaraj@ti.com>
+ *     Brijesh R Jadav <brijesh.j@ti.com>
+ *     Hardik Shah <hardik.shah@ti.com>
+ *     Manjunath Hadli <mrh@ti.com>
+ *     Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-int-device.h>
+#include <media/tvp514x.h>
+
+#include "tvp514x_regs.h"
+
+/* Module Name */
+#define TVP514X_MODULE_NAME            "tvp514x"
+
+/* Private macros for TVP */
+#define I2C_RETRY_COUNT                 (5)
+#define LOCK_RETRY_COUNT                (5)
+#define LOCK_RETRY_DELAY                (200)
+
+/* Debug functions */
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define dump_reg(client, reg, val)                             \
+       do {                                                    \
+               val = tvp514x_read_reg(client, reg);            \
+               v4l_info(client, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
+       } while (0)
+
+/**
+ * enum tvp514x_std - enum for supported standards
+ */
+enum tvp514x_std {
+       STD_NTSC_MJ = 0,
+       STD_PAL_BDGHIN,
+       STD_INVALID
+};
+
+/**
+ * enum tvp514x_state - enum for different decoder states
+ */
+enum tvp514x_state {
+       STATE_NOT_DETECTED,
+       STATE_DETECTED
+};
+
+/**
+ * struct tvp514x_std_info - Structure to store standard informations
+ * @width: Line width in pixels
+ * @height:Number of active lines
+ * @video_std: Value to write in REG_VIDEO_STD register
+ * @standard: v4l2 standard structure information
+ */
+struct tvp514x_std_info {
+       unsigned long width;
+       unsigned long height;
+       u8 video_std;
+       struct v4l2_standard standard;
+};
+
+/**
+ * struct tvp514x_decoded - TVP5146/47 decoder object
+ * @v4l2_int_device: Slave handle
+ * @pdata: Board specific
+ * @client: I2C client data
+ * @id: Entry from I2C table
+ * @ver: Chip version
+ * @state: TVP5146/47 decoder state - detected or not-detected
+ * @pix: Current pixel format
+ * @num_fmts: Number of formats
+ * @fmt_list: Format list
+ * @current_std: Current standard
+ * @num_stds: Number of standards
+ * @std_list: Standards list
+ * @route: input and output routing at chip level
+ */
+struct tvp514x_decoder {
+       struct v4l2_int_device *v4l2_int_device;
+       const struct tvp514x_platform_data *pdata;
+       struct i2c_client *client;
+
+       struct i2c_device_id *id;
+
+       int ver;
+       enum tvp514x_state state;
+
+       struct v4l2_pix_format pix;
+       int num_fmts;
+       const struct v4l2_fmtdesc *fmt_list;
+
+       enum tvp514x_std current_std;
+       int num_stds;
+       struct tvp514x_std_info *std_list;
+
+       struct v4l2_routing route;
+};
+
+/* TVP514x default register values */
+static struct tvp514x_reg tvp514x_reg_list[] = {
+       {TOK_WRITE, REG_INPUT_SEL, 0x05},       /* Composite selected */
+       {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
+       {TOK_WRITE, REG_VIDEO_STD, 0x00},       /* Auto mode */
+       {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+       {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F},
+       {TOK_WRITE, REG_COLOR_KILLER, 0x10},
+       {TOK_WRITE, REG_LUMA_CONTROL1, 0x00},
+       {TOK_WRITE, REG_LUMA_CONTROL2, 0x00},
+       {TOK_WRITE, REG_LUMA_CONTROL3, 0x02},
+       {TOK_WRITE, REG_BRIGHTNESS, 0x80},
+       {TOK_WRITE, REG_CONTRAST, 0x80},
+       {TOK_WRITE, REG_SATURATION, 0x80},
+       {TOK_WRITE, REG_HUE, 0x00},
+       {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00},
+       {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E},
+       {TOK_SKIP, 0x0F, 0x00}, /* Reserved */
+       {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80},
+       {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80},
+       {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80},
+       {TOK_SKIP, 0x13, 0x00}, /* Reserved */
+       {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80},
+       {TOK_SKIP, 0x15, 0x00}, /* Reserved */
+       {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55},     /* NTSC timing */
+       {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00},
+       {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25},
+       {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03},
+       {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00},    /* NTSC timing */
+       {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00},
+       {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40},
+       {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00},
+       {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04},     /* NTSC timing */
+       {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00},
+       {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07},
+       {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00},
+       {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01},      /* NTSC timing */
+       {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00},
+       {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15},
+       {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00},
+       {TOK_SKIP, 0x26, 0x00}, /* Reserved */
+       {TOK_SKIP, 0x27, 0x00}, /* Reserved */
+       {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC},
+       {TOK_SKIP, 0x29, 0x00}, /* Reserved */
+       {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00},
+       {TOK_SKIP, 0x2B, 0x00}, /* Reserved */
+       {TOK_SKIP, REG_SCART_DELAY, 0x00},
+       {TOK_SKIP, REG_CTI_DELAY, 0x00},
+       {TOK_SKIP, REG_CTI_CONTROL, 0x00},
+       {TOK_SKIP, 0x2F, 0x00}, /* Reserved */
+       {TOK_SKIP, 0x30, 0x00}, /* Reserved */
+       {TOK_SKIP, 0x31, 0x00}, /* Reserved */
+       {TOK_WRITE, REG_SYNC_CONTROL, 0x00},    /* HS, VS active high */
+       {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00},       /* 10-bit BT.656 */
+       {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11},       /* Enable clk & data */
+       {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE},       /* Enable AVID & FLD */
+       {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF},       /* Enable VS & HS */
+       {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF},
+       {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF},
+       {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, /* Clear status */
+       {TOK_TERM, 0, 0},
+};
+
+/* List of image formats supported by TVP5146/47 decoder
+ * Currently we are using 8 bit mode only, but can be
+ * extended to 10/20 bit mode.
+ */
+static const struct v4l2_fmtdesc tvp514x_fmt_list[] = {
+       {
+        .index = 0,
+        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+        .flags = 0,
+        .description = "8-bit UYVY 4:2:2 Format",
+        .pixelformat = V4L2_PIX_FMT_UYVY,
+       },
+};
+
+/*
+ * Supported standards -
+ *
+ * Currently supports two standards only, need to add support for rest of the
+ * modes, like SECAM, etc...
+ */
+static struct tvp514x_std_info tvp514x_std_list[] = {
+       /* Standard: STD_NTSC_MJ */
+       [STD_NTSC_MJ] = {
+        .width = NTSC_NUM_ACTIVE_PIXELS,
+        .height = NTSC_NUM_ACTIVE_LINES,
+        .video_std = VIDEO_STD_NTSC_MJ_BIT,
+        .standard = {
+                     .index = 0,
+                     .id = V4L2_STD_NTSC,
+                     .name = "NTSC",
+                     .frameperiod = {1001, 30000},
+                     .framelines = 525
+                    },
+       /* Standard: STD_PAL_BDGHIN */
+       },
+       [STD_PAL_BDGHIN] = {
+        .width = PAL_NUM_ACTIVE_PIXELS,
+        .height = PAL_NUM_ACTIVE_LINES,
+        .video_std = VIDEO_STD_PAL_BDGHIN_BIT,
+        .standard = {
+                     .index = 1,
+                     .id = V4L2_STD_PAL,
+                     .name = "PAL",
+                     .frameperiod = {1, 25},
+                     .framelines = 625
+                    },
+       },
+       /* Standard: need to add for additional standard */
+};
+/*
+ * Control structure for Auto Gain
+ *     This is temporary data, will get replaced once
+ *     v4l2_ctrl_query_fill supports it.
+ */
+static const struct v4l2_queryctrl tvp514x_autogain_ctrl = {
+       .id = V4L2_CID_AUTOGAIN,
+       .name = "Gain, Automatic",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .minimum = 0,
+       .maximum = 1,
+       .step = 1,
+       .default_value = 1,
+};
+
+/*
+ * Read a value from a register in an TVP5146/47 decoder device.
+ * Returns value read if successful, or non-zero (-1) otherwise.
+ */
+static int tvp514x_read_reg(struct i2c_client *client, u8 reg)
+{
+       int err;
+       int retry = 0;
+read_again:
+
+       err = i2c_smbus_read_byte_data(client, reg);
+       if (err == -1) {
+               if (retry <= I2C_RETRY_COUNT) {
+                       v4l_warn(client, "Read: retry ... %d\n", retry);
+                       retry++;
+                       msleep_interruptible(10);
+                       goto read_again;
+               }
+       }
+
+       return err;
+}
+
+/*
+ * Write a value to a register in an TVP5146/47 decoder device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+       int err;
+       int retry = 0;
+write_again:
+
+       err = i2c_smbus_write_byte_data(client, reg, val);
+       if (err) {
+               if (retry <= I2C_RETRY_COUNT) {
+                       v4l_warn(client, "Write: retry ... %d\n", retry);
+                       retry++;
+                       msleep_interruptible(10);
+                       goto write_again;
+               }
+       }
+
+       return err;
+}
+
+/*
+ * tvp514x_write_regs : Initializes a list of TVP5146/47 registers
+ *             if token is TOK_TERM, then entire write operation terminates
+ *             if token is TOK_DELAY, then a delay of 'val' msec is introduced
+ *             if token is TOK_SKIP, then the register write is skipped
+ *             if token is TOK_WRITE, then the register write is performed
+ *
+ * reglist - list of registers to be written
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_write_regs(struct i2c_client *client,
+                             const struct tvp514x_reg reglist[])
+{
+       int err;
+       const struct tvp514x_reg *next = reglist;
+
+       for (; next->token != TOK_TERM; next++) {
+               if (next->token == TOK_DELAY) {
+                       msleep(next->val);
+                       continue;
+               }
+
+               if (next->token == TOK_SKIP)
+                       continue;
+
+               err = tvp514x_write_reg(client, next->reg, (u8) next->val);
+               if (err) {
+                       v4l_err(client, "Write failed. Err[%d]\n", err);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+/*
+ * tvp514x_get_current_std:
+ * Returns the current standard detected by TVP5146/47
+ */
+static enum tvp514x_std tvp514x_get_current_std(struct tvp514x_decoder
+                                               *decoder)
+{
+       u8 std, std_status;
+
+       std = tvp514x_read_reg(decoder->client, REG_VIDEO_STD);
+       if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) {
+               /* use the standard status register */
+               std_status = tvp514x_read_reg(decoder->client,
+                               REG_VIDEO_STD_STATUS);
+       } else
+               std_status = std;       /* use the standard register itself */
+
+       switch (std_status & VIDEO_STD_MASK) {
+       case VIDEO_STD_NTSC_MJ_BIT:
+               return STD_NTSC_MJ;
+
+       case VIDEO_STD_PAL_BDGHIN_BIT:
+               return STD_PAL_BDGHIN;
+
+       default:
+               return STD_INVALID;
+       }
+
+       return STD_INVALID;
+}
+
+/*
+ * TVP5146/47 register dump function
+ */
+static void tvp514x_reg_dump(struct tvp514x_decoder *decoder)
+{
+       u8 value;
+
+       dump_reg(decoder->client, REG_INPUT_SEL, value);
+       dump_reg(decoder->client, REG_AFE_GAIN_CTRL, value);
+       dump_reg(decoder->client, REG_VIDEO_STD, value);
+       dump_reg(decoder->client, REG_OPERATION_MODE, value);
+       dump_reg(decoder->client, REG_COLOR_KILLER, value);
+       dump_reg(decoder->client, REG_LUMA_CONTROL1, value);
+       dump_reg(decoder->client, REG_LUMA_CONTROL2, value);
+       dump_reg(decoder->client, REG_LUMA_CONTROL3, value);
+       dump_reg(decoder->client, REG_BRIGHTNESS, value);
+       dump_reg(decoder->client, REG_CONTRAST, value);
+       dump_reg(decoder->client, REG_SATURATION, value);
+       dump_reg(decoder->client, REG_HUE, value);
+       dump_reg(decoder->client, REG_CHROMA_CONTROL1, value);
+       dump_reg(decoder->client, REG_CHROMA_CONTROL2, value);
+       dump_reg(decoder->client, REG_COMP_PR_SATURATION, value);
+       dump_reg(decoder->client, REG_COMP_Y_CONTRAST, value);
+       dump_reg(decoder->client, REG_COMP_PB_SATURATION, value);
+       dump_reg(decoder->client, REG_COMP_Y_BRIGHTNESS, value);
+       dump_reg(decoder->client, REG_AVID_START_PIXEL_LSB, value);
+       dump_reg(decoder->client, REG_AVID_START_PIXEL_MSB, value);
+       dump_reg(decoder->client, REG_AVID_STOP_PIXEL_LSB, value);
+       dump_reg(decoder->client, REG_AVID_STOP_PIXEL_MSB, value);
+       dump_reg(decoder->client, REG_HSYNC_START_PIXEL_LSB, value);
+       dump_reg(decoder->client, REG_HSYNC_START_PIXEL_MSB, value);
+       dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_LSB, value);
+       dump_reg(decoder->client, REG_HSYNC_STOP_PIXEL_MSB, value);
+       dump_reg(decoder->client, REG_VSYNC_START_LINE_LSB, value);
+       dump_reg(decoder->client, REG_VSYNC_START_LINE_MSB, value);
+       dump_reg(decoder->client, REG_VSYNC_STOP_LINE_LSB, value);
+       dump_reg(decoder->client, REG_VSYNC_STOP_LINE_MSB, value);
+       dump_reg(decoder->client, REG_VBLK_START_LINE_LSB, value);
+       dump_reg(decoder->client, REG_VBLK_START_LINE_MSB, value);
+       dump_reg(decoder->client, REG_VBLK_STOP_LINE_LSB, value);
+       dump_reg(decoder->client, REG_VBLK_STOP_LINE_MSB, value);
+       dump_reg(decoder->client, REG_SYNC_CONTROL, value);
+       dump_reg(decoder->client, REG_OUTPUT_FORMATTER1, value);
+       dump_reg(decoder->client, REG_OUTPUT_FORMATTER2, value);
+       dump_reg(decoder->client, REG_OUTPUT_FORMATTER3, value);
+       dump_reg(decoder->client, REG_OUTPUT_FORMATTER4, value);
+       dump_reg(decoder->client, REG_OUTPUT_FORMATTER5, value);
+       dump_reg(decoder->client, REG_OUTPUT_FORMATTER6, value);
+       dump_reg(decoder->client, REG_CLEAR_LOST_LOCK, value);
+}
+
+/*
+ * Configure the TVP5146/47 with the current register settings
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tvp514x_configure(struct tvp514x_decoder *decoder)
+{
+       int err;
+
+       /* common register initialization */
+       err =
+           tvp514x_write_regs(decoder->client, tvp514x_reg_list);
+       if (err)
+               return err;
+
+       if (debug)
+               tvp514x_reg_dump(decoder);
+
+       return 0;
+}
+
+/*
+ * Detect if an tvp514x is present, and if so which revision.
+ * A device is considered to be detected if the chip ID (LSB and MSB)
+ * registers match the expected values.
+ * Any value of the rom version register is accepted.
+ * Returns ENODEV error number if no device is detected, or zero
+ * if a device is detected.
+ */
+static int tvp514x_detect(struct tvp514x_decoder *decoder)
+{
+       u8 chip_id_msb, chip_id_lsb, rom_ver;
+
+       chip_id_msb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_MSB);
+       chip_id_lsb = tvp514x_read_reg(decoder->client, REG_CHIP_ID_LSB);
+       rom_ver = tvp514x_read_reg(decoder->client, REG_ROM_VERSION);
+
+       v4l_dbg(1, debug, decoder->client,
+                "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n",
+                chip_id_msb, chip_id_lsb, rom_ver);
+       if ((chip_id_msb != TVP514X_CHIP_ID_MSB)
+               || ((chip_id_lsb != TVP5146_CHIP_ID_LSB)
+               && (chip_id_lsb != TVP5147_CHIP_ID_LSB))) {
+               /* We didn't read the values we expected, so this must not be
+                * an TVP5146/47.
+                */
+               v4l_err(decoder->client,
+                       "chip id mismatch msb:0x%x lsb:0x%x\n",
+                       chip_id_msb, chip_id_lsb);
+               return -ENODEV;
+       }
+
+       decoder->ver = rom_ver;
+       decoder->state = STATE_DETECTED;
+
+       v4l_info(decoder->client,
+                       "%s found at 0x%x (%s)\n", decoder->client->name,
+                       decoder->client->addr << 1,
+                       decoder->client->adapter->name);
+       return 0;
+}
+
+/*
+ * Following are decoder interface functions implemented by
+ * TVP5146/47 decoder driver.
+ */
+
+/**
+ * ioctl_querystd - V4L2 decoder interface handler for VIDIOC_QUERYSTD ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @std_id: standard V4L2 std_id ioctl enum
+ *
+ * Returns the current standard detected by TVP5146/47. If no active input is
+ * detected, returns -EINVAL
+ */
+static int ioctl_querystd(struct v4l2_int_device *s, v4l2_std_id *std_id)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       enum tvp514x_std current_std;
+       enum tvp514x_input input_sel;
+       u8 sync_lock_status, lock_mask;
+
+       if (std_id == NULL)
+               return -EINVAL;
+
+       /* get the current standard */
+       current_std = tvp514x_get_current_std(decoder);
+       if (current_std == STD_INVALID)
+               return -EINVAL;
+
+       input_sel = decoder->route.input;
+
+       switch (input_sel) {
+       case INPUT_CVBS_VI1A:
+       case INPUT_CVBS_VI1B:
+       case INPUT_CVBS_VI1C:
+       case INPUT_CVBS_VI2A:
+       case INPUT_CVBS_VI2B:
+       case INPUT_CVBS_VI2C:
+       case INPUT_CVBS_VI3A:
+       case INPUT_CVBS_VI3B:
+       case INPUT_CVBS_VI3C:
+       case INPUT_CVBS_VI4A:
+               lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+                       STATUS_HORZ_SYNC_LOCK_BIT |
+                       STATUS_VIRT_SYNC_LOCK_BIT;
+               break;
+
+       case INPUT_SVIDEO_VI2A_VI1A:
+       case INPUT_SVIDEO_VI2B_VI1B:
+       case INPUT_SVIDEO_VI2C_VI1C:
+       case INPUT_SVIDEO_VI2A_VI3A:
+       case INPUT_SVIDEO_VI2B_VI3B:
+       case INPUT_SVIDEO_VI2C_VI3C:
+       case INPUT_SVIDEO_VI4A_VI1A:
+       case INPUT_SVIDEO_VI4A_VI1B:
+       case INPUT_SVIDEO_VI4A_VI1C:
+       case INPUT_SVIDEO_VI4A_VI3A:
+       case INPUT_SVIDEO_VI4A_VI3B:
+       case INPUT_SVIDEO_VI4A_VI3C:
+               lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+                       STATUS_VIRT_SYNC_LOCK_BIT;
+               break;
+               /*Need to add other interfaces*/
+       default:
+               return -EINVAL;
+       }
+       /* check whether signal is locked */
+       sync_lock_status = tvp514x_read_reg(decoder->client, REG_STATUS1);
+       if (lock_mask != (sync_lock_status & lock_mask))
+               return -EINVAL; /* No input detected */
+
+       decoder->current_std = current_std;
+       *std_id = decoder->std_list[current_std].standard.id;
+
+       v4l_dbg(1, debug, decoder->client, "Current STD: %s",
+                       decoder->std_list[current_std].standard.name);
+       return 0;
+}
+
+/**
+ * ioctl_s_std - V4L2 decoder interface handler for VIDIOC_S_STD ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @std_id: standard V4L2 v4l2_std_id ioctl enum
+ *
+ * If std_id is supported, sets the requested standard. Otherwise, returns
+ * -EINVAL
+ */
+static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int err, i;
+
+       if (std_id == NULL)
+               return -EINVAL;
+
+       for (i = 0; i < decoder->num_stds; i++)
+               if (*std_id & decoder->std_list[i].standard.id)
+                       break;
+
+       if ((i == decoder->num_stds) || (i == STD_INVALID))
+               return -EINVAL;
+
+       err = tvp514x_write_reg(decoder->client, REG_VIDEO_STD,
+                               decoder->std_list[i].video_std);
+       if (err)
+               return err;
+
+       decoder->current_std = i;
+       tvp514x_reg_list[REG_VIDEO_STD].val = decoder->std_list[i].video_std;
+
+       v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
+                       decoder->std_list[i].standard.name);
+       return 0;
+}
+
+/**
+ * ioctl_s_routing - V4L2 decoder interface handler for VIDIOC_S_INPUT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @index: number of the input
+ *
+ * If index is valid, selects the requested input. Otherwise, returns -EINVAL if
+ * the input is not supported or there is no active signal present in the
+ * selected input.
+ */
+static int ioctl_s_routing(struct v4l2_int_device *s,
+                               struct v4l2_routing *route)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int err;
+       enum tvp514x_input input_sel;
+       enum tvp514x_output output_sel;
+       enum tvp514x_std current_std = STD_INVALID;
+       u8 sync_lock_status, lock_mask;
+       int try_count = LOCK_RETRY_COUNT;
+
+       if ((!route) || (route->input >= INPUT_INVALID) ||
+                       (route->output >= OUTPUT_INVALID))
+               return -EINVAL; /* Index out of bound */
+
+       input_sel = route->input;
+       output_sel = route->output;
+
+       err = tvp514x_write_reg(decoder->client, REG_INPUT_SEL, input_sel);
+       if (err)
+               return err;
+
+       output_sel |= tvp514x_read_reg(decoder->client,
+                       REG_OUTPUT_FORMATTER1) & 0x7;
+       err = tvp514x_write_reg(decoder->client, REG_OUTPUT_FORMATTER1,
+                       output_sel);
+       if (err)
+               return err;
+
+       tvp514x_reg_list[REG_INPUT_SEL].val = input_sel;
+       tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val = output_sel;
+
+       /* Clear status */
+       msleep(LOCK_RETRY_DELAY);
+       err =
+           tvp514x_write_reg(decoder->client, REG_CLEAR_LOST_LOCK, 0x01);
+       if (err)
+               return err;
+
+       switch (input_sel) {
+       case INPUT_CVBS_VI1A:
+       case INPUT_CVBS_VI1B:
+       case INPUT_CVBS_VI1C:
+       case INPUT_CVBS_VI2A:
+       case INPUT_CVBS_VI2B:
+       case INPUT_CVBS_VI2C:
+       case INPUT_CVBS_VI3A:
+       case INPUT_CVBS_VI3B:
+       case INPUT_CVBS_VI3C:
+       case INPUT_CVBS_VI4A:
+               lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT |
+                       STATUS_HORZ_SYNC_LOCK_BIT |
+                       STATUS_VIRT_SYNC_LOCK_BIT;
+               break;
+
+       case INPUT_SVIDEO_VI2A_VI1A:
+       case INPUT_SVIDEO_VI2B_VI1B:
+       case INPUT_SVIDEO_VI2C_VI1C:
+       case INPUT_SVIDEO_VI2A_VI3A:
+       case INPUT_SVIDEO_VI2B_VI3B:
+       case INPUT_SVIDEO_VI2C_VI3C:
+       case INPUT_SVIDEO_VI4A_VI1A:
+       case INPUT_SVIDEO_VI4A_VI1B:
+       case INPUT_SVIDEO_VI4A_VI1C:
+       case INPUT_SVIDEO_VI4A_VI3A:
+       case INPUT_SVIDEO_VI4A_VI3B:
+       case INPUT_SVIDEO_VI4A_VI3C:
+               lock_mask = STATUS_HORZ_SYNC_LOCK_BIT |
+                       STATUS_VIRT_SYNC_LOCK_BIT;
+               break;
+       /*Need to add other interfaces*/
+       default:
+               return -EINVAL;
+       }
+
+       while (try_count-- > 0) {
+               /* Allow decoder to sync up with new input */
+               msleep(LOCK_RETRY_DELAY);
+
+               /* get the current standard for future reference */
+               current_std = tvp514x_get_current_std(decoder);
+               if (current_std == STD_INVALID)
+                       continue;
+
+               sync_lock_status = tvp514x_read_reg(decoder->client,
+                               REG_STATUS1);
+               if (lock_mask == (sync_lock_status & lock_mask))
+                       break;  /* Input detected */
+       }
+
+       if ((current_std == STD_INVALID) || (try_count < 0))
+               return -EINVAL;
+
+       decoder->current_std = current_std;
+       decoder->route.input = route->input;
+       decoder->route.output = route->output;
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Input set to: %d, std : %d",
+                       input_sel, current_std);
+
+       return 0;
+}
+
+/**
+ * ioctl_queryctrl - V4L2 decoder interface handler for VIDIOC_QUERYCTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qctrl: standard V4L2 v4l2_queryctrl structure
+ *
+ * If the requested control is supported, returns the control information.
+ * Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int
+ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int err = -EINVAL;
+
+       if (qctrl == NULL)
+               return err;
+
+       switch (qctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               /* Brightness supported is same as standard one (0-255),
+                * so make use of standard API provided.
+                */
+               err = v4l2_ctrl_query_fill_std(qctrl);
+               break;
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+               /* Saturation and Contrast supported is -
+                *      Contrast: 0 - 255 (Default - 128)
+                *      Saturation: 0 - 255 (Default - 128)
+                */
+               err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+               break;
+       case V4L2_CID_HUE:
+               /* Hue Supported is -
+                *      Hue - -180 - +180 (Default - 0, Step - +180)
+                */
+               err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
+               break;
+       case V4L2_CID_AUTOGAIN:
+               /* Autogain is either 0 or 1*/
+               memcpy(qctrl, &tvp514x_autogain_ctrl,
+                               sizeof(struct v4l2_queryctrl));
+               err = 0;
+               break;
+       default:
+               v4l_err(decoder->client,
+                       "invalid control id %d\n", qctrl->id);
+               return err;
+       }
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Query Control: %s : Min - %d, Max - %d, Def - %d",
+                       qctrl->name,
+                       qctrl->minimum,
+                       qctrl->maximum,
+                       qctrl->default_value);
+
+       return err;
+}
+
+/**
+ * ioctl_g_ctrl - V4L2 decoder interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the decoder. Otherwise, returns -EINVAL if the control is not
+ * supported.
+ */
+static int
+ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+
+       if (ctrl == NULL)
+               return -EINVAL;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = tvp514x_reg_list[REG_BRIGHTNESS].val;
+               break;
+       case V4L2_CID_CONTRAST:
+               ctrl->value = tvp514x_reg_list[REG_CONTRAST].val;
+               break;
+       case V4L2_CID_SATURATION:
+               ctrl->value = tvp514x_reg_list[REG_SATURATION].val;
+               break;
+       case V4L2_CID_HUE:
+               ctrl->value = tvp514x_reg_list[REG_HUE].val;
+               if (ctrl->value == 0x7F)
+                       ctrl->value = 180;
+               else if (ctrl->value == 0x80)
+                       ctrl->value = -180;
+               else
+                       ctrl->value = 0;
+
+               break;
+       case V4L2_CID_AUTOGAIN:
+               ctrl->value = tvp514x_reg_list[REG_AFE_GAIN_CTRL].val;
+               if ((ctrl->value & 0x3) == 3)
+                       ctrl->value = 1;
+               else
+                       ctrl->value = 0;
+
+               break;
+       default:
+               v4l_err(decoder->client,
+                       "invalid control id %d\n", ctrl->id);
+               return -EINVAL;
+       }
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Get Control: ID - %d - %d",
+                       ctrl->id, ctrl->value);
+       return 0;
+}
+
+/**
+ * ioctl_s_ctrl - V4L2 decoder interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @ctrl: pointer to v4l2_control structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW. Otherwise, returns -EINVAL if the control is not supported.
+ */
+static int
+ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int err = -EINVAL, value;
+
+       if (ctrl == NULL)
+               return err;
+
+       value = (__s32) ctrl->value;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (ctrl->value < 0 || ctrl->value > 255) {
+                       v4l_err(decoder->client,
+                                       "invalid brightness setting %d\n",
+                                       ctrl->value);
+                       return -ERANGE;
+               }
+               err = tvp514x_write_reg(decoder->client, REG_BRIGHTNESS,
+                               value);
+               if (err)
+                       return err;
+               tvp514x_reg_list[REG_BRIGHTNESS].val = value;
+               break;
+       case V4L2_CID_CONTRAST:
+               if (ctrl->value < 0 || ctrl->value > 255) {
+                       v4l_err(decoder->client,
+                                       "invalid contrast setting %d\n",
+                                       ctrl->value);
+                       return -ERANGE;
+               }
+               err = tvp514x_write_reg(decoder->client, REG_CONTRAST,
+                               value);
+               if (err)
+                       return err;
+               tvp514x_reg_list[REG_CONTRAST].val = value;
+               break;
+       case V4L2_CID_SATURATION:
+               if (ctrl->value < 0 || ctrl->value > 255) {
+                       v4l_err(decoder->client,
+                                       "invalid saturation setting %d\n",
+                                       ctrl->value);
+                       return -ERANGE;
+               }
+               err = tvp514x_write_reg(decoder->client, REG_SATURATION,
+                               value);
+               if (err)
+                       return err;
+               tvp514x_reg_list[REG_SATURATION].val = value;
+               break;
+       case V4L2_CID_HUE:
+               if (value == 180)
+                       value = 0x7F;
+               else if (value == -180)
+                       value = 0x80;
+               else if (value == 0)
+                       value = 0;
+               else {
+                       v4l_err(decoder->client,
+                                       "invalid hue setting %d\n",
+                                       ctrl->value);
+                       return -ERANGE;
+               }
+               err = tvp514x_write_reg(decoder->client, REG_HUE,
+                               value);
+               if (err)
+                       return err;
+               tvp514x_reg_list[REG_HUE].val = value;
+               break;
+       case V4L2_CID_AUTOGAIN:
+               if (value == 1)
+                       value = 0x0F;
+               else if (value == 0)
+                       value = 0x0C;
+               else {
+                       v4l_err(decoder->client,
+                                       "invalid auto gain setting %d\n",
+                                       ctrl->value);
+                       return -ERANGE;
+               }
+               err = tvp514x_write_reg(decoder->client, REG_AFE_GAIN_CTRL,
+                               value);
+               if (err)
+                       return err;
+               tvp514x_reg_list[REG_AFE_GAIN_CTRL].val = value;
+               break;
+       default:
+               v4l_err(decoder->client,
+                       "invalid control id %d\n", ctrl->id);
+               return err;
+       }
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Set Control: ID - %d - %d",
+                       ctrl->id, ctrl->value);
+
+       return err;
+}
+
+/**
+ * ioctl_enum_fmt_cap - Implement the CAPTURE buffer VIDIOC_ENUM_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
+ *
+ * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
+ */
+static int
+ioctl_enum_fmt_cap(struct v4l2_int_device *s, struct v4l2_fmtdesc *fmt)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int index;
+
+       if (fmt == NULL)
+               return -EINVAL;
+
+       index = fmt->index;
+       if ((index >= decoder->num_fmts) || (index < 0))
+               return -EINVAL; /* Index out of bound */
+
+       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL; /* only capture is supported */
+
+       memcpy(fmt, &decoder->fmt_list[index],
+               sizeof(struct v4l2_fmtdesc));
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Current FMT: index - %d (%s)",
+                       decoder->fmt_list[index].index,
+                       decoder->fmt_list[index].description);
+       return 0;
+}
+
+/**
+ * ioctl_try_fmt_cap - Implement the CAPTURE buffer VIDIOC_TRY_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ *
+ * 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)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int ifmt;
+       struct v4l2_pix_format *pix;
+       enum tvp514x_std current_std;
+
+       if (f == NULL)
+               return -EINVAL;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       pix = &f->fmt.pix;
+
+       /* Calculate height and width based on current standard */
+       current_std = tvp514x_get_current_std(decoder);
+       if (current_std == STD_INVALID)
+               return -EINVAL;
+
+       decoder->current_std = current_std;
+       pix->width = decoder->std_list[current_std].width;
+       pix->height = decoder->std_list[current_std].height;
+
+       for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) {
+               if (pix->pixelformat ==
+                       decoder->fmt_list[ifmt].pixelformat)
+                       break;
+       }
+       if (ifmt == decoder->num_fmts)
+               ifmt = 0;       /* None of the format matched, select default */
+       pix->pixelformat = decoder->fmt_list[ifmt].pixelformat;
+
+       pix->field = V4L2_FIELD_INTERLACED;
+       pix->bytesperline = pix->width * 2;
+       pix->sizeimage = pix->bytesperline * pix->height;
+       pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+       pix->priv = 0;
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Try FMT: pixelformat - %s, bytesperline - %d"
+                       "Width - %d, Height - %d",
+                       decoder->fmt_list[ifmt].description, pix->bytesperline,
+                       pix->width, pix->height);
+       return 0;
+}
+
+/**
+ * ioctl_s_fmt_cap - V4L2 decoder interface handler for VIDIOC_S_FMT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
+ *
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */
+static int
+ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       struct v4l2_pix_format *pix;
+       int rval;
+
+       if (f == NULL)
+               return -EINVAL;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL; /* only capture is supported */
+
+       pix = &f->fmt.pix;
+       rval = ioctl_try_fmt_cap(s, f);
+       if (rval)
+               return rval;
+
+               decoder->pix = *pix;
+
+       return rval;
+}
+
+/**
+ * ioctl_g_fmt_cap - V4L2 decoder interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the decoder's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int
+ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+
+       if (f == NULL)
+               return -EINVAL;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL; /* only capture is supported */
+
+       f->fmt.pix = decoder->pix;
+
+       v4l_dbg(1, debug, decoder->client,
+                       "Current FMT: bytesperline - %d"
+                       "Width - %d, Height - %d",
+                       decoder->pix.bytesperline,
+                       decoder->pix.width, decoder->pix.height);
+       return 0;
+}
+
+/**
+ * ioctl_g_parm - V4L2 decoder interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the decoder's video CAPTURE parameters.
+ */
+static int
+ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       struct v4l2_captureparm *cparm;
+       enum tvp514x_std current_std;
+
+       if (a == NULL)
+               return -EINVAL;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL; /* only capture is supported */
+
+       memset(a, 0, sizeof(*a));
+       a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       /* get the current standard */
+       current_std = tvp514x_get_current_std(decoder);
+       if (current_std == STD_INVALID)
+               return -EINVAL;
+
+       decoder->current_std = current_std;
+
+       cparm = &a->parm.capture;
+       cparm->capability = V4L2_CAP_TIMEPERFRAME;
+       cparm->timeperframe =
+               decoder->std_list[current_std].standard.frameperiod;
+
+       return 0;
+}
+
+/**
+ * ioctl_s_parm - V4L2 decoder interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the decoder to use the input parameters, if possible. If
+ * not possible, returns the appropriate error code.
+ */
+static int
+ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       struct v4l2_fract *timeperframe;
+       enum tvp514x_std current_std;
+
+       if (a == NULL)
+               return -EINVAL;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL; /* only capture is supported */
+
+       timeperframe = &a->parm.capture.timeperframe;
+
+       /* get the current standard */
+       current_std = tvp514x_get_current_std(decoder);
+       if (current_std == STD_INVALID)
+               return -EINVAL;
+
+       decoder->current_std = current_std;
+
+       *timeperframe =
+           decoder->std_list[current_std].standard.frameperiod;
+
+       return 0;
+}
+
+/**
+ * ioctl_g_ifparm - V4L2 decoder interface handler for vidioc_int_g_ifparm_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
+ *
+ * Gets slave interface parameters.
+ * Calculates the required xclk value to support the requested
+ * clock parameters in p. This value is returned in the p
+ * parameter.
+ */
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int rval;
+
+       if (p == NULL)
+               return -EINVAL;
+
+       if (NULL == decoder->pdata->ifparm)
+               return -EINVAL;
+
+       rval = decoder->pdata->ifparm(p);
+       if (rval) {
+               v4l_err(decoder->client, "g_ifparm.Err[%d]\n", rval);
+               return rval;
+       }
+
+       p->u.bt656.clock_curr = TVP514X_XCLK_BT656;
+
+       return 0;
+}
+
+/**
+ * ioctl_g_priv - V4L2 decoder interface handler for vidioc_int_g_priv_num
+ * @s: pointer to standard V4L2 device structure
+ * @p: void pointer to hold decoder's private data address
+ *
+ * Returns device's (decoder's) private data area address in p parameter
+ */
+static int ioctl_g_priv(struct v4l2_int_device *s, void *p)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+
+       if (NULL == decoder->pdata->priv_data_set)
+               return -EINVAL;
+
+       return decoder->pdata->priv_data_set(p);
+}
+
+/**
+ * ioctl_s_power - V4L2 decoder interface handler for vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int err = 0;
+
+       switch (on) {
+       case V4L2_POWER_OFF:
+               /* Power Down Sequence */
+               err =
+                   tvp514x_write_reg(decoder->client, REG_OPERATION_MODE,
+                                       0x01);
+               /* Disable mux for TVP5146/47 decoder data path */
+               if (decoder->pdata->power_set)
+                       err |= decoder->pdata->power_set(on);
+               decoder->state = STATE_NOT_DETECTED;
+               break;
+
+       case V4L2_POWER_STANDBY:
+               if (decoder->pdata->power_set)
+                       err = decoder->pdata->power_set(on);
+               break;
+
+       case V4L2_POWER_ON:
+               /* Enable mux for TVP5146/47 decoder data path */
+               if ((decoder->pdata->power_set) &&
+                               (decoder->state == STATE_NOT_DETECTED)) {
+                       int i;
+                       struct tvp514x_init_seq *int_seq =
+                               (struct tvp514x_init_seq *)
+                               decoder->id->driver_data;
+
+                       err = decoder->pdata->power_set(on);
+
+                       /* Power Up Sequence */
+                       for (i = 0; i < int_seq->no_regs; i++) {
+                               err |= tvp514x_write_reg(decoder->client,
+                                               int_seq->init_reg_seq[i].reg,
+                                               int_seq->init_reg_seq[i].val);
+                       }
+                       /* Detect the sensor is not already detected */
+                       err |= tvp514x_detect(decoder);
+                       if (err) {
+                               v4l_err(decoder->client,
+                                               "Unable to detect decoder\n");
+                               return err;
+                       }
+               }
+               err |= tvp514x_configure(decoder);
+               break;
+
+       default:
+               err = -ENODEV;
+               break;
+       }
+
+       return err;
+}
+
+/**
+ * ioctl_init - V4L2 decoder interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialize the decoder device (calls tvp514x_configure())
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+
+       /* Set default standard to auto */
+       tvp514x_reg_list[REG_VIDEO_STD].val =
+           VIDEO_STD_AUTO_SWITCH_BIT;
+
+       return tvp514x_configure(decoder);
+}
+
+/**
+ * ioctl_dev_exit - V4L2 decoder interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the dev. at slave detach. The complement of ioctl_dev_init.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+       return 0;
+}
+
+/**
+ * ioctl_dev_init - V4L2 decoder interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master. Returns 0 if
+ * TVP5146/47 device could be found, otherwise returns appropriate error.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+       struct tvp514x_decoder *decoder = s->priv;
+       int err;
+
+       err = tvp514x_detect(decoder);
+       if (err < 0) {
+               v4l_err(decoder->client,
+                       "Unable to detect decoder\n");
+               return err;
+       }
+
+       v4l_info(decoder->client,
+                "chip version 0x%.2x detected\n", decoder->ver);
+
+       return 0;
+}
+
+static struct v4l2_int_ioctl_desc tvp514x_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_priv_num, (v4l2_int_ioctl_func*) ioctl_g_priv},
+       {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},
+       {vidioc_int_querystd_num, (v4l2_int_ioctl_func *) ioctl_querystd},
+       {vidioc_int_s_std_num, (v4l2_int_ioctl_func *) ioctl_s_std},
+       {vidioc_int_s_video_routing_num,
+               (v4l2_int_ioctl_func *) ioctl_s_routing},
+};
+
+static struct v4l2_int_slave tvp514x_slave = {
+       .ioctls = tvp514x_ioctl_desc,
+       .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
+};
+
+static struct tvp514x_decoder tvp514x_dev = {
+       .state = STATE_NOT_DETECTED,
+
+       .fmt_list = tvp514x_fmt_list,
+       .num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
+
+       .pix = {                /* Default to NTSC 8-bit YUV 422 */
+               .width = NTSC_NUM_ACTIVE_PIXELS,
+               .height = NTSC_NUM_ACTIVE_LINES,
+               .pixelformat = V4L2_PIX_FMT_UYVY,
+               .field = V4L2_FIELD_INTERLACED,
+               .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2,
+               .sizeimage =
+               NTSC_NUM_ACTIVE_PIXELS * 2 * NTSC_NUM_ACTIVE_LINES,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
+               },
+
+       .current_std = STD_NTSC_MJ,
+       .std_list = tvp514x_std_list,
+       .num_stds = ARRAY_SIZE(tvp514x_std_list),
+
+};
+
+static struct v4l2_int_device tvp514x_int_device = {
+       .module = THIS_MODULE,
+       .name = TVP514X_MODULE_NAME,
+       .priv = &tvp514x_dev,
+       .type = v4l2_int_type_slave,
+       .u = {
+             .slave = &tvp514x_slave,
+             },
+};
+
+/**
+ * tvp514x_probe - decoder driver i2c probe handler
+ * @client: i2c driver client device structure
+ *
+ * Register decoder as an i2c client device and V4L2
+ * device.
+ */
+static int
+tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct tvp514x_decoder *decoder = &tvp514x_dev;
+       int err;
+
+       /* Check if the adapter supports the needed features */
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EIO;
+
+       decoder->pdata = client->dev.platform_data;
+       if (!decoder->pdata) {
+               v4l_err(client, "No platform data\n!!");
+               return -ENODEV;
+       }
+       /*
+        * Fetch platform specific data, and configure the
+        * tvp514x_reg_list[] accordingly. Since this is one
+        * time configuration, no need to preserve.
+        */
+       tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |=
+                       (decoder->pdata->clk_polarity << 1);
+       tvp514x_reg_list[REG_SYNC_CONTROL].val |=
+                       ((decoder->pdata->hs_polarity << 2) |
+                       (decoder->pdata->vs_polarity << 3));
+       /*
+        * Save the id data, required for power up sequence
+        */
+       decoder->id = (struct i2c_device_id *)id;
+       /* Attach to Master */
+       strcpy(tvp514x_int_device.u.slave->attach_to, decoder->pdata->master);
+       decoder->v4l2_int_device = &tvp514x_int_device;
+       decoder->client = client;
+       i2c_set_clientdata(client, decoder);
+
+       /* Register with V4L2 layer as slave device */
+       err = v4l2_int_device_register(decoder->v4l2_int_device);
+       if (err) {
+               i2c_set_clientdata(client, NULL);
+               v4l_err(client,
+                       "Unable to register to v4l2. Err[%d]\n", err);
+
+       } else
+               v4l_info(client, "Registered to v4l2 master %s!!\n",
+                               decoder->pdata->master);
+
+       return 0;
+}
+
+/**
+ * tvp514x_remove - decoder driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister decoder as an i2c client device and V4L2
+ * device. Complement of tvp514x_probe().
+ */
+static int __exit tvp514x_remove(struct i2c_client *client)
+{
+       struct tvp514x_decoder *decoder = i2c_get_clientdata(client);
+
+       if (!client->adapter)
+               return -ENODEV; /* our client isn't attached */
+
+       v4l2_int_device_unregister(decoder->v4l2_int_device);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+/*
+ * TVP5146 Init/Power on Sequence
+ */
+static const struct tvp514x_reg tvp5146_init_reg_seq[] = {
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+       {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+       {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static const struct tvp514x_init_seq tvp5146_init = {
+       .no_regs = ARRAY_SIZE(tvp5146_init_reg_seq),
+       .init_reg_seq = tvp5146_init_reg_seq,
+};
+/*
+ * TVP5147 Init/Power on Sequence
+ */
+static const struct tvp514x_reg tvp5147_init_reg_seq[] =       {
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00},
+       {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0},
+       {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00},
+       {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+       {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static const struct tvp514x_init_seq tvp5147_init = {
+       .no_regs = ARRAY_SIZE(tvp5147_init_reg_seq),
+       .init_reg_seq = tvp5147_init_reg_seq,
+};
+/*
+ * TVP5146M2/TVP5147M1 Init/Power on Sequence
+ */
+static const struct tvp514x_reg tvp514xm_init_reg_seq[] = {
+       {TOK_WRITE, REG_OPERATION_MODE, 0x01},
+       {TOK_WRITE, REG_OPERATION_MODE, 0x00},
+};
+static const struct tvp514x_init_seq tvp514xm_init = {
+       .no_regs = ARRAY_SIZE(tvp514xm_init_reg_seq),
+       .init_reg_seq = tvp514xm_init_reg_seq,
+};
+/*
+ * I2C Device Table -
+ *
+ * name - Name of the actual device/chip.
+ * driver_data - Driver data
+ */
+static const struct i2c_device_id tvp514x_id[] = {
+       {"tvp5146", (unsigned long)&tvp5146_init},
+       {"tvp5146m2", (unsigned long)&tvp514xm_init},
+       {"tvp5147", (unsigned long)&tvp5147_init},
+       {"tvp5147m1", (unsigned long)&tvp514xm_init},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, tvp514x_id);
+
+static struct i2c_driver tvp514x_i2c_driver = {
+       .driver = {
+                  .name = TVP514X_MODULE_NAME,
+                  .owner = THIS_MODULE,
+                  },
+       .probe = tvp514x_probe,
+       .remove = __exit_p(tvp514x_remove),
+       .id_table = tvp514x_id,
+};
+
+/**
+ * tvp514x_init
+ *
+ * Module init function
+ */
+static int __init tvp514x_init(void)
+{
+       return i2c_add_driver(&tvp514x_i2c_driver);
+}
+
+/**
+ * tvp514x_cleanup
+ *
+ * Module exit function
+ */
+static void __exit tvp514x_cleanup(void)
+{
+       i2c_del_driver(&tvp514x_i2c_driver);
+}
+
+module_init(tvp514x_init);
+module_exit(tvp514x_cleanup);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TVP514X linux decoder driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tvp514x_regs.h b/drivers/media/video/tvp514x_regs.h
new file mode 100644 (file)
index 0000000..351620a
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * drivers/media/video/tvp514x_regs.h
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ *     Sivaraj R <sivaraj@ti.com>
+ *     Brijesh R Jadav <brijesh.j@ti.com>
+ *     Hardik Shah <hardik.shah@ti.com>
+ *     Manjunath Hadli <mrh@ti.com>
+ *     Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _TVP514X_REGS_H
+#define _TVP514X_REGS_H
+
+/*
+ * TVP5146/47 registers
+ */
+#define REG_INPUT_SEL                  (0x00)
+#define REG_AFE_GAIN_CTRL              (0x01)
+#define REG_VIDEO_STD                  (0x02)
+#define REG_OPERATION_MODE             (0x03)
+#define REG_AUTOSWITCH_MASK            (0x04)
+
+#define REG_COLOR_KILLER               (0x05)
+#define REG_LUMA_CONTROL1              (0x06)
+#define REG_LUMA_CONTROL2              (0x07)
+#define REG_LUMA_CONTROL3              (0x08)
+
+#define REG_BRIGHTNESS                 (0x09)
+#define REG_CONTRAST                   (0x0A)
+#define REG_SATURATION                 (0x0B)
+#define REG_HUE                                (0x0C)
+
+#define REG_CHROMA_CONTROL1            (0x0D)
+#define REG_CHROMA_CONTROL2            (0x0E)
+
+/* 0x0F Reserved */
+
+#define REG_COMP_PR_SATURATION         (0x10)
+#define REG_COMP_Y_CONTRAST            (0x11)
+#define REG_COMP_PB_SATURATION         (0x12)
+
+/* 0x13 Reserved */
+
+#define REG_COMP_Y_BRIGHTNESS          (0x14)
+
+/* 0x15 Reserved */
+
+#define REG_AVID_START_PIXEL_LSB       (0x16)
+#define REG_AVID_START_PIXEL_MSB       (0x17)
+#define REG_AVID_STOP_PIXEL_LSB                (0x18)
+#define REG_AVID_STOP_PIXEL_MSB                (0x19)
+
+#define REG_HSYNC_START_PIXEL_LSB      (0x1A)
+#define REG_HSYNC_START_PIXEL_MSB      (0x1B)
+#define REG_HSYNC_STOP_PIXEL_LSB       (0x1C)
+#define REG_HSYNC_STOP_PIXEL_MSB       (0x1D)
+
+#define REG_VSYNC_START_LINE_LSB       (0x1E)
+#define REG_VSYNC_START_LINE_MSB       (0x1F)
+#define REG_VSYNC_STOP_LINE_LSB                (0x20)
+#define REG_VSYNC_STOP_LINE_MSB                (0x21)
+
+#define REG_VBLK_START_LINE_LSB                (0x22)
+#define REG_VBLK_START_LINE_MSB                (0x23)
+#define REG_VBLK_STOP_LINE_LSB         (0x24)
+#define REG_VBLK_STOP_LINE_MSB         (0x25)
+
+/* 0x26 - 0x27 Reserved */
+
+#define REG_FAST_SWTICH_CONTROL                (0x28)
+
+/* 0x29 Reserved */
+
+#define REG_FAST_SWTICH_SCART_DELAY    (0x2A)
+
+/* 0x2B Reserved */
+
+#define REG_SCART_DELAY                        (0x2C)
+#define REG_CTI_DELAY                  (0x2D)
+#define REG_CTI_CONTROL                        (0x2E)
+
+/* 0x2F - 0x31 Reserved */
+
+#define REG_SYNC_CONTROL               (0x32)
+#define REG_OUTPUT_FORMATTER1          (0x33)
+#define REG_OUTPUT_FORMATTER2          (0x34)
+#define REG_OUTPUT_FORMATTER3          (0x35)
+#define REG_OUTPUT_FORMATTER4          (0x36)
+#define REG_OUTPUT_FORMATTER5          (0x37)
+#define REG_OUTPUT_FORMATTER6          (0x38)
+#define REG_CLEAR_LOST_LOCK            (0x39)
+
+#define REG_STATUS1                    (0x3A)
+#define REG_STATUS2                    (0x3B)
+
+#define REG_AGC_GAIN_STATUS_LSB                (0x3C)
+#define REG_AGC_GAIN_STATUS_MSB                (0x3D)
+
+/* 0x3E Reserved */
+
+#define REG_VIDEO_STD_STATUS           (0x3F)
+#define REG_GPIO_INPUT1                        (0x40)
+#define REG_GPIO_INPUT2                        (0x41)
+
+/* 0x42 - 0x45 Reserved */
+
+#define REG_AFE_COARSE_GAIN_CH1                (0x46)
+#define REG_AFE_COARSE_GAIN_CH2                (0x47)
+#define REG_AFE_COARSE_GAIN_CH3                (0x48)
+#define REG_AFE_COARSE_GAIN_CH4                (0x49)
+
+#define REG_AFE_FINE_GAIN_PB_B_LSB     (0x4A)
+#define REG_AFE_FINE_GAIN_PB_B_MSB     (0x4B)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_LSB       (0x4C)
+#define REG_AFE_FINE_GAIN_Y_G_CHROMA_MSB       (0x4D)
+#define REG_AFE_FINE_GAIN_PR_R_LSB     (0x4E)
+#define REG_AFE_FINE_GAIN_PR_R_MSB     (0x4F)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_LSB        (0x50)
+#define REG_AFE_FINE_GAIN_CVBS_LUMA_MSB        (0x51)
+
+/* 0x52 - 0x68 Reserved */
+
+#define REG_FBIT_VBIT_CONTROL1         (0x69)
+
+/* 0x6A - 0x6B Reserved */
+
+#define REG_BACKEND_AGC_CONTROL                (0x6C)
+
+/* 0x6D - 0x6E Reserved */
+
+#define REG_AGC_DECREMENT_SPEED_CONTROL        (0x6F)
+#define REG_ROM_VERSION                        (0x70)
+
+/* 0x71 - 0x73 Reserved */
+
+#define REG_AGC_WHITE_PEAK_PROCESSING  (0x74)
+#define REG_FBIT_VBIT_CONTROL2         (0x75)
+#define REG_VCR_TRICK_MODE_CONTROL     (0x76)
+#define REG_HORIZONTAL_SHAKE_INCREMENT (0x77)
+#define REG_AGC_INCREMENT_SPEED                (0x78)
+#define REG_AGC_INCREMENT_DELAY                (0x79)
+
+/* 0x7A - 0x7F Reserved */
+
+#define REG_CHIP_ID_MSB                        (0x80)
+#define REG_CHIP_ID_LSB                        (0x81)
+
+/* 0x82 Reserved */
+
+#define REG_CPLL_SPEED_CONTROL         (0x83)
+
+/* 0x84 - 0x96 Reserved */
+
+#define REG_STATUS_REQUEST             (0x97)
+
+/* 0x98 - 0x99 Reserved */
+
+#define REG_VERTICAL_LINE_COUNT_LSB    (0x9A)
+#define REG_VERTICAL_LINE_COUNT_MSB    (0x9B)
+
+/* 0x9C - 0x9D Reserved */
+
+#define REG_AGC_DECREMENT_DELAY                (0x9E)
+
+/* 0x9F - 0xB0 Reserved */
+
+#define REG_VDP_TTX_FILTER_1_MASK1     (0xB1)
+#define REG_VDP_TTX_FILTER_1_MASK2     (0xB2)
+#define REG_VDP_TTX_FILTER_1_MASK3     (0xB3)
+#define REG_VDP_TTX_FILTER_1_MASK4     (0xB4)
+#define REG_VDP_TTX_FILTER_1_MASK5     (0xB5)
+#define REG_VDP_TTX_FILTER_2_MASK1     (0xB6)
+#define REG_VDP_TTX_FILTER_2_MASK2     (0xB7)
+#define REG_VDP_TTX_FILTER_2_MASK3     (0xB8)
+#define REG_VDP_TTX_FILTER_2_MASK4     (0xB9)
+#define REG_VDP_TTX_FILTER_2_MASK5     (0xBA)
+#define REG_VDP_TTX_FILTER_CONTROL     (0xBB)
+#define REG_VDP_FIFO_WORD_COUNT                (0xBC)
+#define REG_VDP_FIFO_INTERRUPT_THRLD   (0xBD)
+
+/* 0xBE Reserved */
+
+#define REG_VDP_FIFO_RESET             (0xBF)
+#define REG_VDP_FIFO_OUTPUT_CONTROL    (0xC0)
+#define REG_VDP_LINE_NUMBER_INTERRUPT  (0xC1)
+#define REG_VDP_PIXEL_ALIGNMENT_LSB    (0xC2)
+#define REG_VDP_PIXEL_ALIGNMENT_MSB    (0xC3)
+
+/* 0xC4 - 0xD5 Reserved */
+
+#define REG_VDP_LINE_START             (0xD6)
+#define REG_VDP_LINE_STOP              (0xD7)
+#define REG_VDP_GLOBAL_LINE_MODE       (0xD8)
+#define REG_VDP_FULL_FIELD_ENABLE      (0xD9)
+#define REG_VDP_FULL_FIELD_MODE                (0xDA)
+
+/* 0xDB - 0xDF Reserved */
+
+#define REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR (0xE0)
+#define REG_VBUS_DATA_ACCESS_VBUS_ADDR_INCR    (0xE1)
+#define REG_FIFO_READ_DATA                     (0xE2)
+
+/* 0xE3 - 0xE7 Reserved */
+
+#define REG_VBUS_ADDRESS_ACCESS1       (0xE8)
+#define REG_VBUS_ADDRESS_ACCESS2       (0xE9)
+#define REG_VBUS_ADDRESS_ACCESS3       (0xEA)
+
+/* 0xEB - 0xEF Reserved */
+
+#define REG_INTERRUPT_RAW_STATUS0      (0xF0)
+#define REG_INTERRUPT_RAW_STATUS1      (0xF1)
+#define REG_INTERRUPT_STATUS0          (0xF2)
+#define REG_INTERRUPT_STATUS1          (0xF3)
+#define REG_INTERRUPT_MASK0            (0xF4)
+#define REG_INTERRUPT_MASK1            (0xF5)
+#define REG_INTERRUPT_CLEAR0           (0xF6)
+#define REG_INTERRUPT_CLEAR1           (0xF7)
+
+/* 0xF8 - 0xFF Reserved */
+
+/*
+ * Mask and bit definitions of TVP5146/47 registers
+ */
+/* The ID values we are looking for */
+#define TVP514X_CHIP_ID_MSB            (0x51)
+#define TVP5146_CHIP_ID_LSB            (0x46)
+#define TVP5147_CHIP_ID_LSB            (0x47)
+
+#define VIDEO_STD_MASK                 (0x07)
+#define VIDEO_STD_AUTO_SWITCH_BIT      (0x00)
+#define VIDEO_STD_NTSC_MJ_BIT          (0x01)
+#define VIDEO_STD_PAL_BDGHIN_BIT       (0x02)
+#define VIDEO_STD_PAL_M_BIT            (0x03)
+#define VIDEO_STD_PAL_COMBINATION_N_BIT        (0x04)
+#define VIDEO_STD_NTSC_4_43_BIT                (0x05)
+#define VIDEO_STD_SECAM_BIT            (0x06)
+#define VIDEO_STD_PAL_60_BIT           (0x07)
+
+/*
+ * Status bit
+ */
+#define STATUS_TV_VCR_BIT              (1<<0)
+#define STATUS_HORZ_SYNC_LOCK_BIT      (1<<1)
+#define STATUS_VIRT_SYNC_LOCK_BIT      (1<<2)
+#define STATUS_CLR_SUBCAR_LOCK_BIT     (1<<3)
+#define STATUS_LOST_LOCK_DETECT_BIT    (1<<4)
+#define STATUS_FEILD_RATE_BIT          (1<<5)
+#define STATUS_LINE_ALTERNATING_BIT    (1<<6)
+#define STATUS_PEAK_WHITE_DETECT_BIT   (1<<7)
+
+/* Tokens for register write */
+#define TOK_WRITE                       (0)     /* token for write operation */
+#define TOK_TERM                        (1)     /* terminating token */
+#define TOK_DELAY                       (2)     /* delay token for reg list */
+#define TOK_SKIP                        (3)     /* token to skip a register */
+/**
+ * struct tvp514x_reg - Structure for TVP5146/47 register initialization values
+ * @token - Token: TOK_WRITE, TOK_TERM etc..
+ * @reg - Register offset
+ * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY
+ */
+struct tvp514x_reg {
+       u8 token;
+       u8 reg;
+       u32 val;
+};
+
+/**
+ * struct tvp514x_init_seq - Structure for TVP5146/47/46M2/47M1 power up
+ *             Sequence.
+ * @ no_regs - Number of registers to write for power up sequence.
+ * @ init_reg_seq - Array of registers and respective value to write.
+ */
+struct tvp514x_init_seq {
+       unsigned int no_regs;
+       const struct tvp514x_reg *init_reg_seq;
+};
+#endif                         /* ifndef _TVP514X_REGS_H */
index 28af5ce5560d793305ccddb4ea75d3fc0f02840f..a388a9f0cb187d380f5286bef7838875b801beb9 100644 (file)
@@ -9,8 +9,10 @@
 #include <linux/videodev2.h>
 #include <linux/delay.h>
 #include <linux/video_decoder.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/tvp5150.h>
+#include <media/v4l2-i2c-drv-legacy.h>
+#include <media/v4l2-chip-ident.h>
 
 #include "tvp5150_reg.h"
 
@@ -29,21 +31,7 @@ I2C_CLIENT_INSMOD;
 
 static int debug;
 module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
-
-#define tvp5150_err(fmt, arg...) do { \
-       printk(KERN_ERR "%s %d-%04x: " fmt, c->driver->driver.name, \
-              i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
-#define tvp5150_info(fmt, arg...) do { \
-       printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \
-              i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0)
-#define tvp5150_dbg(num, fmt, arg...) \
-       do { \
-               if (debug >= num) \
-                       printk(KERN_DEBUG "%s debug %d-%04x: " fmt,\
-                               c->driver->driver.name, \
-                               i2c_adapter_id(c->adapter), \
-                               c->addr , ## arg); } while (0)
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
 /* supported controls */
 static struct v4l2_queryctrl tvp5150_qctrl[] = {
@@ -87,7 +75,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
 };
 
 struct tvp5150 {
-       struct i2c_client *client;
+       struct v4l2_subdev sd;
 
        v4l2_std_id norm;       /* Current set standard */
        struct v4l2_routing route;
@@ -98,49 +86,57 @@ struct tvp5150 {
        int sat;
 };
 
-static int tvp5150_read(struct i2c_client *c, unsigned char addr)
+static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
 {
+       return container_of(sd, struct tvp5150, sd);
+}
+
+static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
        unsigned char buffer[1];
        int rc;
 
        buffer[0] = addr;
        if (1 != (rc = i2c_master_send(c, buffer, 1)))
-               tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+               v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
 
        msleep(10);
 
        if (1 != (rc = i2c_master_recv(c, buffer, 1)))
-               tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 1)\n", rc);
+               v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
 
-       tvp5150_dbg(2, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
+       v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
 
        return (buffer[0]);
 }
 
-static inline void tvp5150_write(struct i2c_client *c, unsigned char addr,
+static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
                                 unsigned char value)
 {
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
        unsigned char buffer[2];
        int rc;
 
        buffer[0] = addr;
        buffer[1] = value;
-       tvp5150_dbg(2, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+       v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
        if (2 != (rc = i2c_master_send(c, buffer, 2)))
-               tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc);
+               v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
 }
 
-static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,int max_line)
+static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
+                               const u8 end, int max_line)
 {
-       int i=0;
+       int i = 0;
 
-       while (init!=(u8)(end+1)) {
-               if ((i%max_line) == 0) {
-                       if (i>0)
+       while (init != (u8)(end + 1)) {
+               if ((i % max_line) == 0) {
+                       if (i > 0)
                                printk("\n");
-                       printk("tvp5150: %s reg 0x%02x = ",s,init);
+                       printk("tvp5150: %s reg 0x%02x = ", s, init);
                }
-               printk("%02x ",tvp5150_read(c, init));
+               printk("%02x ", tvp5150_read(sd, init));
 
                init++;
                i++;
@@ -148,147 +144,148 @@ static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,
        printk("\n");
 }
 
-static void dump_reg(struct i2c_client *c)
+static int tvp5150_log_status(struct v4l2_subdev *sd)
 {
        printk("tvp5150: Video input source selection #1 = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1));
+                       tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1));
        printk("tvp5150: Analog channel controls = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_ANAL_CHL_CTL));
+                       tvp5150_read(sd, TVP5150_ANAL_CHL_CTL));
        printk("tvp5150: Operation mode controls = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_OP_MODE_CTL));
+                       tvp5150_read(sd, TVP5150_OP_MODE_CTL));
        printk("tvp5150: Miscellaneous controls = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_MISC_CTL));
+                       tvp5150_read(sd, TVP5150_MISC_CTL));
        printk("tvp5150: Autoswitch mask= 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_AUTOSW_MSK));
+                       tvp5150_read(sd, TVP5150_AUTOSW_MSK));
        printk("tvp5150: Color killer threshold control = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL));
+                       tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL));
        printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n",
-                                       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1),
-                                       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2),
-                                       tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3));
+                       tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1),
+                       tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2),
+                       tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3));
        printk("tvp5150: Brightness control = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_BRIGHT_CTL));
+                       tvp5150_read(sd, TVP5150_BRIGHT_CTL));
        printk("tvp5150: Color saturation control = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_SATURATION_CTL));
+                       tvp5150_read(sd, TVP5150_SATURATION_CTL));
        printk("tvp5150: Hue control = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_HUE_CTL));
+                       tvp5150_read(sd, TVP5150_HUE_CTL));
        printk("tvp5150: Contrast control = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_CONTRAST_CTL));
+                       tvp5150_read(sd, TVP5150_CONTRAST_CTL));
        printk("tvp5150: Outputs and data rates select = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_DATA_RATE_SEL));
+                       tvp5150_read(sd, TVP5150_DATA_RATE_SEL));
        printk("tvp5150: Configuration shared pins = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_CONF_SHARED_PIN));
+                       tvp5150_read(sd, TVP5150_CONF_SHARED_PIN));
        printk("tvp5150: Active video cropping start = 0x%02x%02x\n",
-                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB),
-                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB));
+                       tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB),
+                       tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB));
        printk("tvp5150: Active video cropping stop  = 0x%02x%02x\n",
-                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB),
-                                       tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB));
+                       tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB),
+                       tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB));
        printk("tvp5150: Genlock/RTC = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_GENLOCK));
+                       tvp5150_read(sd, TVP5150_GENLOCK));
        printk("tvp5150: Horizontal sync start = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_HORIZ_SYNC_START));
+                       tvp5150_read(sd, TVP5150_HORIZ_SYNC_START));
        printk("tvp5150: Vertical blanking start = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_VERT_BLANKING_START));
+                       tvp5150_read(sd, TVP5150_VERT_BLANKING_START));
        printk("tvp5150: Vertical blanking stop = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_VERT_BLANKING_STOP));
+                       tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP));
        printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n",
-                                       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1),
-                                       tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2));
+                       tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1),
+                       tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2));
        printk("tvp5150: Interrupt reset register B = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_RESET_REG_B));
+                       tvp5150_read(sd, TVP5150_INT_RESET_REG_B));
        printk("tvp5150: Interrupt enable register B = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_ENABLE_REG_B));
+                       tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B));
        printk("tvp5150: Interrupt configuration register B = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B));
+                       tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B));
        printk("tvp5150: Video standard = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_VIDEO_STD));
+                       tvp5150_read(sd, TVP5150_VIDEO_STD));
        printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n",
-                                       tvp5150_read(c, TVP5150_CB_GAIN_FACT),
-                                       tvp5150_read(c, TVP5150_CR_GAIN_FACTOR));
+                       tvp5150_read(sd, TVP5150_CB_GAIN_FACT),
+                       tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR));
        printk("tvp5150: Macrovision on counter = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_MACROVISION_ON_CTR));
+                       tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR));
        printk("tvp5150: Macrovision off counter = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR));
+                       tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR));
        printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n",
-                                       (tvp5150_read(c, TVP5150_REV_SELECT)&1)?3:4);
+                       (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4);
        printk("tvp5150: Device ID = %02x%02x\n",
-                                       tvp5150_read(c, TVP5150_MSB_DEV_ID),
-                                       tvp5150_read(c, TVP5150_LSB_DEV_ID));
+                       tvp5150_read(sd, TVP5150_MSB_DEV_ID),
+                       tvp5150_read(sd, TVP5150_LSB_DEV_ID));
        printk("tvp5150: ROM version = (hex) %02x.%02x\n",
-                                       tvp5150_read(c, TVP5150_ROM_MAJOR_VER),
-                                       tvp5150_read(c, TVP5150_ROM_MINOR_VER));
+                       tvp5150_read(sd, TVP5150_ROM_MAJOR_VER),
+                       tvp5150_read(sd, TVP5150_ROM_MINOR_VER));
        printk("tvp5150: Vertical line count = 0x%02x%02x\n",
-                                       tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB),
-                                       tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB));
+                       tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB),
+                       tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB));
        printk("tvp5150: Interrupt status register B = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_STATUS_REG_B));
+                       tvp5150_read(sd, TVP5150_INT_STATUS_REG_B));
        printk("tvp5150: Interrupt active register B = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B));
+                       tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B));
        printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n",
-                                       tvp5150_read(c, TVP5150_STATUS_REG_1),
-                                       tvp5150_read(c, TVP5150_STATUS_REG_2),
-                                       tvp5150_read(c, TVP5150_STATUS_REG_3),
-                                       tvp5150_read(c, TVP5150_STATUS_REG_4),
-                                       tvp5150_read(c, TVP5150_STATUS_REG_5));
+                       tvp5150_read(sd, TVP5150_STATUS_REG_1),
+                       tvp5150_read(sd, TVP5150_STATUS_REG_2),
+                       tvp5150_read(sd, TVP5150_STATUS_REG_3),
+                       tvp5150_read(sd, TVP5150_STATUS_REG_4),
+                       tvp5150_read(sd, TVP5150_STATUS_REG_5));
 
-       dump_reg_range(c,"Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
-                                               TVP5150_TELETEXT_FIL1_END,8);
-       dump_reg_range(c,"Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
-                                               TVP5150_TELETEXT_FIL2_END,8);
+       dump_reg_range(sd, "Teletext filter 1",   TVP5150_TELETEXT_FIL1_INI,
+                       TVP5150_TELETEXT_FIL1_END, 8);
+       dump_reg_range(sd, "Teletext filter 2",   TVP5150_TELETEXT_FIL2_INI,
+                       TVP5150_TELETEXT_FIL2_END, 8);
 
        printk("tvp5150: Teletext filter enable = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA));
+                       tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA));
        printk("tvp5150: Interrupt status register A = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_STATUS_REG_A));
+                       tvp5150_read(sd, TVP5150_INT_STATUS_REG_A));
        printk("tvp5150: Interrupt enable register A = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_ENABLE_REG_A));
+                       tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A));
        printk("tvp5150: Interrupt configuration = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_INT_CONF));
+                       tvp5150_read(sd, TVP5150_INT_CONF));
        printk("tvp5150: VDP status register = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_VDP_STATUS_REG));
+                       tvp5150_read(sd, TVP5150_VDP_STATUS_REG));
        printk("tvp5150: FIFO word count = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_FIFO_WORD_COUNT));
+                       tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT));
        printk("tvp5150: FIFO interrupt threshold = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD));
+                       tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD));
        printk("tvp5150: FIFO reset = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_FIFO_RESET));
+                       tvp5150_read(sd, TVP5150_FIFO_RESET));
        printk("tvp5150: Line number interrupt = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_LINE_NUMBER_INT));
+                       tvp5150_read(sd, TVP5150_LINE_NUMBER_INT));
        printk("tvp5150: Pixel alignment register = 0x%02x%02x\n",
-                                       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH),
-                                       tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW));
+                       tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH),
+                       tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW));
        printk("tvp5150: FIFO output control = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_FIFO_OUT_CTRL));
+                       tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL));
        printk("tvp5150: Full field enable = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_FULL_FIELD_ENA));
+                       tvp5150_read(sd, TVP5150_FULL_FIELD_ENA));
        printk("tvp5150: Full field mode register = 0x%02x\n",
-                                       tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG));
+                       tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG));
 
-       dump_reg_range(c,"CC   data",   TVP5150_CC_DATA_INI,
-                                       TVP5150_CC_DATA_END,8);
+       dump_reg_range(sd, "CC   data",   TVP5150_CC_DATA_INI,
+                       TVP5150_CC_DATA_END, 8);
 
-       dump_reg_range(c,"WSS  data",   TVP5150_WSS_DATA_INI,
-                                       TVP5150_WSS_DATA_END,8);
+       dump_reg_range(sd, "WSS  data",   TVP5150_WSS_DATA_INI,
+                       TVP5150_WSS_DATA_END, 8);
 
-       dump_reg_range(c,"VPS  data",   TVP5150_VPS_DATA_INI,
-                                       TVP5150_VPS_DATA_END,8);
+       dump_reg_range(sd, "VPS  data",   TVP5150_VPS_DATA_INI,
+                       TVP5150_VPS_DATA_END, 8);
 
-       dump_reg_range(c,"VITC data",   TVP5150_VITC_DATA_INI,
-                                       TVP5150_VITC_DATA_END,10);
+       dump_reg_range(sd, "VITC data",   TVP5150_VITC_DATA_INI,
+                       TVP5150_VITC_DATA_END, 10);
 
-       dump_reg_range(c,"Line mode",   TVP5150_LINE_MODE_INI,
-                                       TVP5150_LINE_MODE_END,8);
+       dump_reg_range(sd, "Line mode",   TVP5150_LINE_MODE_INI,
+                       TVP5150_LINE_MODE_END, 8);
+       return 0;
 }
 
 /****************************************************************************
                        Basic functions
  ****************************************************************************/
 
-static inline void tvp5150_selmux(struct i2c_client *c)
+static inline void tvp5150_selmux(struct v4l2_subdev *sd)
 {
        int opmode=0;
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
+       struct tvp5150 *decoder = to_tvp5150(sd);
        int input = 0;
        unsigned char val;
 
@@ -309,23 +306,23 @@ static inline void tvp5150_selmux(struct i2c_client *c)
                break;
        }
 
-       tvp5150_dbg( 1, "Selecting video route: route input=%i, output=%i "
+       v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i "
                        "=> tvp5150 input=%i, opmode=%i\n",
                        decoder->route.input,decoder->route.output,
                        input, opmode );
 
-       tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
-       tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
+       tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
+       tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);
 
        /* Svideo should enable YCrCb output and disable GPCL output
         * For Composite and TV, it should be the reverse
         */
-       val = tvp5150_read(c, TVP5150_MISC_CTL);
+       val = tvp5150_read(sd, TVP5150_MISC_CTL);
        if (decoder->route.input == TVP5150_SVIDEO)
                val = (val & ~0x40) | 0x10;
        else
                val = (val & ~0x10) | 0x40;
-       tvp5150_write(c, TVP5150_MISC_CTL, val);
+       tvp5150_write(sd, TVP5150_MISC_CTL, val);
 };
 
 struct i2c_reg_value {
@@ -593,35 +590,35 @@ static struct i2c_vbi_ram_value vbi_ram_default[] =
        { (u16)-1 }
 };
 
-static int tvp5150_write_inittab(struct i2c_client *c,
+static int tvp5150_write_inittab(struct v4l2_subdev *sd,
                                const struct i2c_reg_value *regs)
 {
        while (regs->reg != 0xff) {
-               tvp5150_write(c, regs->reg, regs->value);
+               tvp5150_write(sd, regs->reg, regs->value);
                regs++;
        }
        return 0;
 }
 
-static int tvp5150_vdp_init(struct i2c_client *c,
+static int tvp5150_vdp_init(struct v4l2_subdev *sd,
                                const struct i2c_vbi_ram_value *regs)
 {
        unsigned int i;
 
        /* Disable Full Field */
-       tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
+       tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
 
        /* Before programming, Line mode should be at 0xff */
-       for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
-               tvp5150_write(c, i, 0xff);
+       for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
+               tvp5150_write(sd, i, 0xff);
 
        /* Load Ram Table */
-       while (regs->reg != (u16)-1 ) {
-               tvp5150_write(c, TVP5150_CONF_RAM_ADDR_HIGH,regs->reg>>8);
-               tvp5150_write(c, TVP5150_CONF_RAM_ADDR_LOW,regs->reg);
+       while (regs->reg != (u16)-1) {
+               tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
+               tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
 
-               for (i=0;i<16;i++)
-                       tvp5150_write(c, TVP5150_VDP_CONF_RAM_DATA,regs->values[i]);
+               for (i = 0; i < 16; i++)
+                       tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
 
                regs++;
        }
@@ -629,11 +626,13 @@ static int tvp5150_vdp_init(struct i2c_client *c,
 }
 
 /* Fills VBI capabilities based on i2c_vbi_ram_value struct */
-static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
+static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
                                struct v4l2_sliced_vbi_cap *cap)
 {
+       const struct i2c_vbi_ram_value *regs = vbi_ram_default;
        int line;
 
+       v4l2_dbg(1, debug, sd, "VIDIOC_G_SLICED_VBI_CAP\n");
        memset(cap, 0, sizeof *cap);
 
        while (regs->reg != (u16)-1 ) {
@@ -644,6 +643,7 @@ static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
 
                regs++;
        }
+       return 0;
 }
 
 /* Set vbi processing
@@ -659,18 +659,18 @@ static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs,
  *     LSB = field1
  *     MSB = field2
  */
-static int tvp5150_set_vbi(struct i2c_client *c,
+static int tvp5150_set_vbi(struct v4l2_subdev *sd,
                        const struct i2c_vbi_ram_value *regs,
                        unsigned int type,u8 flags, int line,
                        const int fields)
 {
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
-       v4l2_std_id std=decoder->norm;
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       v4l2_std_id std = decoder->norm;
        u8 reg;
        int pos=0;
 
        if (std == V4L2_STD_ALL) {
-               tvp5150_err("VBI can't be configured without knowing number of lines\n");
+               v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
                return 0;
        } else if (std & V4L2_STD_625_50) {
                /* Don't follow NTSC Line number convension */
@@ -698,163 +698,186 @@ static int tvp5150_set_vbi(struct i2c_client *c,
        reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
 
        if (fields&1) {
-               tvp5150_write(c, reg, type);
+               tvp5150_write(sd, reg, type);
        }
 
        if (fields&2) {
-               tvp5150_write(c, reg+1, type);
+               tvp5150_write(sd, reg+1, type);
        }
 
        return type;
 }
 
-static int tvp5150_get_vbi(struct i2c_client *c,
+static int tvp5150_get_vbi(struct v4l2_subdev *sd,
                        const struct i2c_vbi_ram_value *regs, int line)
 {
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
-       v4l2_std_id std=decoder->norm;
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       v4l2_std_id std = decoder->norm;
        u8 reg;
-       int pos, type=0;
+       int pos, type = 0;
 
        if (std == V4L2_STD_ALL) {
-               tvp5150_err("VBI can't be configured without knowing number of lines\n");
+               v4l2_err(sd, "VBI can't be configured without knowing number of lines\n");
                return 0;
        } else if (std & V4L2_STD_625_50) {
                /* Don't follow NTSC Line number convension */
                line += 3;
        }
 
-       if (line<6||line>27)
+       if (line < 6 || line > 27)
                return 0;
 
-       reg=((line-6)<<1)+TVP5150_LINE_MODE_INI;
+       reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
 
-       pos=tvp5150_read(c, reg)&0x0f;
-       if (pos<0x0f)
-               type=regs[pos].type.vbi_type;
+       pos = tvp5150_read(sd, reg) & 0x0f;
+       if (pos < 0x0f)
+               type = regs[pos].type.vbi_type;
 
-       pos=tvp5150_read(c, reg+1)&0x0f;
-       if (pos<0x0f)
-               type|=regs[pos].type.vbi_type;
+       pos = tvp5150_read(sd, reg + 1) & 0x0f;
+       if (pos < 0x0f)
+               type |= regs[pos].type.vbi_type;
 
        return type;
 }
-static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std)
+
+static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
-       int fmt=0;
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       int fmt = 0;
 
-       decoder->norm=std;
+       decoder->norm = std;
 
        /* First tests should be against specific std */
 
        if (std == V4L2_STD_ALL) {
-               fmt=0;  /* Autodetect mode */
+               fmt = 0;        /* Autodetect mode */
        } else if (std & V4L2_STD_NTSC_443) {
-               fmt=0xa;
+               fmt = 0xa;
        } else if (std & V4L2_STD_PAL_M) {
-               fmt=0x6;
-       } else if (std & (V4L2_STD_PAL_N| V4L2_STD_PAL_Nc)) {
-               fmt=0x8;
+               fmt = 0x6;
+       } else if (std & (V4L2_STD_PAL_N | V4L2_STD_PAL_Nc)) {
+               fmt = 0x8;
        } else {
                /* Then, test against generic ones */
-               if (std & V4L2_STD_NTSC) {
-                       fmt=0x2;
-               } else if (std & V4L2_STD_PAL) {
-                       fmt=0x4;
-               } else if (std & V4L2_STD_SECAM) {
-                       fmt=0xc;
-               }
+               if (std & V4L2_STD_NTSC)
+                       fmt = 0x2;
+               else if (std & V4L2_STD_PAL)
+                       fmt = 0x4;
+               else if (std & V4L2_STD_SECAM)
+                       fmt = 0xc;
        }
 
-       tvp5150_dbg(1,"Set video std register to %d.\n",fmt);
-       tvp5150_write(c, TVP5150_VIDEO_STD, fmt);
-
+       v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt);
+       tvp5150_write(sd, TVP5150_VIDEO_STD, fmt);
        return 0;
 }
 
-static inline void tvp5150_reset(struct i2c_client *c)
+static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct tvp5150 *decoder = to_tvp5150(sd);
+
+       if (decoder->norm == std)
+               return 0;
+
+       return tvp5150_set_std(sd, std);
+}
+
+static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 {
+       struct tvp5150 *decoder = to_tvp5150(sd);
        u8 msb_id, lsb_id, msb_rom, lsb_rom;
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
 
-       msb_id=tvp5150_read(c,TVP5150_MSB_DEV_ID);
-       lsb_id=tvp5150_read(c,TVP5150_LSB_DEV_ID);
-       msb_rom=tvp5150_read(c,TVP5150_ROM_MAJOR_VER);
-       lsb_rom=tvp5150_read(c,TVP5150_ROM_MINOR_VER);
+       msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID);
+       lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID);
+       msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER);
+       lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
 
-       if ((msb_rom==4)&&(lsb_rom==0)) { /* Is TVP5150AM1 */
-               tvp5150_info("tvp%02x%02xam1 detected.\n",msb_id, lsb_id);
+       if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */
+               v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id);
 
                /* ITU-T BT.656.4 timing */
-               tvp5150_write(c,TVP5150_REV_SELECT,0);
+               tvp5150_write(sd, TVP5150_REV_SELECT, 0);
        } else {
-               if ((msb_rom==3)||(lsb_rom==0x21)) { /* Is TVP5150A */
-                       tvp5150_info("tvp%02x%02xa detected.\n",msb_id, lsb_id);
+               if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */
+                       v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id);
                } else {
-                       tvp5150_info("*** unknown tvp%02x%02x chip detected.\n",msb_id,lsb_id);
-                       tvp5150_info("*** Rom ver is %d.%d\n",msb_rom,lsb_rom);
+                       v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
+                                       msb_id, lsb_id);
+                       v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom);
                }
        }
 
        /* Initializes TVP5150 to its default values */
-       tvp5150_write_inittab(c, tvp5150_init_default);
+       tvp5150_write_inittab(sd, tvp5150_init_default);
 
        /* Initializes VDP registers */
-       tvp5150_vdp_init(c, vbi_ram_default);
+       tvp5150_vdp_init(sd, vbi_ram_default);
 
        /* Selects decoder input */
-       tvp5150_selmux(c);
+       tvp5150_selmux(sd);
 
        /* Initializes TVP5150 to stream enabled values */
-       tvp5150_write_inittab(c, tvp5150_init_enable);
+       tvp5150_write_inittab(sd, tvp5150_init_enable);
 
        /* Initialize image preferences */
-       tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright);
-       tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast);
-       tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast);
-       tvp5150_write(c, TVP5150_HUE_CTL, decoder->hue);
+       tvp5150_write(sd, TVP5150_BRIGHT_CTL, decoder->bright);
+       tvp5150_write(sd, TVP5150_CONTRAST_CTL, decoder->contrast);
+       tvp5150_write(sd, TVP5150_SATURATION_CTL, decoder->contrast);
+       tvp5150_write(sd, TVP5150_HUE_CTL, decoder->hue);
 
-       tvp5150_set_std(c, decoder->norm);
+       tvp5150_set_std(sd, decoder->norm);
+       return 0;
 };
 
-static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-/*     struct tvp5150 *decoder = i2c_get_clientdata(c); */
+       v4l2_dbg(1, debug, sd, "VIDIOC_G_CTRL called\n");
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               ctrl->value = tvp5150_read(c, TVP5150_BRIGHT_CTL);
+               ctrl->value = tvp5150_read(sd, TVP5150_BRIGHT_CTL);
                return 0;
        case V4L2_CID_CONTRAST:
-               ctrl->value = tvp5150_read(c, TVP5150_CONTRAST_CTL);
+               ctrl->value = tvp5150_read(sd, TVP5150_CONTRAST_CTL);
                return 0;
        case V4L2_CID_SATURATION:
-               ctrl->value = tvp5150_read(c, TVP5150_SATURATION_CTL);
+               ctrl->value = tvp5150_read(sd, TVP5150_SATURATION_CTL);
                return 0;
        case V4L2_CID_HUE:
-               ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
+               ctrl->value = tvp5150_read(sd, TVP5150_HUE_CTL);
                return 0;
        }
        return -EINVAL;
 }
 
-static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
+static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-/*     struct tvp5150 *decoder = i2c_get_clientdata(c); */
+       u8 i, n;
+       n = ARRAY_SIZE(tvp5150_qctrl);
+
+       for (i = 0; i < n; i++) {
+               if (ctrl->id != tvp5150_qctrl[i].id)
+                       continue;
+               if (ctrl->value < tvp5150_qctrl[i].minimum ||
+                   ctrl->value > tvp5150_qctrl[i].maximum)
+                       return -ERANGE;
+               v4l2_dbg(1, debug, sd, "VIDIOC_S_CTRL: id=%d, value=%d\n",
+                                       ctrl->id, ctrl->value);
+               break;
+       }
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               tvp5150_write(c, TVP5150_BRIGHT_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->value);
                return 0;
        case V4L2_CID_CONTRAST:
-               tvp5150_write(c, TVP5150_CONTRAST_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->value);
                return 0;
        case V4L2_CID_SATURATION:
-               tvp5150_write(c, TVP5150_SATURATION_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->value);
                return 0;
        case V4L2_CID_HUE:
-               tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
+               tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->value);
                return 0;
        }
        return -EINVAL;
@@ -863,227 +886,210 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
 /****************************************************************************
                        I2C Command
  ****************************************************************************/
-static int tvp5150_command(struct i2c_client *c,
-                          unsigned int cmd, void *arg)
-{
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
 
-       switch (cmd) {
+static int tvp5150_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct tvp5150 *decoder = to_tvp5150(sd);
 
-       case 0:
-       case VIDIOC_INT_RESET:
-               tvp5150_reset(c);
-               break;
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-       {
-               struct v4l2_routing *route = arg;
+       decoder->route = *route;
+       tvp5150_selmux(sd);
+       return 0;
+}
 
-               *route = decoder->route;
-               break;
+static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct v4l2_sliced_vbi_format *svbi;
+       int i;
+
+       /* raw vbi */
+       if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+               /* this is for capturing 36 raw vbi lines
+                  if there's a way to cut off the beginning 2 vbi lines
+                  with the tvp5150 then the vbi line count could be lowered
+                  to 17 lines/field again, although I couldn't find a register
+                  which could do that cropping */
+               if (fmt->fmt.vbi.sample_format == V4L2_PIX_FMT_GREY)
+                       tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
+               if (fmt->fmt.vbi.count[0] == 18 && fmt->fmt.vbi.count[1] == 18) {
+                       tvp5150_write(sd, TVP5150_VERT_BLANKING_START, 0x00);
+                       tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP, 0x01);
+               }
+               return 0;
        }
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-       {
-               struct v4l2_routing *route = arg;
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               return -EINVAL;
+       svbi = &fmt->fmt.sliced;
+       if (svbi->service_set != 0) {
+               for (i = 0; i <= 23; i++) {
+                       svbi->service_lines[1][i] = 0;
+                       svbi->service_lines[0][i] =
+                               tvp5150_set_vbi(sd, vbi_ram_default,
+                                      svbi->service_lines[0][i], 0xf0, i, 3);
+               }
+               /* Enables FIFO */
+               tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
+       } else {
+               /* Disables FIFO*/
+               tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 0);
 
-               decoder->route = *route;
-               tvp5150_selmux(c);
-               break;
+               /* Disable Full Field */
+               tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
+
+               /* Disable Line modes */
+               for (i = TVP5150_LINE_MODE_INI; i <= TVP5150_LINE_MODE_END; i++)
+                       tvp5150_write(sd, i, 0xff);
        }
-       case VIDIOC_S_STD:
-               if (decoder->norm == *(v4l2_std_id *)arg)
-                       break;
-               return tvp5150_set_std(c, *(v4l2_std_id *)arg);
-       case VIDIOC_G_STD:
-               *(v4l2_std_id *)arg = decoder->norm;
-               break;
+       return 0;
+}
 
-       case VIDIOC_G_SLICED_VBI_CAP:
-       {
-               struct v4l2_sliced_vbi_cap *cap = arg;
-               tvp5150_dbg(1, "VIDIOC_G_SLICED_VBI_CAP\n");
+static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct v4l2_sliced_vbi_format *svbi;
+       int i, mask = 0;
 
-               tvp5150_vbi_get_cap(vbi_ram_default, cap);
-               break;
+       if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+               return -EINVAL;
+       svbi = &fmt->fmt.sliced;
+       memset(svbi, 0, sizeof(*svbi));
+
+       for (i = 0; i <= 23; i++) {
+               svbi->service_lines[0][i] =
+                       tvp5150_get_vbi(sd, vbi_ram_default, i);
+               mask |= svbi->service_lines[0][i];
        }
-       case VIDIOC_S_FMT:
-       {
-               struct v4l2_format *fmt;
-               struct v4l2_sliced_vbi_format *svbi;
-               int i;
-
-               fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-                       return -EINVAL;
-               svbi = &fmt->fmt.sliced;
-               if (svbi->service_set != 0) {
-                       for (i = 0; i <= 23; i++) {
-                               svbi->service_lines[1][i] = 0;
-
-                               svbi->service_lines[0][i]=tvp5150_set_vbi(c,
-                                        vbi_ram_default,
-                                        svbi->service_lines[0][i],0xf0,i,3);
-                       }
-                       /* Enables FIFO */
-                       tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,1);
-               } else {
-                       /* Disables FIFO*/
-                       tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,0);
+       svbi->service_set = mask;
+       return 0;
+}
 
-                       /* Disable Full Field */
-                       tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0);
 
-                       /* Disable Line modes */
-                       for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++)
-                               tvp5150_write(c, i, 0xff);
-               }
-               break;
-       }
-       case VIDIOC_G_FMT:
-       {
-               struct v4l2_format *fmt;
-               struct v4l2_sliced_vbi_format *svbi;
+static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_chip_ident *chip)
+{
+       int rev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-               int i, mask=0;
+       rev = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER) << 8 |
+             tvp5150_read(sd, TVP5150_ROM_MINOR_VER);
 
-               fmt = arg;
-               if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
-                       return -EINVAL;
-               svbi = &fmt->fmt.sliced;
-               memset(svbi, 0, sizeof(*svbi));
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP5150,
+                                         rev);
+}
 
-               for (i = 0; i <= 23; i++) {
-                       svbi->service_lines[0][i]=tvp5150_get_vbi(c,
-                               vbi_ram_default,i);
-                       mask|=svbi->service_lines[0][i];
-               }
-               svbi->service_set=mask;
-               break;
-       }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(c, reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER)
-                       reg->val = tvp5150_read(c, reg->reg & 0xff);
-               else
-                       tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
-               break;
-       }
-#endif
+static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_LOG_STATUS:
-               dump_reg(c);
-               break;
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = tvp5150_read(sd, reg->reg & 0xff);
+       return 0;
+}
 
-       case VIDIOC_G_TUNER:
-               {
-                       struct v4l2_tuner *vt = arg;
-                       int status = tvp5150_read(c, 0x88);
+static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-                       vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
-                       break;
-               }
-       case VIDIOC_QUERYCTRL:
-               {
-                       struct v4l2_queryctrl *qc = arg;
-                       int i;
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
+}
+#endif
 
-                       tvp5150_dbg(1, "VIDIOC_QUERYCTRL called\n");
+static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       int status = tvp5150_read(sd, 0x88);
 
-                       for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
-                               if (qc->id && qc->id == tvp5150_qctrl[i].id) {
-                                       memcpy(qc, &(tvp5150_qctrl[i]),
-                                              sizeof(*qc));
-                                       return 0;
-                               }
+       vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0;
+       return 0;
+}
 
-                       return -EINVAL;
-               }
-       case VIDIOC_G_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-                       tvp5150_dbg(1, "VIDIOC_G_CTRL called\n");
+static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       int i;
 
-                       return tvp5150_get_ctrl(c, ctrl);
-               }
-       case VIDIOC_S_CTRL:
-               {
-                       struct v4l2_control *ctrl = arg;
-                       u8 i, n;
-                       n = ARRAY_SIZE(tvp5150_qctrl);
-                       for (i = 0; i < n; i++)
-                               if (ctrl->id == tvp5150_qctrl[i].id) {
-                                       if (ctrl->value <
-                                           tvp5150_qctrl[i].minimum
-                                           || ctrl->value >
-                                           tvp5150_qctrl[i].maximum)
-                                               return -ERANGE;
-                                       tvp5150_dbg(1,
-                                               "VIDIOC_S_CTRL: id=%d, value=%d\n",
-                                               ctrl->id, ctrl->value);
-                                       return tvp5150_set_ctrl(c, ctrl);
-                               }
-                       return -EINVAL;
+       v4l2_dbg(1, debug, sd, "VIDIOC_QUERYCTRL called\n");
+
+       for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
+               if (qc->id && qc->id == tvp5150_qctrl[i].id) {
+                       memcpy(qc, &(tvp5150_qctrl[i]),
+                              sizeof(*qc));
+                       return 0;
                }
 
-       default:
-               return -EINVAL;
-       }
+       return -EINVAL;
+}
 
-       return 0;
+static int tvp5150_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
 }
 
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
+       .log_status = tvp5150_log_status,
+       .g_ctrl = tvp5150_g_ctrl,
+       .s_ctrl = tvp5150_s_ctrl,
+       .queryctrl = tvp5150_queryctrl,
+       .reset = tvp5150_reset,
+       .g_chip_ident = tvp5150_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = tvp5150_g_register,
+       .s_register = tvp5150_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
+       .s_std = tvp5150_s_std,
+       .g_tuner = tvp5150_g_tuner,
+};
+
+static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
+       .s_routing = tvp5150_s_routing,
+       .g_fmt = tvp5150_g_fmt,
+       .s_fmt = tvp5150_s_fmt,
+       .g_sliced_vbi_cap = tvp5150_g_sliced_vbi_cap,
+};
+
+static const struct v4l2_subdev_ops tvp5150_ops = {
+       .core = &tvp5150_core_ops,
+       .tuner = &tvp5150_tuner_ops,
+       .video = &tvp5150_video_ops,
+};
+
+
 /****************************************************************************
                        I2C Client & Driver
  ****************************************************************************/
-static struct i2c_driver driver;
-
-static struct i2c_client client_template = {
-       .name = "(unset)",
-       .driver = &driver,
-};
 
-static int tvp5150_detect_client(struct i2c_adapter *adapter,
-                                int address, int kind)
+static int tvp5150_probe(struct i2c_client *c,
+                        const struct i2c_device_id *id)
 {
-       struct i2c_client *c;
        struct tvp5150 *core;
-       int rv;
-
-       if (debug)
-               printk( KERN_INFO
-               "tvp5150.c: detecting tvp5150 client on address 0x%x\n",
-               address << 1);
-
-       client_template.adapter = adapter;
-       client_template.addr = address;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
-       if (!i2c_check_functionality
-           (adapter,
+       if (!i2c_check_functionality(c->adapter,
             I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-               return 0;
-
-       c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (!c)
-               return -ENOMEM;
-       memcpy(c, &client_template, sizeof(struct i2c_client));
+               return -EIO;
 
        core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
        if (!core) {
-               kfree(c);
                return -ENOMEM;
        }
-       i2c_set_clientdata(c, core);
-
-       rv = i2c_attach_client(c);
+       sd = &core->sd;
+       v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+       v4l_info(c, "chip found @ 0x%02x (%s)\n",
+                c->addr << 1, c->adapter->name);
 
        core->norm = V4L2_STD_ALL;      /* Default is autodetect */
        core->route.input = TVP5150_COMPOSITE1;
@@ -1093,69 +1099,38 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
        core->hue = 0;
        core->sat = 128;
 
-       if (rv) {
-               kfree(c);
-               kfree(core);
-               return rv;
-       }
-
        if (debug > 1)
-               dump_reg(c);
+               tvp5150_log_status(sd);
        return 0;
 }
 
-static int tvp5150_attach_adapter(struct i2c_adapter *adapter)
+static int tvp5150_remove(struct i2c_client *c)
 {
-       if (debug)
-               printk( KERN_INFO
-               "tvp5150.c: starting probe for adapter %s (0x%x)\n",
-               adapter->name, adapter->id);
-       return i2c_probe(adapter, &addr_data, &tvp5150_detect_client);
-}
-
-static int tvp5150_detach_client(struct i2c_client *c)
-{
-       struct tvp5150 *decoder = i2c_get_clientdata(c);
-       int err;
+       struct v4l2_subdev *sd = i2c_get_clientdata(c);
 
-       tvp5150_dbg(1,
+       v4l2_dbg(1, debug, sd,
                "tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
                c->addr << 1);
 
-       err = i2c_detach_client(c);
-       if (err) {
-               return err;
-       }
-
-       kfree(decoder);
-       kfree(c);
-
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_tvp5150(sd));
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver driver = {
-       .driver = {
-               .name = "tvp5150",
-       },
-       .id = I2C_DRIVERID_TVP5150,
-
-       .attach_adapter = tvp5150_attach_adapter,
-       .detach_client = tvp5150_detach_client,
+static const struct i2c_device_id tvp5150_id[] = {
+       { "tvp5150", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tvp5150_id);
 
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = "tvp5150",
+       .driverid = I2C_DRIVERID_TVP5150,
        .command = tvp5150_command,
+       .probe = tvp5150_probe,
+       .remove = tvp5150_remove,
+       .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+       .id_table = tvp5150_id,
 };
-
-static int __init tvp5150_init(void)
-{
-       return i2c_add_driver(&driver);
-}
-
-static void __exit tvp5150_exit(void)
-{
-       i2c_del_driver(&driver);
-}
-
-module_init(tvp5150_init);
-module_exit(tvp5150_exit);
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
new file mode 100644 (file)
index 0000000..d5cdc4b
--- /dev/null
@@ -0,0 +1,951 @@
+/*
+ * tw9910 Video Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can 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/i2c.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-common.h>
+#include <media/soc_camera.h>
+#include <media/tw9910.h>
+
+#define GET_ID(val)  ((val & 0xF8) >> 3)
+#define GET_ReV(val) (val & 0x07)
+
+/*
+ * register offset
+ */
+#define ID             0x00 /* Product ID Code Register */
+#define STATUS1                0x01 /* Chip Status Register I */
+#define INFORM         0x02 /* Input Format */
+#define OPFORM         0x03 /* Output Format Control Register */
+#define DLYCTR         0x04 /* Hysteresis and HSYNC Delay Control */
+#define OUTCTR1                0x05 /* Output Control I */
+#define ACNTL1         0x06 /* Analog Control Register 1 */
+#define CROP_HI                0x07 /* Cropping Register, High */
+#define VDELAY_LO      0x08 /* Vertical Delay Register, Low */
+#define VACTIVE_LO     0x09 /* Vertical Active Register, Low */
+#define HDELAY_LO      0x0A /* Horizontal Delay Register, Low */
+#define HACTIVE_LO     0x0B /* Horizontal Active Register, Low */
+#define CNTRL1         0x0C /* Control Register I */
+#define VSCALE_LO      0x0D /* Vertical Scaling Register, Low */
+#define SCALE_HI       0x0E /* Scaling Register, High */
+#define HSCALE_LO      0x0F /* Horizontal Scaling Register, Low */
+#define BRIGHT         0x10 /* BRIGHTNESS Control Register */
+#define CONTRAST       0x11 /* CONTRAST Control Register */
+#define SHARPNESS      0x12 /* SHARPNESS Control Register I */
+#define SAT_U          0x13 /* Chroma (U) Gain Register */
+#define SAT_V          0x14 /* Chroma (V) Gain Register */
+#define HUE            0x15 /* Hue Control Register */
+#define CORING1                0x17
+#define CORING2                0x18 /* Coring and IF compensation */
+#define VBICNTL                0x19 /* VBI Control Register */
+#define ACNTL2         0x1A /* Analog Control 2 */
+#define OUTCTR2                0x1B /* Output Control 2 */
+#define SDT            0x1C /* Standard Selection */
+#define SDTR           0x1D /* Standard Recognition */
+#define TEST           0x1F /* Test Control Register */
+#define CLMPG          0x20 /* Clamping Gain */
+#define IAGC           0x21 /* Individual AGC Gain */
+#define AGCGAIN                0x22 /* AGC Gain */
+#define PEAKWT         0x23 /* White Peak Threshold */
+#define CLMPL          0x24 /* Clamp level */
+#define SYNCT          0x25 /* Sync Amplitude */
+#define MISSCNT                0x26 /* Sync Miss Count Register */
+#define PCLAMP         0x27 /* Clamp Position Register */
+#define VCNTL1         0x28 /* Vertical Control I */
+#define VCNTL2         0x29 /* Vertical Control II */
+#define CKILL          0x2A /* Color Killer Level Control */
+#define COMB           0x2B /* Comb Filter Control */
+#define LDLY           0x2C /* Luma Delay and H Filter Control */
+#define MISC1          0x2D /* Miscellaneous Control I */
+#define LOOP           0x2E /* LOOP Control Register */
+#define MISC2          0x2F /* Miscellaneous Control II */
+#define MVSN           0x30 /* Macrovision Detection */
+#define STATUS2                0x31 /* Chip STATUS II */
+#define HFREF          0x32 /* H monitor */
+#define CLMD           0x33 /* CLAMP MODE */
+#define IDCNTL         0x34 /* ID Detection Control */
+#define CLCNTL1                0x35 /* Clamp Control I */
+#define ANAPLLCTL      0x4C
+#define VBIMIN         0x4D
+#define HSLOWCTL       0x4E
+#define WSS3           0x4F
+#define FILLDATA       0x50
+#define SDID           0x51
+#define DID            0x52
+#define WSS1           0x53
+#define WSS2           0x54
+#define VVBI           0x55
+#define LCTL6          0x56
+#define LCTL7          0x57
+#define LCTL8          0x58
+#define LCTL9          0x59
+#define LCTL10         0x5A
+#define LCTL11         0x5B
+#define LCTL12         0x5C
+#define LCTL13         0x5D
+#define LCTL14         0x5E
+#define LCTL15         0x5F
+#define LCTL16         0x60
+#define LCTL17         0x61
+#define LCTL18         0x62
+#define LCTL19         0x63
+#define LCTL20         0x64
+#define LCTL21         0x65
+#define LCTL22         0x66
+#define LCTL23         0x67
+#define LCTL24         0x68
+#define LCTL25         0x69
+#define LCTL26         0x6A
+#define HSGEGIN                0x6B
+#define HSEND          0x6C
+#define OVSDLY         0x6D
+#define OVSEND         0x6E
+#define VBIDELAY       0x6F
+
+/*
+ * register detail
+ */
+
+/* INFORM */
+#define FC27_ON     0x40 /* 1 : Input crystal clock frequency is 27MHz */
+#define FC27_FF     0x00 /* 0 : Square pixel mode. */
+                        /*     Must use 24.54MHz for 60Hz field rate */
+                        /*     source or 29.5MHz for 50Hz field rate */
+#define IFSEL_S     0x10 /* 01 : S-video decoding */
+#define IFSEL_C     0x00 /* 00 : Composite video decoding */
+                        /* Y input video selection */
+#define YSEL_M0     0x00 /*  00 : Mux0 selected */
+#define YSEL_M1     0x04 /*  01 : Mux1 selected */
+#define YSEL_M2     0x08 /*  10 : Mux2 selected */
+#define YSEL_M3     0x10 /*  11 : Mux3 selected */
+
+/* OPFORM */
+#define MODE        0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
+                        /* 1 : ITU-R-656 compatible data sequence format */
+#define LEN         0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
+                        /* 1 : 16-bit YCrCb 4:2:2 output format.*/
+#define LLCMODE     0x20 /* 1 : LLC output mode. */
+                        /* 0 : free-run output mode */
+#define AINC        0x10 /* Serial interface auto-indexing control */
+                        /* 0 : auto-increment */
+                        /* 1 : non-auto */
+#define VSCTL       0x08 /* 1 : Vertical out ctrl by DVALID */
+                        /* 0 : Vertical out ctrl by HACTIVE and DVALID */
+#define OEN         0x04 /* Output Enable together with TRI_SEL. */
+
+/* OUTCTR1 */
+#define VSP_LO      0x00 /* 0 : VS pin output polarity is active low */
+#define VSP_HI      0x80 /* 1 : VS pin output polarity is active high. */
+                        /* VS pin output control */
+#define VSSL_VSYNC  0x00 /*   0 : VSYNC  */
+#define VSSL_VACT   0x10 /*   1 : VACT   */
+#define VSSL_FIELD  0x20 /*   2 : FIELD  */
+#define VSSL_VVALID 0x30 /*   3 : VVALID */
+#define VSSL_ZERO   0x70 /*   7 : 0      */
+#define HSP_LOW     0x00 /* 0 : HS pin output polarity is active low */
+#define HSP_HI      0x08 /* 1 : HS pin output polarity is active high.*/
+                        /* HS pin output control */
+#define HSSL_HACT   0x00 /*   0 : HACT   */
+#define HSSL_HSYNC  0x01 /*   1 : HSYNC  */
+#define HSSL_DVALID 0x02 /*   2 : DVALID */
+#define HSSL_HLOCK  0x03 /*   3 : HLOCK  */
+#define HSSL_ASYNCW 0x04 /*   4 : ASYNCW */
+#define HSSL_ZERO   0x07 /*   7 : 0      */
+
+/* ACNTL1 */
+#define SRESET      0x80 /* resets the device to its default state
+                         * but all register content remain unchanged.
+                         * This bit is self-resetting.
+                         */
+
+/* VBICNTL */
+/* RTSEL : control the real time signal
+*          output from the MPOUT pin
+*/
+#define RTSEL_MASK  0x07
+#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
+#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
+#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
+#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
+#define RTSEL_MONO  0x04 /* 0100 = MONO */
+#define RTSEL_DET50 0x05 /* 0101 = DET50 */
+#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
+#define RTSEL_RTCO  0x07 /* 0111 = RTCO ( Real Time Control ) */
+
+/*
+ * structure
+ */
+
+struct regval_list {
+       unsigned char reg_num;
+       unsigned char value;
+};
+
+struct tw9910_scale_ctrl {
+       char           *name;
+       unsigned short  width;
+       unsigned short  height;
+       u16             hscale;
+       u16             vscale;
+};
+
+struct tw9910_cropping_ctrl {
+       u16 vdelay;
+       u16 vactive;
+       u16 hdelay;
+       u16 hactive;
+};
+
+struct tw9910_hsync_ctrl {
+       u16 start;
+       u16 end;
+};
+
+struct tw9910_priv {
+       struct tw9910_video_info       *info;
+       struct i2c_client              *client;
+       struct soc_camera_device        icd;
+       const struct tw9910_scale_ctrl *scale;
+};
+
+/*
+ * register settings
+ */
+
+#define ENDMARKER { 0xff, 0xff }
+
+static const struct regval_list tw9910_default_regs[] =
+{
+       { OPFORM,  0x00 },
+       { OUTCTR1, VSP_LO | VSSL_VVALID | HSP_HI | HSSL_HSYNC },
+       ENDMARKER,
+};
+
+static const struct soc_camera_data_format tw9910_color_fmt[] = {
+       {
+               .name       = "VYUY",
+               .fourcc     = V4L2_PIX_FMT_VYUY,
+               .depth      = 16,
+               .colorspace = V4L2_COLORSPACE_SMPTE170M,
+       }
+};
+
+static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
+       {
+               .name   = "NTSC SQ",
+               .width  = 640,
+               .height = 480,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "NTSC CCIR601",
+               .width  = 720,
+               .height = 480,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "NTSC SQ (CIF)",
+               .width  = 320,
+               .height = 240,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "NTSC CCIR601 (CIF)",
+               .width  = 360,
+               .height = 240,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "NTSC SQ (QCIF)",
+               .width  = 160,
+               .height = 120,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+       {
+               .name   = "NTSC CCIR601 (QCIF)",
+               .width  = 180,
+               .height = 120,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+};
+
+static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
+       {
+               .name   = "PAL SQ",
+               .width  = 768,
+               .height = 576,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "PAL CCIR601",
+               .width  = 720,
+               .height = 576,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "PAL SQ (CIF)",
+               .width  = 384,
+               .height = 288,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "PAL CCIR601 (CIF)",
+               .width  = 360,
+               .height = 288,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "PAL SQ (QCIF)",
+               .width  = 192,
+               .height = 144,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+       {
+               .name   = "PAL CCIR601 (QCIF)",
+               .width  = 180,
+               .height = 144,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+};
+
+static const struct tw9910_cropping_ctrl tw9910_cropping_ctrl = {
+       .vdelay  = 0x0012,
+       .vactive = 0x00F0,
+       .hdelay  = 0x0010,
+       .hactive = 0x02D0,
+};
+
+static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = {
+       .start = 0x0260,
+       .end   = 0x0300,
+};
+
+/*
+ * general function
+ */
+static int tw9910_set_scale(struct i2c_client *client,
+                           const struct tw9910_scale_ctrl *scale)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, SCALE_HI,
+                                       (scale->vscale & 0x0F00) >> 4 |
+                                       (scale->hscale & 0x0F00) >> 8);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
+                                       scale->hscale & 0x00FF);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
+                                       scale->vscale & 0x00FF);
+
+       return ret;
+}
+
+static int tw9910_set_cropping(struct i2c_client *client,
+                              const struct tw9910_cropping_ctrl *cropping)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, CROP_HI,
+                                       (cropping->vdelay  & 0x0300) >> 2 |
+                                       (cropping->vactive & 0x0300) >> 4 |
+                                       (cropping->hdelay  & 0x0300) >> 6 |
+                                       (cropping->hactive & 0x0300) >> 8);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
+                                       cropping->vdelay & 0x00FF);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
+                                       cropping->vactive & 0x00FF);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, HDELAY_LO,
+                                       cropping->hdelay & 0x00FF);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, HACTIVE_LO,
+                                       cropping->hactive & 0x00FF);
+
+       return ret;
+}
+
+static int tw9910_set_hsync(struct i2c_client *client,
+                           const struct tw9910_hsync_ctrl *hsync)
+{
+       int ret;
+
+       /* bit 10 - 3 */
+       ret = i2c_smbus_write_byte_data(client, HSGEGIN,
+                                       (hsync->start & 0x07F8) >> 3);
+       if (ret < 0)
+               return ret;
+
+       /* bit 10 - 3 */
+       ret = i2c_smbus_write_byte_data(client, HSEND,
+                                       (hsync->end & 0x07F8) >> 3);
+       if (ret < 0)
+               return ret;
+
+       /* bit 2 - 0 */
+       ret = i2c_smbus_read_byte_data(client, HSLOWCTL);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, HSLOWCTL,
+                                       (ret & 0x88)                 |
+                                       (hsync->start & 0x0007) << 4 |
+                                       (hsync->end   & 0x0007));
+
+       return ret;
+}
+
+static int tw9910_write_array(struct i2c_client *client,
+                             const struct regval_list *vals)
+{
+       while (vals->reg_num != 0xff) {
+               int ret = i2c_smbus_write_byte_data(client,
+                                                   vals->reg_num,
+                                                   vals->value);
+               if (ret < 0)
+                       return ret;
+               vals++;
+       }
+       return 0;
+}
+
+static int tw9910_mask_set(struct i2c_client *client, u8 command,
+                          u8 mask, u8 set)
+{
+       s32 val = i2c_smbus_read_byte_data(client, command);
+
+       val &= ~mask;
+       val |=  set;
+
+       return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static void tw9910_reset(struct i2c_client *client)
+{
+       i2c_smbus_write_byte_data(client, ACNTL1, SRESET);
+       msleep(1);
+}
+
+static const struct tw9910_scale_ctrl*
+tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
+{
+       const struct tw9910_scale_ctrl *scale;
+       const struct tw9910_scale_ctrl *ret = NULL;
+       v4l2_std_id norm = icd->vdev->current_norm;
+       __u32 diff = 0xffffffff, tmp;
+       int size, i;
+
+       if (norm & V4L2_STD_NTSC) {
+               scale = tw9910_ntsc_scales;
+               size = ARRAY_SIZE(tw9910_ntsc_scales);
+       } else if (norm & V4L2_STD_PAL) {
+               scale = tw9910_pal_scales;
+               size = ARRAY_SIZE(tw9910_pal_scales);
+       } else {
+               return NULL;
+       }
+
+       for (i = 0; i < size; i++) {
+               tmp = abs(width - scale[i].width) +
+                       abs(height - scale[i].height);
+               if (tmp < diff) {
+                       diff = tmp;
+                       ret = scale + i;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * soc_camera_ops function
+ */
+static int tw9910_init(struct soc_camera_device *icd)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+       int ret = 0;
+
+       if (priv->info->link.power) {
+               ret = priv->info->link.power(&priv->client->dev, 1);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (priv->info->link.reset)
+               ret = priv->info->link.reset(&priv->client->dev);
+
+       return ret;
+}
+
+static int tw9910_release(struct soc_camera_device *icd)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+       int ret = 0;
+
+       if (priv->info->link.power)
+               ret = priv->info->link.power(&priv->client->dev, 0);
+
+       return ret;
+}
+
+static int tw9910_start_capture(struct soc_camera_device *icd)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+
+       if (!priv->scale) {
+               dev_err(&icd->dev, "norm select error\n");
+               return -EPERM;
+       }
+
+       dev_dbg(&icd->dev, "%s %dx%d\n",
+                priv->scale->name,
+                priv->scale->width,
+                priv->scale->height);
+
+       return 0;
+}
+
+static int tw9910_stop_capture(struct soc_camera_device *icd)
+{
+       return 0;
+}
+
+static int tw9910_set_bus_param(struct soc_camera_device *icd,
+                               unsigned long flags)
+{
+       return 0;
+}
+
+static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+       struct soc_camera_link *icl = priv->client->dev.platform_data;
+       unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+               SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int tw9910_get_chip_id(struct soc_camera_device *icd,
+                             struct v4l2_chip_ident *id)
+{
+       id->ident = V4L2_IDENT_TW9910;
+       id->revision = 0;
+
+       return 0;
+}
+
+static int tw9910_set_std(struct soc_camera_device *icd,
+                         v4l2_std_id *a)
+{
+       int ret = -EINVAL;
+
+       if (*a & (V4L2_STD_NTSC | V4L2_STD_PAL))
+               ret = 0;
+
+       return ret;
+}
+
+static int tw9910_enum_input(struct soc_camera_device *icd,
+                            struct v4l2_input *inp)
+{
+       inp->type = V4L2_INPUT_TYPE_TUNER;
+       inp->std  = V4L2_STD_UNKNOWN;
+       strcpy(inp->name, "Video");
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tw9910_get_register(struct soc_camera_device *icd,
+                              struct v4l2_register *reg)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+       int ret;
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       ret = i2c_smbus_read_byte_data(priv->client, reg->reg);
+       if (ret < 0)
+               return ret;
+
+       /* ret      = int
+        * reg->val = __u64
+        */
+       reg->val = (__u64)ret;
+
+       return 0;
+}
+
+static int tw9910_set_register(struct soc_camera_device *icd,
+                              struct v4l2_register *reg)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+
+       if (reg->reg > 0xff ||
+           reg->val > 0xff)
+               return -EINVAL;
+
+       return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val);
+}
+#endif
+
+static int tw9910_set_fmt(struct soc_camera_device *icd, __u32 pixfmt,
+                             struct v4l2_rect *rect)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+       int                 ret  = -EINVAL;
+       u8                  val;
+
+       /*
+        * select suitable norm
+        */
+       priv->scale = tw9910_select_norm(icd, rect->width, rect->height);
+       if (!priv->scale)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * reset hardware
+        */
+       tw9910_reset(priv->client);
+       ret = tw9910_write_array(priv->client, tw9910_default_regs);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * set bus width
+        */
+       val = 0x00;
+       if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
+               val = LEN;
+
+       ret = tw9910_mask_set(priv->client, OPFORM, LEN, val);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * select MPOUT behavior
+        */
+       switch (priv->info->mpout) {
+       case TW9910_MPO_VLOSS:
+               val = RTSEL_VLOSS; break;
+       case TW9910_MPO_HLOCK:
+               val = RTSEL_HLOCK; break;
+       case TW9910_MPO_SLOCK:
+               val = RTSEL_SLOCK; break;
+       case TW9910_MPO_VLOCK:
+               val = RTSEL_VLOCK; break;
+       case TW9910_MPO_MONO:
+               val = RTSEL_MONO;  break;
+       case TW9910_MPO_DET50:
+               val = RTSEL_DET50; break;
+       case TW9910_MPO_FIELD:
+               val = RTSEL_FIELD; break;
+       case TW9910_MPO_RTCO:
+               val = RTSEL_RTCO;  break;
+       default:
+               val = 0;
+       }
+
+       ret = tw9910_mask_set(priv->client, VBICNTL, RTSEL_MASK, val);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * set scale
+        */
+       ret = tw9910_set_scale(priv->client, priv->scale);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * set cropping
+        */
+       ret = tw9910_set_cropping(priv->client, &tw9910_cropping_ctrl);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * set hsync
+        */
+       ret = tw9910_set_hsync(priv->client, &tw9910_hsync_ctrl);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       return ret;
+
+tw9910_set_fmt_error:
+
+       tw9910_reset(priv->client);
+       priv->scale = NULL;
+
+       return ret;
+}
+
+static int tw9910_try_fmt(struct soc_camera_device *icd,
+                             struct v4l2_format *f)
+{
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       const struct tw9910_scale_ctrl *scale;
+
+       if (V4L2_FIELD_ANY == pix->field) {
+               pix->field = V4L2_FIELD_INTERLACED;
+       } else if (V4L2_FIELD_INTERLACED != pix->field) {
+               dev_err(&icd->dev, "Field type invalid.\n");
+               return -EINVAL;
+       }
+
+       /*
+        * select suitable norm
+        */
+       scale = tw9910_select_norm(icd, pix->width, pix->height);
+       if (!scale)
+               return -EINVAL;
+
+       pix->width  = scale->width;
+       pix->height = scale->height;
+
+       return 0;
+}
+
+static int tw9910_video_probe(struct soc_camera_device *icd)
+{
+       struct tw9910_priv *priv = container_of(icd, struct tw9910_priv, icd);
+       s32 val;
+       int ret;
+
+       /*
+        * We must have a parent by now. And it cannot be a wrong one.
+        * So this entire test is completely redundant.
+        */
+       if (!icd->dev.parent ||
+           to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+               return -ENODEV;
+
+       /*
+        * tw9910 only use 8 or 16 bit bus width
+        */
+       if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
+           SOCAM_DATAWIDTH_8  != priv->info->buswidth) {
+               dev_err(&icd->dev, "bus width error\n");
+               return -ENODEV;
+       }
+
+       icd->formats     = tw9910_color_fmt;
+       icd->num_formats = ARRAY_SIZE(tw9910_color_fmt);
+
+       /*
+        * check and show Product ID
+        */
+       val = i2c_smbus_read_byte_data(priv->client, ID);
+       if (0x0B != GET_ID(val) ||
+           0x00 != GET_ReV(val)) {
+               dev_err(&icd->dev,
+                       "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val));
+               return -ENODEV;
+       }
+
+       dev_info(&icd->dev,
+                "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val));
+
+       ret = soc_camera_video_start(icd);
+       if (ret < 0)
+               return ret;
+
+       icd->vdev->tvnorms      = V4L2_STD_NTSC | V4L2_STD_PAL;
+       icd->vdev->current_norm = V4L2_STD_NTSC;
+
+       return ret;
+}
+
+static void tw9910_video_remove(struct soc_camera_device *icd)
+{
+       soc_camera_video_stop(icd);
+}
+
+static struct soc_camera_ops tw9910_ops = {
+       .owner                  = THIS_MODULE,
+       .probe                  = tw9910_video_probe,
+       .remove                 = tw9910_video_remove,
+       .init                   = tw9910_init,
+       .release                = tw9910_release,
+       .start_capture          = tw9910_start_capture,
+       .stop_capture           = tw9910_stop_capture,
+       .set_fmt                = tw9910_set_fmt,
+       .try_fmt                = tw9910_try_fmt,
+       .set_bus_param          = tw9910_set_bus_param,
+       .query_bus_param        = tw9910_query_bus_param,
+       .get_chip_id            = tw9910_get_chip_id,
+       .set_std                = tw9910_set_std,
+       .enum_input             = tw9910_enum_input,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .get_register           = tw9910_get_register,
+       .set_register           = tw9910_set_register,
+#endif
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int tw9910_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+
+{
+       struct tw9910_priv             *priv;
+       struct tw9910_video_info       *info;
+       struct soc_camera_device       *icd;
+       const struct tw9910_scale_ctrl *scale;
+       int                             i, ret;
+
+       info = client->dev.platform_data;
+       if (!info)
+               return -EINVAL;
+
+       if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
+                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev,
+                       "I2C-Adapter doesn't support "
+                       "I2C_FUNC_SMBUS_BYTE_DATA\n");
+               return -EIO;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->info   = info;
+       priv->client = client;
+       i2c_set_clientdata(client, priv);
+
+       icd          = &priv->icd;
+       icd->ops     = &tw9910_ops;
+       icd->control = &client->dev;
+       icd->iface   = info->link.bus_id;
+
+       /*
+        * set width and height
+        */
+       icd->width_max  = tw9910_ntsc_scales[0].width; /* set default */
+       icd->width_min  = tw9910_ntsc_scales[0].width;
+       icd->height_max = tw9910_ntsc_scales[0].height;
+       icd->height_min = tw9910_ntsc_scales[0].height;
+
+       scale = tw9910_ntsc_scales;
+       for (i = 0; i < ARRAY_SIZE(tw9910_ntsc_scales); i++) {
+               icd->width_max  = max(scale[i].width,  icd->width_max);
+               icd->width_min  = min(scale[i].width,  icd->width_min);
+               icd->height_max = max(scale[i].height, icd->height_max);
+               icd->height_min = min(scale[i].height, icd->height_min);
+       }
+       scale = tw9910_pal_scales;
+       for (i = 0; i < ARRAY_SIZE(tw9910_pal_scales); i++) {
+               icd->width_max  = max(scale[i].width,  icd->width_max);
+               icd->width_min  = min(scale[i].width,  icd->width_min);
+               icd->height_max = max(scale[i].height, icd->height_max);
+               icd->height_min = min(scale[i].height, icd->height_min);
+       }
+
+       ret = soc_camera_device_register(icd);
+
+       if (ret) {
+               i2c_set_clientdata(client, NULL);
+               kfree(priv);
+       }
+
+       return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+       struct tw9910_priv *priv = i2c_get_clientdata(client);
+
+       soc_camera_device_unregister(&priv->icd);
+       i2c_set_clientdata(client, NULL);
+       kfree(priv);
+       return 0;
+}
+
+static const struct i2c_device_id tw9910_id[] = {
+       { "tw9910", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9910_id);
+
+static struct i2c_driver tw9910_i2c_driver = {
+       .driver = {
+               .name = "tw9910",
+       },
+       .probe    = tw9910_probe,
+       .remove   = tw9910_remove,
+       .id_table = tw9910_id,
+};
+
+/*
+ * module function
+ */
+static int __init tw9910_module_init(void)
+{
+       return i2c_add_driver(&tw9910_i2c_driver);
+}
+
+static void __exit tw9910_module_exit(void)
+{
+       i2c_del_driver(&tw9910_i2c_driver);
+}
+
+module_init(tw9910_module_init);
+module_exit(tw9910_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for tw9910");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
index b4628874933bc3eb23595b0c54acf5854b1e0378..7a609a3a6dbe2e3be83b06afa6669c86c365e03a 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 #include <media/upd64031a.h>
@@ -62,6 +62,7 @@ enum {
 };
 
 struct upd64031a_state {
+       struct v4l2_subdev sd;
        u8 regs[TOT_REGS];
        u8 gr_mode;
        u8 direct_3dycs_connect;
@@ -69,6 +70,11 @@ struct upd64031a_state {
        u8 ext_vert_sync;
 };
 
+static inline struct upd64031a_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct upd64031a_state, sd);
+}
+
 static u8 upd64031a_init[] = {
        0x00, 0xb8, 0x48, 0xd2, 0xe6,
        0x03, 0x10, 0x0b, 0xaf, 0x7f,
@@ -78,8 +84,9 @@ static u8 upd64031a_init[] = {
 
 /* ------------------------------------------------------------------------ */
 
-static u8 upd64031a_read(struct i2c_client *client, u8 reg)
+static u8 upd64031a_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 buf[2];
 
        if (reg >= sizeof(buf))
@@ -90,106 +97,127 @@ static u8 upd64031a_read(struct i2c_client *client, u8 reg)
 
 /* ------------------------------------------------------------------------ */
 
-static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val)
+static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 buf[2];
 
        buf[0] = reg;
        buf[1] = val;
-       v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val);
+       v4l2_dbg(1, debug, sd, "write reg: %02X val: %02X\n", reg, val);
        if (i2c_master_send(client, buf, 2) != 2)
-               v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
+               v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
 }
 
 /* ------------------------------------------------------------------------ */
 
 /* The input changed due to new input or channel changed */
-static void upd64031a_change(struct i2c_client *client)
+static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
 {
-       struct upd64031a_state *state = i2c_get_clientdata(client);
+       struct upd64031a_state *state = to_state(sd);
        u8 reg = state->regs[R00];
 
-       v4l_dbg(1, debug, client, "changed input or channel\n");
-       upd64031a_write(client, R00, reg | 0x10);
-       upd64031a_write(client, R00, reg & ~0x10);
+       v4l2_dbg(1, debug, sd, "changed input or channel\n");
+       upd64031a_write(sd, R00, reg | 0x10);
+       upd64031a_write(sd, R00, reg & ~0x10);
+       return 0;
 }
 
 /* ------------------------------------------------------------------------ */
 
+static int upd64031a_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
+{
+       struct upd64031a_state *state = to_state(sd);
+       u8 r00, r05, r08;
+
+       state->gr_mode = (route->input & 3) << 6;
+       state->direct_3dycs_connect = (route->input & 0xc) << 4;
+       state->ext_comp_sync =
+               (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
+       state->ext_vert_sync =
+               (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
+       r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
+       r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
+               state->ext_comp_sync | state->ext_vert_sync;
+       r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
+               state->direct_3dycs_connect;
+       upd64031a_write(sd, R00, r00);
+       upd64031a_write(sd, R05, r05);
+       upd64031a_write(sd, R08, r08);
+       return upd64031a_s_frequency(sd, NULL);
+}
+
+static int upd64031a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64031A, 0);
+}
+
+static int upd64031a_log_status(struct v4l2_subdev *sd)
+{
+       v4l2_info(sd, "Status: SA00=0x%02x SA01=0x%02x\n",
+                       upd64031a_read(sd, 0), upd64031a_read(sd, 1));
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = upd64031a_read(sd, reg->reg & 0xff);
+       return 0;
+}
+
+static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       upd64031a_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
+}
+#endif
+
 static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
-       struct upd64031a_state *state = i2c_get_clientdata(client);
-       struct v4l2_routing *route = arg;
-
-       switch (cmd) {
-       case VIDIOC_S_FREQUENCY:
-               upd64031a_change(client);
-               break;
-
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = (state->gr_mode >> 6) |
-                       (state->direct_3dycs_connect >> 4) |
-                       (state->ext_comp_sync >> 1) |
-                       (state->ext_vert_sync >> 2);
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-       {
-               u8 r00, r05, r08;
-
-               state->gr_mode = (route->input & 3) << 6;
-               state->direct_3dycs_connect = (route->input & 0xc) << 4;
-               state->ext_comp_sync =
-                       (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
-               state->ext_vert_sync =
-                       (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
-               r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
-               r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
-                       state->ext_comp_sync | state->ext_vert_sync;
-               r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) |
-                       state->direct_3dycs_connect;
-               upd64031a_write(client, R00, r00);
-               upd64031a_write(client, R05, r05);
-               upd64031a_write(client, R08, r08);
-               upd64031a_change(client);
-               break;
-       }
-
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Status: SA00=0x%02x SA01=0x%02x\n",
-                       upd64031a_read(client, 0), upd64031a_read(client, 1));
-               break;
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
 
+static const struct v4l2_subdev_core_ops upd64031a_core_ops = {
+       .log_status = upd64031a_log_status,
+       .g_chip_ident = upd64031a_g_chip_ident,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
-
-               if (!v4l2_chip_match_i2c_client(client,
-                                       reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER) {
-                       reg->val = upd64031a_read(client, reg->reg & 0xff);
-                       break;
-               }
-               upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
-               break;
-       }
+       .g_register = upd64031a_g_register,
+       .s_register = upd64031a_s_register,
 #endif
+};
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg,
-                               V4L2_IDENT_UPD64031A, 0);
+static const struct v4l2_subdev_tuner_ops upd64031a_tuner_ops = {
+       .s_frequency = upd64031a_s_frequency,
+};
 
-       default:
-               break;
-       }
-       return 0;
-}
+static const struct v4l2_subdev_video_ops upd64031a_video_ops = {
+       .s_routing = upd64031a_s_routing,
+};
+
+static const struct v4l2_subdev_ops upd64031a_ops = {
+       .core = &upd64031a_core_ops,
+       .tuner = &upd64031a_tuner_ops,
+       .video = &upd64031a_video_ops,
+};
 
 /* ------------------------------------------------------------------------ */
 
@@ -199,6 +227,7 @@ static int upd64031a_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
        struct upd64031a_state *state;
+       struct v4l2_subdev *sd;
        int i;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -210,19 +239,23 @@ static int upd64031a_probe(struct i2c_client *client,
        state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
-       i2c_set_clientdata(client, state);
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &upd64031a_ops);
        memcpy(state->regs, upd64031a_init, sizeof(state->regs));
        state->gr_mode = UPD64031A_GR_ON << 6;
        state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
        state->ext_comp_sync = state->ext_vert_sync = 0;
        for (i = 0; i < TOT_REGS; i++)
-               upd64031a_write(client, i, state->regs[i]);
+               upd64031a_write(sd, i, state->regs[i]);
        return 0;
 }
 
 static int upd64031a_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index 9521ce004dcc1b282b4febbb4bcb7a3a43f74e25..58412cb9c01a0d058ec01f3f5113b75e6b757e0b 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 #include <media/upd64083.h>
@@ -51,11 +51,17 @@ enum {
 };
 
 struct upd64083_state {
+       struct v4l2_subdev sd;
        u8 mode;
        u8 ext_y_adc;
        u8 regs[TOT_REGS];
 };
 
+static inline struct upd64083_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct upd64083_state, sd);
+}
+
 /* Initial values when used in combination with the
    NEC upd64031a ghost reduction chip. */
 static u8 upd64083_init[] = {
@@ -68,34 +74,24 @@ static u8 upd64083_init[] = {
 
 /* ------------------------------------------------------------------------ */
 
-static void upd64083_log_status(struct i2c_client *client)
-{
-       u8 buf[7];
-
-       i2c_master_recv(client, buf, 7);
-       v4l_info(client, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x "
-                     "SA04=%02x SA05=%02x SA06=%02x\n",
-               buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
-}
-
-/* ------------------------------------------------------------------------ */
-
-static void upd64083_write(struct i2c_client *client, u8 reg, u8 val)
+static void upd64083_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 buf[2];
 
        buf[0] = reg;
        buf[1] = val;
-       v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val);
+       v4l2_dbg(1, debug, sd, "write reg: %02x val: %02x\n", reg, val);
        if (i2c_master_send(client, buf, 2) != 2)
-               v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
+               v4l2_err(sd, "I/O error write 0x%02x/0x%02x\n", reg, val);
 }
 
 /* ------------------------------------------------------------------------ */
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 upd64083_read(struct i2c_client *client, u8 reg)
+static u8 upd64083_read(struct v4l2_subdev *sd, u8 reg)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 buf[7];
 
        if (reg >= sizeof(buf))
@@ -107,67 +103,94 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg)
 
 /* ------------------------------------------------------------------------ */
 
-static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int upd64083_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
-       struct upd64083_state *state = i2c_get_clientdata(client);
-       struct v4l2_routing *route = arg;
-
-       switch (cmd) {
-       case VIDIOC_INT_G_VIDEO_ROUTING:
-               route->input = (state->mode >> 6) | (state->ext_y_adc >> 3);
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_VIDEO_ROUTING:
-       {
-               u8 r00, r02;
-
-               if (route->input > 7 || (route->input & 6) == 6)
-                       return -EINVAL;
-               state->mode = (route->input & 3) << 6;
-               state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3;
-               r00 = (state->regs[R00] & ~(3 << 6)) | state->mode;
-               r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc;
-               upd64083_write(client, R00, r00);
-               upd64083_write(client, R02, r02);
-               break;
-       }
-
-       case VIDIOC_LOG_STATUS:
-               upd64083_log_status(client);
-               break;
+       struct upd64083_state *state = to_state(sd);
+       u8 r00, r02;
+
+       if (route->input > 7 || (route->input & 6) == 6)
+               return -EINVAL;
+       state->mode = (route->input & 3) << 6;
+       state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3;
+       r00 = (state->regs[R00] & ~(3 << 6)) | state->mode;
+       r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc;
+       upd64083_write(sd, R00, r00);
+       upd64083_write(sd, R02, r02);
+       return 0;
+}
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       case VIDIOC_DBG_G_REGISTER:
-       case VIDIOC_DBG_S_REGISTER:
-       {
-               struct v4l2_register *reg = arg;
+static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
+                               reg->match_type, reg->match_chip))
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       reg->val = upd64083_read(sd, reg->reg & 0xff);
+       return 0;
+}
 
-               if (!v4l2_chip_match_i2c_client(client,
+static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!v4l2_chip_match_i2c_client(client,
                                reg->match_type, reg->match_chip))
-                       return -EINVAL;
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if (cmd == VIDIOC_DBG_G_REGISTER) {
-                       reg->val = upd64083_read(client, reg->reg & 0xff);
-                       break;
-               }
-               upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
-               break;
-       }
+               return -EINVAL;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       upd64083_write(sd, reg->reg & 0xff, reg->val & 0xff);
+       return 0;
+}
 #endif
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg,
-                               V4L2_IDENT_UPD64083, 0);
+static int upd64083_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_UPD64083, 0);
+}
 
-       default:
-               break;
-       }
+static int upd64083_log_status(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 buf[7];
 
+       i2c_master_recv(client, buf, 7);
+       v4l2_info(sd, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x "
+                     "SA04=%02x SA05=%02x SA06=%02x\n",
+               buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
        return 0;
 }
 
+static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops upd64083_core_ops = {
+       .log_status = upd64083_log_status,
+       .g_chip_ident = upd64083_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = upd64083_g_register,
+       .s_register = upd64083_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops upd64083_video_ops = {
+       .s_routing = upd64083_s_routing,
+};
+
+static const struct v4l2_subdev_ops upd64083_ops = {
+       .core = &upd64083_core_ops,
+       .video = &upd64083_video_ops,
+};
+
 /* ------------------------------------------------------------------------ */
 
 /* i2c implementation */
@@ -176,6 +199,7 @@ static int upd64083_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
        struct upd64083_state *state;
+       struct v4l2_subdev *sd;
        int i;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -187,19 +211,23 @@ static int upd64083_probe(struct i2c_client *client,
        state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
-       i2c_set_clientdata(client, state);
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &upd64083_ops);
        /* Initially assume that a ghost reduction chip is present */
        state->mode = 0;  /* YCS mode */
        state->ext_y_adc = (1 << 5);
        memcpy(state->regs, upd64083_init, TOT_REGS);
        for (i = 0; i < TOT_REGS; i++)
-               upd64083_write(client, i, state->regs[i]);
+               upd64083_write(sd, i, state->regs[i]);
        return 0;
 }
 
 static int upd64083_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index c710bcd1df48a7ba8f122c8ff3efce75af9b7488..f8d85ddb48048b6eb320d2cabdcdd5f929a5ea2c 100644 (file)
@@ -3779,11 +3779,11 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
                        err("Alternate settings have different endpoint addresses!");
                        return -ENODEV;
                }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+               if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
                        err("Interface %d. has non-ISO endpoint!", ifnum);
                        return -ENODEV;
                }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+               if (usb_endpoint_dir_out(endpoint)) {
                        err("Interface %d. has ISO OUT endpoint!", ifnum);
                        return -ENODEV;
                }
index da27a5287983f79716bf61543b1cfe834d03188a..90f0ce6a26bc017de47bc3f8bb8c762121abf001 100644 (file)
@@ -823,12 +823,12 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id
                        err("Alternate settings have different endpoint addresses!");
                        return -ENODEV;
                }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+               if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
                        err("Interface %d. has non-ISO endpoint!",
                            interface->desc.bInterfaceNumber);
                        return -ENODEV;
                }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+               if (usb_endpoint_dir_out(endpoint)) {
                        err("Interface %d. has ISO OUT endpoint!",
                            interface->desc.bInterfaceNumber);
                        return -ENODEV;
index 4459b8a7f818775359ebecdef1926fe211cd27a9..fd112f0b9d35e7082b113c37ca549c59d547c546 100644 (file)
@@ -447,7 +447,7 @@ static int qcm_sensor_init(struct uvd *uvd)
        CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
                                cpu_to_le16(ISOC_PACKET_SIZE)));
        CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
-       CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+       CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143f, 0x01));
 
        CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
 
@@ -955,8 +955,7 @@ static int qcm_probe(struct usb_interface *intf,
                for (j=0; j < interface->desc.bNumEndpoints; j++) {
                        endpoint = &interface->endpoint[j].desc;
 
-                       if ((endpoint->bEndpointAddress &
-                               USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+                       if (usb_endpoint_dir_out(endpoint))
                                continue; /* not input then not good */
 
                        buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
@@ -965,9 +964,7 @@ static int qcm_probe(struct usb_interface *intf,
                                continue; /* 0 pkt size is not what we want */
                        }
 
-                       if ((endpoint->bmAttributes &
-                               USB_ENDPOINT_XFERTYPE_MASK) ==
-                               USB_ENDPOINT_XFER_ISOC) {
+                       if (usb_endpoint_xfer_isoc(endpoint)) {
                                video_ep = endpoint->bEndpointAddress;
                                /* break out of the search */
                                goto good_videoep;
index 9714baab7833b61a696ce5120427c42c0a9aa7cd..839a08240c2579f96768e0d544b13e873f857b51 100644 (file)
@@ -556,12 +556,12 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id
                        err("Alternate settings have different endpoint addresses!");
                        return -ENODEV;
                }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+               if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
                        err("Interface %d. has non-ISO endpoint!",
                            interface->desc.bInterfaceNumber);
                        return -ENODEV;
                }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+               if (usb_endpoint_dir_out(endpoint)) {
                        err("Interface %d. has ISO OUT endpoint!",
                            interface->desc.bInterfaceNumber);
                        return -ENODEV;
index 7c575bb8184fd6a95c80750f7a3f795afc5f6a24..148a1f98c70f714e46f0af650a49268f5d07ae59 100644 (file)
@@ -1123,7 +1123,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
        if (uvd->debug > 1)
                dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
 
-       if (0 < usbvideo_ClientIncModCount(uvd))
+       if (usbvideo_ClientIncModCount(uvd) < 0)
                return -ENODEV;
        mutex_lock(&uvd->lock);
 
@@ -1281,8 +1281,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
  * History:
  * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
  */
-static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
+static int usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct uvd *uvd = file->private_data;
 
@@ -1505,7 +1504,7 @@ static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
 static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
+       return video_usercopy(file, cmd, arg, usbvideo_v4l_do_ioctl);
 }
 
 /*
index 8e2d58bec48120c1991c78fd3f8be963c5095f47..4602597ed8d1af301b198dfb7dfe8f97994f5614 100644 (file)
@@ -844,8 +844,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
               interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
        endpoint = &interface->endpoint[0].desc;
 
-       if ((endpoint->bEndpointAddress & 0x80) &&
-           ((endpoint->bmAttributes & 3) == 0x02)) {
+       if (usb_endpoint_is_bulk_in(endpoint)) {
                /* we found a bulk in endpoint */
                bulkEndpoint = endpoint->bEndpointAddress;
        } else {
index d185b57fdcd0eb11108f9e2a482c6e869227f24e..85661b1848fe5cb52111c50b65b56c93372070b8 100644 (file)
@@ -523,7 +523,7 @@ static int vidioc_querycap (struct file *file, void  *priv,
        strlcpy(vc->card,
                usbvision_device_data[usbvision->DevModel].ModelString,
                sizeof(vc->card));
-       strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+       strlcpy(vc->bus_info, dev_name(&usbvision->dev->dev),
                sizeof(vc->bus_info));
        vc->version = USBVISION_DRIVER_VERSION;
        vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
@@ -1278,7 +1278,7 @@ static int usbvision_vbi_close(struct inode *inode, struct file *file)
        return -ENODEV;
 }
 
-static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
+static int usbvision_do_vbi_ioctl(struct file *file,
                                 unsigned int cmd, void *arg)
 {
        /* TODO */
@@ -1288,7 +1288,7 @@ static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
 static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl);
+       return video_usercopy(file, cmd, arg, usbvision_do_vbi_ioctl);
 }
 
 
@@ -1679,7 +1679,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
                interface = &dev->actconfig->interface[ifnum]->altsetting[0];
        }
        endpoint = &interface->endpoint[1].desc;
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+       if (usb_endpoint_type(endpoint) !=
            USB_ENDPOINT_XFER_ISOC) {
                err("%s: interface %d. has non-ISO endpoint!",
                    __func__, ifnum);
@@ -1687,8 +1687,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
                    __func__, endpoint->bmAttributes);
                return -ENODEV;
        }
-       if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
-           USB_DIR_OUT) {
+       if (usb_endpoint_dir_out(endpoint)) {
                err("%s: interface %d. has ISO OUT endpoint!",
                    __func__, ifnum);
                return -ENODEV;
index f16aafe9cf145a6cbbdc44af3451649939573968..2208165aa6f0c27db68994b1f3dacce55912fc26 100644 (file)
@@ -327,6 +327,31 @@ static struct uvc_menu_info exposure_auto_controls[] = {
        { 8, "Aperture Priority Mode" },
 };
 
+static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
+       __u8 query, const __u8 *data)
+{
+       __s8 zoom = (__s8)data[0];
+
+       switch (query) {
+       case GET_CUR:
+               return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
+
+       case GET_MIN:
+       case GET_MAX:
+       case GET_RES:
+       case GET_DEF:
+       default:
+               return data[2];
+       }
+}
+
+static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
+       __s32 value, __u8 *data)
+{
+       data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+       data[2] = min(abs(value), 0xff);
+}
+
 static struct uvc_control_mapping uvc_ctrl_mappings[] = {
        {
                .id             = V4L2_CID_BRIGHTNESS,
@@ -532,6 +557,38 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
                .data_type      = UVC_CTRL_DATA_TYPE_BOOLEAN,
        },
+       {
+               .id             = V4L2_CID_ZOOM_ABSOLUTE,
+               .name           = "Zoom, Absolute",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_ZOOM_ABSOLUTE_CONTROL,
+               .size           = 16,
+               .offset         = 0,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_UNSIGNED,
+       },
+       {
+               .id             = V4L2_CID_ZOOM_CONTINUOUS,
+               .name           = "Zoom, Continuous",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_ZOOM_RELATIVE_CONTROL,
+               .size           = 0,
+               .offset         = 0,
+               .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
+               .data_type      = UVC_CTRL_DATA_TYPE_SIGNED,
+               .get            = uvc_ctrl_get_zoom,
+               .set            = uvc_ctrl_set_zoom,
+       },
+       {
+               .id             = V4L2_CID_PRIVACY,
+               .name           = "Privacy",
+               .entity         = UVC_GUID_UVC_CAMERA,
+               .selector       = CT_PRIVACY_CONTROL,
+               .size           = 1,
+               .offset         = 0,
+               .v4l2_type      = V4L2_CTRL_TYPE_BOOLEAN,
+               .data_type      = UVC_CTRL_DATA_TYPE_BOOLEAN,
+       },
 };
 
 /* ------------------------------------------------------------------------
@@ -543,18 +600,23 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
        return ctrl->data + id * ctrl->info->size;
 }
 
-static inline int uvc_get_bit(const __u8 *data, int bit)
+static inline int uvc_test_bit(const __u8 *data, int bit)
 {
        return (data[bit >> 3] >> (bit & 7)) & 1;
 }
 
+static inline void uvc_clear_bit(__u8 *data, int bit)
+{
+       data[bit >> 3] &= ~(1 << (bit & 7));
+}
+
 /* Extract the bit string specified by mapping->offset and mapping->size
  * from the little-endian data stored at 'data' and return the result as
  * a signed 32bit integer. Sign extension will be performed if the mapping
  * references a signed data type.
  */
-static __s32 uvc_get_le_value(const __u8 *data,
-       struct uvc_control_mapping *mapping)
+static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
+       __u8 query, const __u8 *data)
 {
        int bits = mapping->size;
        int offset = mapping->offset;
@@ -583,8 +645,8 @@ static __s32 uvc_get_le_value(const __u8 *data,
 /* Set the bit string specified by mapping->offset and mapping->size
  * in the little-endian data stored at 'data' to the value 'value'.
  */
-static void uvc_set_le_value(__s32 value, __u8 *data,
-       struct uvc_control_mapping *mapping)
+static void uvc_set_le_value(struct uvc_control_mapping *mapping,
+       __s32 value, __u8 *data)
 {
        int bits = mapping->size;
        int offset = mapping->offset;
@@ -736,7 +798,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
                                video->dev->intfnum, ctrl->info->selector,
                                data, ctrl->info->size)) < 0)
                        goto out;
-               v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+               v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
        }
 
        switch (mapping->v4l2_type) {
@@ -772,21 +834,21 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
                                video->dev->intfnum, ctrl->info->selector,
                                data, ctrl->info->size)) < 0)
                        goto out;
-               v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+               v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
        }
        if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
                if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
                                video->dev->intfnum, ctrl->info->selector,
                                data, ctrl->info->size)) < 0)
                        goto out;
-               v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+               v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
        }
        if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
                if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
                                video->dev->intfnum, ctrl->info->selector,
                                data, ctrl->info->size)) < 0)
                        goto out;
-               v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+               v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
        }
 
        ret = 0;
@@ -923,8 +985,8 @@ int uvc_ctrl_get(struct uvc_video_device *video,
                ctrl->loaded = 1;
        }
 
-       xctrl->value = uvc_get_le_value(
-               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+       xctrl->value = mapping->get(mapping, GET_CUR,
+               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
 
        if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
                menu = mapping->menu_info;
@@ -980,8 +1042,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
                       ctrl->info->size);
        }
 
-       uvc_set_le_value(value,
-               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+       mapping->set(mapping, value,
+               uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
 
        ctrl->dirty = 1;
        ctrl->modified = 1;
@@ -1257,6 +1319,11 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
        struct uvc_control_mapping *map;
        int ret = -EINVAL;
 
+       if (mapping->get == NULL)
+               mapping->get = uvc_get_le_value;
+       if (mapping->set == NULL)
+               mapping->set = uvc_set_le_value;
+
        if (mapping->id & ~V4L2_CTRL_ID_MASK) {
                uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
                        "invalid control id 0x%08x\n", mapping->name,
@@ -1305,6 +1372,51 @@ end:
        return ret;
 }
 
+/*
+ * Prune an entity of its bogus controls. This currently includes processing
+ * unit auto controls for which no corresponding manual control is available.
+ * Such auto controls make little sense if any, and are known to crash at
+ * least the SiGma Micro webcam.
+ */
+static void
+uvc_ctrl_prune_entity(struct uvc_entity *entity)
+{
+       static const struct {
+               u8 idx_manual;
+               u8 idx_auto;
+       } blacklist[] = {
+               { 2, 11 }, /* Hue */
+               { 6, 12 }, /* White Balance Temperature */
+               { 7, 13 }, /* White Balance Component */
+       };
+
+       u8 *controls;
+       unsigned int size;
+       unsigned int i;
+
+       if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+               return;
+
+       controls = entity->processing.bmControls;
+       size = entity->processing.bControlSize;
+
+       for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+               if (blacklist[i].idx_auto >= 8 * size ||
+                   blacklist[i].idx_manual >= 8 * size)
+                       continue;
+
+               if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
+                    uvc_test_bit(controls, blacklist[i].idx_manual))
+                       continue;
+
+               uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
+                       "matching manual control, removing it.\n", entity->id,
+                       blacklist[i].idx_auto);
+
+               uvc_clear_bit(controls, blacklist[i].idx_auto);
+       }
+}
+
 /*
  * Initialize device controls.
  */
@@ -1331,6 +1443,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                        bControlSize = entity->camera.bControlSize;
                }
 
+               if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
+                       uvc_ctrl_prune_entity(entity);
+
                for (i = 0; i < bControlSize; ++i)
                        ncontrols += hweight8(bmControls[i]);
 
@@ -1345,7 +1460,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 
                ctrl = entity->controls;
                for (i = 0; i < bControlSize * 8; ++i) {
-                       if (uvc_get_bit(bmControls, i) == 0)
+                       if (uvc_test_bit(bmControls, i) == 0)
                                continue;
 
                        ctrl->entity = entity;
index d7ad060640bc5758fd526d7864fc94adcab8a52c..89d8bd10a8521b6c108d219470bdebf7850d6651 100644 (file)
@@ -12,8 +12,8 @@
  */
 
 /*
- * This driver aims to support video input devices compliant with the 'USB
- * Video Class' specification.
+ * This driver aims to support video input and ouput devices compliant with the
+ * 'USB Video Class' specification.
  *
  * The driver doesn't support the deprecated v4l1 interface. It implements the
  * mmap capture method only, and doesn't do any image format conversion in
@@ -32,6 +32,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <asm/atomic.h>
+#include <asm/unaligned.h>
 
 #include <media/v4l2-common.h>
 
@@ -43,6 +44,7 @@
 #define DRIVER_VERSION         "v0.1.0"
 #endif
 
+unsigned int uvc_no_drop_param;
 static unsigned int uvc_quirks_param;
 unsigned int uvc_trace_param;
 
@@ -288,8 +290,10 @@ static int uvc_parse_format(struct uvc_device *dev,
        struct uvc_format_desc *fmtdesc;
        struct uvc_frame *frame;
        const unsigned char *start = buffer;
+       unsigned char *_buffer;
        unsigned int interval;
        unsigned int i, n;
+       int _buflen;
        __u8 ftype;
 
        format->type = buffer[2];
@@ -410,12 +414,20 @@ static int uvc_parse_format(struct uvc_device *dev,
        buflen -= buffer[0];
        buffer += buffer[0];
 
+       /* Count the number of frame descriptors to test the bFrameIndex
+        * field when parsing the descriptors. We can't rely on the
+        * bNumFrameDescriptors field as some cameras don't initialize it
+        * properly.
+        */
+       for (_buflen = buflen, _buffer = buffer;
+            _buflen > 2 && _buffer[2] == ftype;
+            _buflen -= _buffer[0], _buffer += _buffer[0])
+               format->nframes++;
+
        /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
         * based formats have frame descriptors.
         */
        while (buflen > 2 && buffer[2] == ftype) {
-               frame = &format->frame[format->nframes];
-
                if (ftype != VS_FRAME_FRAME_BASED)
                        n = buflen > 25 ? buffer[25] : 0;
                else
@@ -430,22 +442,32 @@ static int uvc_parse_format(struct uvc_device *dev,
                        return -EINVAL;
                }
 
+               if (buffer[3] - 1 >= format->nframes) {
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                              "interface %d frame index %u out of range\n",
+                              dev->udev->devnum, alts->desc.bInterfaceNumber,
+                              buffer[3]);
+                       return -EINVAL;
+               }
+
+               frame = &format->frame[buffer[3] - 1];
+
                frame->bFrameIndex = buffer[3];
                frame->bmCapabilities = buffer[4];
-               frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]);
-               frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]);
-               frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]);
-               frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]);
+               frame->wWidth = get_unaligned_le16(&buffer[5]);
+               frame->wHeight = get_unaligned_le16(&buffer[7]);
+               frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
+               frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
                if (ftype != VS_FRAME_FRAME_BASED) {
                        frame->dwMaxVideoFrameBufferSize =
-                               le32_to_cpup((__le32 *)&buffer[17]);
+                               get_unaligned_le32(&buffer[17]);
                        frame->dwDefaultFrameInterval =
-                               le32_to_cpup((__le32 *)&buffer[21]);
+                               get_unaligned_le32(&buffer[21]);
                        frame->bFrameIntervalType = buffer[25];
                } else {
                        frame->dwMaxVideoFrameBufferSize = 0;
                        frame->dwDefaultFrameInterval =
-                               le32_to_cpup((__le32 *)&buffer[17]);
+                               get_unaligned_le32(&buffer[17]);
                        frame->bFrameIntervalType = buffer[21];
                }
                frame->dwFrameInterval = *intervals;
@@ -468,7 +490,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                 * some other divisions by zero which could happen.
                 */
                for (i = 0; i < n; ++i) {
-                       interval = le32_to_cpup((__le32 *)&buffer[26+4*i]);
+                       interval = get_unaligned_le32(&buffer[26+4*i]);
                        *(*intervals)++ = interval ? interval : 1;
                }
 
@@ -486,7 +508,6 @@ static int uvc_parse_format(struct uvc_device *dev,
                        10000000/frame->dwDefaultFrameInterval,
                        (100000000/frame->dwDefaultFrameInterval)%10);
 
-               format->nframes++;
                buflen -= buffer[0];
                buffer += buffer[0];
        }
@@ -588,46 +609,55 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        }
 
        /* Parse the header descriptor. */
-       if (buffer[2] == VS_OUTPUT_HEADER) {
+       switch (buffer[2]) {
+       case VS_OUTPUT_HEADER:
+               streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+               size = 9;
+               break;
+
+       case VS_INPUT_HEADER:
+               streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               size = 13;
+               break;
+
+       default:
                uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
-                       "%d OUTPUT HEADER descriptor is not supported.\n",
-                       dev->udev->devnum, alts->desc.bInterfaceNumber);
+                       "%d HEADER descriptor not found.\n", dev->udev->devnum,
+                       alts->desc.bInterfaceNumber);
                goto error;
-       } else if (buffer[2] == VS_INPUT_HEADER) {
-               p = buflen >= 5 ? buffer[3] : 0;
-               n = buflen >= 12 ? buffer[12] : 0;
+       }
 
-               if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
-                               "interface %d INPUT HEADER descriptor is "
-                               "invalid.\n", dev->udev->devnum,
-                               alts->desc.bInterfaceNumber);
-                       goto error;
-               }
+       p = buflen >= 4 ? buffer[3] : 0;
+       n = buflen >= size ? buffer[size-1] : 0;
+
+       if (buflen < size + p*n) {
+               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+                       "interface %d HEADER descriptor is invalid.\n",
+                       dev->udev->devnum, alts->desc.bInterfaceNumber);
+               goto error;
+       }
 
-               streaming->header.bNumFormats = p;
-               streaming->header.bEndpointAddress = buffer[6];
+       streaming->header.bNumFormats = p;
+       streaming->header.bEndpointAddress = buffer[6];
+       if (buffer[2] == VS_INPUT_HEADER) {
                streaming->header.bmInfo = buffer[7];
                streaming->header.bTerminalLink = buffer[8];
                streaming->header.bStillCaptureMethod = buffer[9];
                streaming->header.bTriggerSupport = buffer[10];
                streaming->header.bTriggerUsage = buffer[11];
-               streaming->header.bControlSize = n;
-
-               streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
-               if (streaming->header.bmaControls == NULL) {
-                       ret = -ENOMEM;
-                       goto error;
-               }
-
-               memcpy(streaming->header.bmaControls, &buffer[13], p*n);
        } else {
-               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
-                       "%d HEADER descriptor not found.\n", dev->udev->devnum,
-                       alts->desc.bInterfaceNumber);
+               streaming->header.bTerminalLink = buffer[7];
+       }
+       streaming->header.bControlSize = n;
+
+       streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+       if (streaming->header.bmaControls == NULL) {
+               ret = -ENOMEM;
                goto error;
        }
 
+       memcpy(streaming->header.bmaControls, &buffer[size], p*n);
+
        buflen -= buffer[0];
        buffer += buffer[0];
 
@@ -813,8 +843,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
                unit->type = VC_EXTENSION_UNIT;
                memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
                unit->extension.bNumControls = buffer[20];
-               unit->extension.bNrInPins =
-                       le16_to_cpup((__le16 *)&buffer[21]);
+               unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
                unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
                memcpy(unit->extension.baSourceID, &buffer[22], p);
                unit->extension.bControlSize = buffer[22+p];
@@ -858,8 +887,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                        return -EINVAL;
                }
 
-               dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]);
-               dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]);
+               dev->uvc_version = get_unaligned_le16(&buffer[3]);
+               dev->clock_frequency = get_unaligned_le32(&buffer[7]);
 
                /* Parse all USB Video Streaming interfaces. */
                for (i = 0; i < n; ++i) {
@@ -886,7 +915,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                /* Make sure the terminal type MSB is not null, otherwise it
                 * could be confused with a unit.
                 */
-               type = le16_to_cpup((__le16 *)&buffer[4]);
+               type = get_unaligned_le16(&buffer[4]);
                if ((type & 0xff00) == 0) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                                "interface %d INPUT_TERMINAL %d has invalid "
@@ -928,11 +957,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                        term->camera.bControlSize = n;
                        term->camera.bmControls = (__u8 *)term + sizeof *term;
                        term->camera.wObjectiveFocalLengthMin =
-                               le16_to_cpup((__le16 *)&buffer[8]);
+                               get_unaligned_le16(&buffer[8]);
                        term->camera.wObjectiveFocalLengthMax =
-                               le16_to_cpup((__le16 *)&buffer[10]);
+                               get_unaligned_le16(&buffer[10]);
                        term->camera.wOcularFocalLength =
-                               le16_to_cpup((__le16 *)&buffer[12]);
+                               get_unaligned_le16(&buffer[12]);
                        memcpy(term->camera.bmControls, &buffer[15], n);
                } else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
                        term->media.bControlSize = n;
@@ -968,7 +997,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                /* Make sure the terminal type MSB is not null, otherwise it
                 * could be confused with a unit.
                 */
-               type = le16_to_cpup((__le16 *)&buffer[4]);
+               type = get_unaligned_le16(&buffer[4]);
                if ((type & 0xff00) == 0) {
                        uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
                                "interface %d OUTPUT_TERMINAL %d has invalid "
@@ -1042,7 +1071,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                unit->type = buffer[2];
                unit->processing.bSourceID = buffer[4];
                unit->processing.wMaxMultiplier =
-                       le16_to_cpup((__le16 *)&buffer[5]);
+                       get_unaligned_le16(&buffer[5]);
                unit->processing.bControlSize = buffer[7];
                unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
                memcpy(unit->processing.bmControls, &buffer[8], n);
@@ -1077,8 +1106,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
                unit->type = buffer[2];
                memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
                unit->extension.bNumControls = buffer[20];
-               unit->extension.bNrInPins =
-                       le16_to_cpup((__le16 *)&buffer[21]);
+               unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
                unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
                memcpy(unit->extension.baSourceID, &buffer[22], p);
                unit->extension.bControlSize = buffer[22+p];
@@ -1128,8 +1156,13 @@ next_descriptor:
                buffer += buffer[0];
        }
 
-       /* Check if the optional status endpoint is present. */
-       if (alts->desc.bNumEndpoints == 1) {
+       /* Check if the optional status endpoint is present. Built-in iSight
+        * webcams have an interrupt endpoint but spit proprietary data that
+        * don't conform to the UVC status endpoint messages. Don't try to
+        * handle the interrupt endpoint for those cameras.
+        */
+       if (alts->desc.bNumEndpoints == 1 &&
+           !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
                struct usb_host_endpoint *ep = &alts->endpoint[0];
                struct usb_endpoint_descriptor *desc = &ep->desc;
 
@@ -1234,6 +1267,26 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
                list_add_tail(&entity->chain, &video->iterms);
                break;
 
+       case TT_STREAMING:
+               if (uvc_trace_param & UVC_TRACE_PROBE)
+                       printk(" <- IT %d\n", entity->id);
+
+               if (!UVC_ENTITY_IS_ITERM(entity)) {
+                       uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
+                               "terminal %u.\n", entity->id);
+                       return -1;
+               }
+
+               if (video->sterm != NULL) {
+                       uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming "
+                               "entities in chain.\n");
+                       return -1;
+               }
+
+               list_add_tail(&entity->chain, &video->iterms);
+               video->sterm = entity;
+               break;
+
        default:
                uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
                        "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
@@ -1344,6 +1397,10 @@ static int uvc_scan_chain(struct uvc_video_device *video)
 
        entity = video->oterm;
        uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+
+       if (UVC_ENTITY_TYPE(entity) == TT_STREAMING)
+               video->sterm = entity;
+
        id = entity->output.bSourceID;
        while (id != 0) {
                prev = entity;
@@ -1372,8 +1429,11 @@ static int uvc_scan_chain(struct uvc_video_device *video)
                        return id;
        }
 
-       /* Initialize the video buffers queue. */
-       uvc_queue_init(&video->queue);
+       if (video->sterm == NULL) {
+               uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in "
+                       "chain.\n");
+               return -1;
+       }
 
        return 0;
 }
@@ -1384,7 +1444,8 @@ static int uvc_scan_chain(struct uvc_video_device *video)
  * The driver currently supports a single video device per control interface
  * only. The terminal and units must match the following structure:
  *
- * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_*
  *
  * The Extension Units, if present, must have a single input pin. The
  * Processing Unit and Extension Units can be in any order. Additional
@@ -1401,7 +1462,7 @@ static int uvc_register_video(struct uvc_device *dev)
        list_for_each_entry(term, &dev->entities, list) {
                struct uvc_streaming *streaming;
 
-               if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+               if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term))
                        continue;
 
                memset(&dev->video, 0, sizeof dev->video);
@@ -1414,7 +1475,8 @@ static int uvc_register_video(struct uvc_device *dev)
                        continue;
 
                list_for_each_entry(streaming, &dev->streaming, list) {
-                       if (streaming->header.bTerminalLink == term->id) {
+                       if (streaming->header.bTerminalLink ==
+                           dev->video.sterm->id) {
                                dev->video.streaming = streaming;
                                found = 1;
                                break;
@@ -1440,6 +1502,9 @@ static int uvc_register_video(struct uvc_device *dev)
                printk(" -> %d).\n", dev->video.oterm->id);
        }
 
+       /* Initialize the video buffers queue. */
+       uvc_queue_init(&dev->video.queue, dev->video.streaming->type);
+
        /* Initialize the streaming interface with default streaming
         * parameters.
         */
@@ -1707,24 +1772,6 @@ static int uvc_reset_resume(struct usb_interface *intf)
  * though they are compliant.
  */
 static struct usb_device_id uvc_ids[] = {
-       /* ALi M5606 (Clevo M540SR) */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x0402,
-         .idProduct            = 0x5606,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Creative Live! Optia */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x041e,
-         .idProduct            = 0x4057,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Microsoft Lifecam NX-6000 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1810,15 +1857,6 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* Silicon Motion SM371 */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x090c,
-         .idProduct            = 0xb371,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* MT6227 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1837,6 +1875,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Syntek (Samsung Q310) */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x174f,
+         .idProduct            = 0x5931,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_STREAM_NO_FID },
        /* Asus F9SG */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1855,6 +1902,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Lenovo Thinkpad SL500 */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x17ef,
+         .idProduct            = 0x480b,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_STREAM_NO_FID },
        /* Ecamm Pico iMage */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1884,106 +1940,8 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
-                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
-       /* Acer OEM Webcam - Unknown vendor */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0100,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Packard Bell OEM Webcam - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0101,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Acer Crystal Eye webcam - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0102,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Compaq Presario B1200 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0104,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Acer Travelmate 7720 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0105,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Medion Akoya Mini E1210 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0141,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Acer OrbiCam - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0200,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /*  Fujitsu Amilo SI2636 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0202,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /*  Advent 4211 - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0203,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0300,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
-       /* Clevo M570TU - Bison Electronics */
-       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
-                               | USB_DEVICE_ID_MATCH_INT_INFO,
-         .idVendor             = 0x5986,
-         .idProduct            = 0x0303,
-         .bInterfaceClass      = USB_CLASS_VIDEO,
-         .bInterfaceSubClass   = 1,
-         .bInterfaceProtocol   = 0,
-         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
+                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT
+                               | UVC_QUIRK_PRUNE_CONTROLS },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
        {}
@@ -2029,6 +1987,8 @@ static void __exit uvc_cleanup(void)
 module_init(uvc_init);
 module_exit(uvc_cleanup);
 
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
 module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(quirks, "Forced device quirks");
 module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
index 5646a6a329393ca9b2573c6de21f29f92805ba44..42546342e97d08b2f46263df98fbb07f02f18b97 100644 (file)
  *
  */
 
-void uvc_queue_init(struct uvc_video_queue *queue)
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
 {
        mutex_init(&queue->mutex);
        spin_lock_init(&queue->irqlock);
        INIT_LIST_HEAD(&queue->mainqueue);
        INIT_LIST_HEAD(&queue->irqqueue);
+       queue->type = type;
 }
 
 /*
@@ -132,7 +133,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
                queue->buffer[i].buf.index = i;
                queue->buffer[i].buf.m.offset = i * bufsize;
                queue->buffer[i].buf.length = buflength;
-               queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               queue->buffer[i].buf.type = queue->type;
                queue->buffer[i].buf.sequence = 0;
                queue->buffer[i].buf.field = V4L2_FIELD_NONE;
                queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
@@ -226,7 +227,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
 
        uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
 
-       if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+       if (v4l2_buf->type != queue->type ||
            v4l2_buf->memory != V4L2_MEMORY_MMAP) {
                uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
                        "and/or memory (%u).\n", v4l2_buf->type,
@@ -249,6 +250,13 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
                goto done;
        }
 
+       if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+           v4l2_buf->bytesused > buf->buf.length) {
+               uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+               ret = -EINVAL;
+               goto done;
+       }
+
        spin_lock_irqsave(&queue->irqlock, flags);
        if (queue->flags & UVC_QUEUE_DISCONNECTED) {
                spin_unlock_irqrestore(&queue->irqlock, flags);
@@ -256,7 +264,11 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
                goto done;
        }
        buf->state = UVC_BUF_STATE_QUEUED;
-       buf->buf.bytesused = 0;
+       if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               buf->buf.bytesused = 0;
+       else
+               buf->buf.bytesused = v4l2_buf->bytesused;
+
        list_add_tail(&buf->stream, &queue->mainqueue);
        list_add_tail(&buf->queue, &queue->irqqueue);
        spin_unlock_irqrestore(&queue->irqlock, flags);
@@ -289,7 +301,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
        struct uvc_buffer *buf;
        int ret = 0;
 
-       if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+       if (v4l2_buf->type != queue->type ||
            v4l2_buf->memory != V4L2_MEMORY_MMAP) {
                uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
                        "and/or memory (%u).\n", v4l2_buf->type,
@@ -397,6 +409,7 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
                }
                queue->sequence = 0;
                queue->flags |= UVC_QUEUE_STREAMING;
+               queue->buf_used = 0;
        } else {
                uvc_queue_cancel(queue, 0);
                INIT_LIST_HEAD(&queue->mainqueue);
index 758dfefaba8d3854e7b2ad22e57467d40edb68c0..afcc6934559e6f7c5f819fd74efb6b0f2c488e63 100644 (file)
@@ -110,7 +110,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
        int ret = 0;
        __u8 *fcc;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fmt->type != video->streaming->type)
                return -EINVAL;
 
        fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -216,7 +216,7 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
        struct uvc_format *format = video->streaming->cur_format;
        struct uvc_frame *frame = video->streaming->cur_frame;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fmt->type != video->streaming->type)
                return -EINVAL;
 
        if (format == NULL || frame == NULL)
@@ -242,7 +242,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
        struct uvc_frame *frame;
        int ret;
 
-       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (fmt->type != video->streaming->type)
                return -EINVAL;
 
        if (uvc_queue_streaming(&video->queue))
@@ -252,9 +252,6 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
        if (ret < 0)
                return ret;
 
-       if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
-               return ret;
-
        memcpy(&video->streaming->ctrl, &probe, sizeof probe);
        video->streaming->cur_format = format;
        video->streaming->cur_frame = frame;
@@ -267,7 +264,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
 {
        uint32_t numerator, denominator;
 
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (parm->type != video->streaming->type)
                return -EINVAL;
 
        numerator = video->streaming->ctrl.dwFrameInterval;
@@ -275,13 +272,21 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
        uvc_simplify_fraction(&numerator, &denominator, 8, 333);
 
        memset(parm, 0, sizeof *parm);
-       parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-       parm->parm.capture.capturemode = 0;
-       parm->parm.capture.timeperframe.numerator = numerator;
-       parm->parm.capture.timeperframe.denominator = denominator;
-       parm->parm.capture.extendedmode = 0;
-       parm->parm.capture.readbuffers = 0;
+       parm->type = video->streaming->type;
+
+       if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               parm->parm.capture.capturemode = 0;
+               parm->parm.capture.timeperframe.numerator = numerator;
+               parm->parm.capture.timeperframe.denominator = denominator;
+               parm->parm.capture.extendedmode = 0;
+               parm->parm.capture.readbuffers = 0;
+       } else {
+               parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+               parm->parm.output.outputmode = 0;
+               parm->parm.output.timeperframe.numerator = numerator;
+               parm->parm.output.timeperframe.denominator = denominator;
+       }
 
        return 0;
 }
@@ -291,42 +296,45 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
 {
        struct uvc_frame *frame = video->streaming->cur_frame;
        struct uvc_streaming_control probe;
+       struct v4l2_fract timeperframe;
        uint32_t interval;
        int ret;
 
-       if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+       if (parm->type != video->streaming->type)
                return -EINVAL;
 
        if (uvc_queue_streaming(&video->queue))
                return -EBUSY;
 
+       if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               timeperframe = parm->parm.capture.timeperframe;
+       else
+               timeperframe = parm->parm.output.timeperframe;
+
        memcpy(&probe, &video->streaming->ctrl, sizeof probe);
-       interval = uvc_fraction_to_interval(
-                       parm->parm.capture.timeperframe.numerator,
-                       parm->parm.capture.timeperframe.denominator);
+       interval = uvc_fraction_to_interval(timeperframe.numerator,
+               timeperframe.denominator);
 
        uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
-                       parm->parm.capture.timeperframe.numerator,
-                       parm->parm.capture.timeperframe.denominator,
-                       interval);
+               timeperframe.numerator, timeperframe.denominator, interval);
        probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
 
        /* Probe the device with the new settings. */
        if ((ret = uvc_probe_video(video, &probe)) < 0)
                return ret;
 
-       /* Commit the new settings. */
-       if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
-               return ret;
-
        memcpy(&video->streaming->ctrl, &probe, sizeof probe);
 
        /* Return the actual frame period. */
-       parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
-       parm->parm.capture.timeperframe.denominator = 10000000;
-       uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
-                               &parm->parm.capture.timeperframe.denominator,
-                               8, 333);
+       timeperframe.numerator = probe.dwFrameInterval;
+       timeperframe.denominator = 10000000;
+       uvc_simplify_fraction(&timeperframe.numerator,
+               &timeperframe.denominator, 8, 333);
+
+       if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               parm->parm.capture.timeperframe = timeperframe;
+       else
+               parm->parm.output.timeperframe = timeperframe;
 
        return 0;
 }
@@ -464,17 +472,13 @@ static int uvc_v4l2_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int __uvc_v4l2_do_ioctl(struct file *file,
-                    unsigned int cmd, void *arg)
+static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *vdev = video_devdata(file);
        struct uvc_video_device *video = video_get_drvdata(vdev);
        struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
        int ret = 0;
 
-       if (uvc_trace_param & UVC_TRACE_IOCTL)
-               v4l_printk_ioctl(cmd);
-
        switch (cmd) {
        /* Query capabilities */
        case VIDIOC_QUERYCAP:
@@ -487,8 +491,12 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
                strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
                        sizeof cap->bus_info);
                cap->version = DRIVER_VERSION_NUMBER;
-               cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
-                                 | V4L2_CAP_STREAMING;
+               if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+                                         | V4L2_CAP_STREAMING;
+               else
+                       cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
+                                         | V4L2_CAP_STREAMING;
                break;
        }
 
@@ -666,7 +674,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
                struct v4l2_fmtdesc *fmt = arg;
                struct uvc_format *format;
 
-               if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+               if (fmt->type != video->streaming->type ||
                    fmt->index >= video->streaming->nformats)
                        return -EINVAL;
 
@@ -805,7 +813,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
                struct v4l2_cropcap *ccap = arg;
                struct uvc_frame *frame = video->streaming->cur_frame;
 
-               if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (ccap->type != video->streaming->type)
                        return -EINVAL;
 
                ccap->bounds.left = 0;
@@ -831,7 +839,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
                unsigned int bufsize =
                        video->streaming->ctrl.dwMaxVideoFrameSize;
 
-               if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+               if (rb->type != video->streaming->type ||
                    rb->memory != V4L2_MEMORY_MMAP)
                        return -EINVAL;
 
@@ -851,7 +859,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
        {
                struct v4l2_buffer *buf = arg;
 
-               if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (buf->type != video->streaming->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
@@ -877,7 +885,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
        {
                int *type = arg;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (*type != video->streaming->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
@@ -892,7 +900,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
        {
                int *type = arg;
 
-               if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               if (*type != video->streaming->type)
                        return -EINVAL;
 
                if (!uvc_has_privileges(handle))
@@ -925,7 +933,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               info = kmalloc(sizeof *info, GFP_KERNEL);
+               info = kzalloc(sizeof *info, GFP_KERNEL);
                if (info == NULL)
                        return -ENOMEM;
 
@@ -952,7 +960,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 
-               map = kmalloc(sizeof *map, GFP_KERNEL);
+               map = kzalloc(sizeof *map, GFP_KERNEL);
                if (map == NULL)
                        return -ENOMEM;
 
@@ -979,7 +987,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
 
        default:
                if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
-                       __uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+                       uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
                        uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
                                  cmd);
                return ret;
@@ -988,17 +996,16 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
        return ret;
 }
 
-static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg)
-{
-       return __uvc_v4l2_do_ioctl(file, cmd, arg);
-}
-
 static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
-       uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
-       return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl);
+       if (uvc_trace_param & UVC_TRACE_IOCTL) {
+               uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl(");
+               v4l_printk_ioctl(cmd);
+               printk(")\n");
+       }
+
+       return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
 }
 
 static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
index b7bb23820d803013548ef99ce91ccd52039102fb..e7c31995527f3d520d50283b8246e5cc5a312b6c 100644 (file)
@@ -36,15 +36,22 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
 {
        __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
        unsigned int pipe;
-       int ret;
 
        pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
                              : usb_sndctrlpipe(dev->udev, 0);
        type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
 
-       ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+       return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
                        unit << 8 | intfnum, data, size, timeout);
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+                       __u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+       int ret;
 
+       ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+                               UVC_CTRL_CONTROL_TIMEOUT);
        if (ret != size) {
                uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
                        "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
@@ -55,13 +62,6 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
        return 0;
 }
 
-int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
-                       __u8 intfnum, __u8 cs, void *data, __u16 size)
-{
-       return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
-                               UVC_CTRL_CONTROL_TIMEOUT);
-}
-
 static void uvc_fixup_buffer_size(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl)
 {
@@ -102,8 +102,36 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
        ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
                probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                UVC_CTRL_STREAMING_TIMEOUT);
-       if (ret < 0)
+
+       if ((query == GET_MIN || query == GET_MAX) && ret == 2) {
+               /* Some cameras, mostly based on Bison Electronics chipsets,
+                * answer a GET_MIN or GET_MAX request with the wCompQuality
+                * field only.
+                */
+               uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non "
+                       "compliance - GET_MIN/MAX(PROBE) incorrectly "
+                       "supported. Enabling workaround.\n");
+               memset(ctrl, 0, sizeof ctrl);
+               ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
+               ret = 0;
+               goto out;
+       } else if (query == GET_DEF && probe == 1) {
+               /* Many cameras don't support the GET_DEF request on their
+                * video probe control. Warn once and return, the caller will
+                * fall back to GET_CUR.
+                */
+               uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non "
+                       "compliance - GET_DEF(PROBE) not supported. "
+                       "Enabling workaround.\n");
+               ret = -EIO;
+               goto out;
+       } else if (ret != size) {
+               uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : "
+                       "%d (exp. %u).\n", query, probe ? "probe" : "commit",
+                       ret, size);
+               ret = -EIO;
                goto out;
+       }
 
        ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
        ctrl->bFormatIndex = data[2];
@@ -114,14 +142,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
        ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
        ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
        ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
-       ctrl->dwMaxVideoFrameSize =
-               le32_to_cpu(get_unaligned((__le32 *)&data[18]));
-       ctrl->dwMaxPayloadTransferSize =
-               le32_to_cpu(get_unaligned((__le32 *)&data[22]));
+       ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
+       ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
 
        if (size == 34) {
-               ctrl->dwClockFrequency =
-                       le32_to_cpu(get_unaligned((__le32 *)&data[26]));
+               ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
                ctrl->bmFramingInfo = data[30];
                ctrl->bPreferedVersion = data[31];
                ctrl->bMinVersion = data[32];
@@ -138,13 +163,14 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
         * Try to get the value from the format and frame descriptor.
         */
        uvc_fixup_buffer_size(video, ctrl);
+       ret = 0;
 
 out:
        kfree(data);
        return ret;
 }
 
-int uvc_set_video_ctrl(struct uvc_video_device *video,
+static int uvc_set_video_ctrl(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl, int probe)
 {
        __u8 *data;
@@ -168,14 +194,11 @@ int uvc_set_video_ctrl(struct uvc_video_device *video,
        /* Note: Some of the fields below are not required for IN devices (see
         * UVC spec, 4.3.1.1), but we still copy them in case support for OUT
         * devices is added in the future. */
-       put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize),
-               (__le32 *)&data[18]);
-       put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize),
-               (__le32 *)&data[22]);
+       put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
+       put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
 
        if (size == 34) {
-               put_unaligned(cpu_to_le32(ctrl->dwClockFrequency),
-                       (__le32 *)&data[26]);
+               put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
                data[30] = ctrl->bmFramingInfo;
                data[31] = ctrl->bPreferedVersion;
                data[32] = ctrl->bMinVersion;
@@ -186,6 +209,12 @@ int uvc_set_video_ctrl(struct uvc_video_device *video,
                video->streaming->intfnum,
                probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                UVC_CTRL_STREAMING_TIMEOUT);
+       if (ret != size) {
+               uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
+                       "%d (exp. %u).\n", probe ? "probe" : "commit",
+                       ret, size);
+               ret = -EIO;
+       }
 
        kfree(data);
        return ret;
@@ -252,6 +281,12 @@ done:
        return ret;
 }
 
+int uvc_commit_video(struct uvc_video_device *video,
+       struct uvc_streaming_control *probe)
+{
+       return uvc_set_video_ctrl(video, probe, 0);
+}
+
 /* ------------------------------------------------------------------------
  * Video codecs
  */
@@ -333,7 +368,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
 
        /* Synchronize to the input stream by waiting for the FID bit to be
         * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
-        * queue->last_fid is initialized to -1, so the first isochronous
+        * video->last_fid is initialized to -1, so the first isochronous
         * frame will always be in sync.
         *
         * If the device doesn't toggle the FID bit, invert video->last_fid
@@ -360,7 +395,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
         * last payload can be lost anyway). We thus must check if the FID has
         * been toggled.
         *
-        * queue->last_fid is initialized to -1, so the first isochronous
+        * video->last_fid is initialized to -1, so the first isochronous
         * frame will never trigger an end of frame detection.
         *
         * Empty buffers (bytesused == 0) don't trigger end of frame detection
@@ -418,6 +453,34 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
        }
 }
 
+static int uvc_video_encode_header(struct uvc_video_device *video,
+               struct uvc_buffer *buf, __u8 *data, int len)
+{
+       data[0] = 2;    /* Header length */
+       data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
+               | (video->last_fid & UVC_STREAM_FID);
+       return 2;
+}
+
+static int uvc_video_encode_data(struct uvc_video_device *video,
+               struct uvc_buffer *buf, __u8 *data, int len)
+{
+       struct uvc_video_queue *queue = &video->queue;
+       unsigned int nbytes;
+       void *mem;
+
+       /* Copy video data to the URB buffer. */
+       mem = queue->mem + buf->buf.m.offset + queue->buf_used;
+       nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+       nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size,
+                       nbytes);
+       memcpy(data, mem, nbytes);
+
+       queue->buf_used += nbytes;
+
+       return nbytes;
+}
+
 /* ------------------------------------------------------------------------
  * URB handling
  */
@@ -477,7 +540,7 @@ static void uvc_video_decode_bulk(struct urb *urb,
        /* If the URB is the first of its payload, decode and save the
         * header.
         */
-       if (video->bulk.header_size == 0) {
+       if (video->bulk.header_size == 0 && !video->bulk.skip_payload) {
                do {
                        ret = uvc_video_decode_start(video, buf, mem, len);
                        if (ret == -EAGAIN)
@@ -487,14 +550,13 @@ static void uvc_video_decode_bulk(struct urb *urb,
                /* If an error occured skip the rest of the payload. */
                if (ret < 0 || buf == NULL) {
                        video->bulk.skip_payload = 1;
-                       return;
-               }
+               } else {
+                       memcpy(video->bulk.header, mem, ret);
+                       video->bulk.header_size = ret;
 
-               video->bulk.header_size = ret;
-               memcpy(video->bulk.header, mem, video->bulk.header_size);
-
-               mem += ret;
-               len -= ret;
+                       mem += ret;
+                       len -= ret;
+               }
        }
 
        /* The buffer queue might have been cancelled while a bulk transfer
@@ -525,6 +587,48 @@ static void uvc_video_decode_bulk(struct urb *urb,
        }
 }
 
+static void uvc_video_encode_bulk(struct urb *urb,
+       struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+       u8 *mem = urb->transfer_buffer;
+       int len = video->urb_size, ret;
+
+       if (buf == NULL) {
+               urb->transfer_buffer_length = 0;
+               return;
+       }
+
+       /* If the URB is the first of its payload, add the header. */
+       if (video->bulk.header_size == 0) {
+               ret = uvc_video_encode_header(video, buf, mem, len);
+               video->bulk.header_size = ret;
+               video->bulk.payload_size += ret;
+               mem += ret;
+               len -= ret;
+       }
+
+       /* Process video data. */
+       ret = uvc_video_encode_data(video, buf, mem, len);
+
+       video->bulk.payload_size += ret;
+       len -= ret;
+
+       if (buf->buf.bytesused == video->queue.buf_used ||
+           video->bulk.payload_size == video->bulk.max_payload_size) {
+               if (buf->buf.bytesused == video->queue.buf_used) {
+                       video->queue.buf_used = 0;
+                       buf->state = UVC_BUF_STATE_DONE;
+                       uvc_queue_next_buffer(&video->queue, buf);
+                       video->last_fid ^= UVC_STREAM_FID;
+               }
+
+               video->bulk.header_size = 0;
+               video->bulk.payload_size = 0;
+       }
+
+       urb->transfer_buffer_length = video->urb_size - len;
+}
+
 static void uvc_video_complete(struct urb *urb)
 {
        struct uvc_video_device *video = urb->context;
@@ -722,7 +826,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
        if (uvc_alloc_urb_buffers(video, size) < 0)
                return -ENOMEM;
 
-       pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+       if (usb_endpoint_dir_in(&ep->desc))
+               pipe = usb_rcvbulkpipe(video->dev->udev,
+                                      ep->desc.bEndpointAddress);
+       else
+               pipe = usb_sndbulkpipe(video->dev->udev,
+                                      ep->desc.bEndpointAddress);
+
+       if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               size = 0;
 
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(0, gfp_flags);
@@ -854,7 +966,7 @@ int uvc_video_resume(struct uvc_video_device *video)
 
        video->frozen = 0;
 
-       if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) {
+       if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) {
                uvc_queue_enable(&video->queue, 0);
                return ret;
        }
@@ -935,23 +1047,30 @@ int uvc_video_init(struct uvc_video_device *video)
                        break;
        }
 
-       /* Commit the default settings. */
        probe->bFormatIndex = format->index;
        probe->bFrameIndex = frame->bFrameIndex;
-       if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
-               return ret;
 
        video->streaming->cur_format = format;
        video->streaming->cur_frame = frame;
        atomic_set(&video->active, 0);
 
        /* Select the video decoding function */
-       if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
-               video->decode = uvc_video_decode_isight;
-       else if (video->streaming->intf->num_altsetting > 1)
-               video->decode = uvc_video_decode_isoc;
-       else
-               video->decode = uvc_video_decode_bulk;
+       if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+                       video->decode = uvc_video_decode_isight;
+               else if (video->streaming->intf->num_altsetting > 1)
+                       video->decode = uvc_video_decode_isoc;
+               else
+                       video->decode = uvc_video_decode_bulk;
+       } else {
+               if (video->streaming->intf->num_altsetting == 1)
+                       video->decode = uvc_video_encode_bulk;
+               else {
+                       uvc_printk(KERN_INFO, "Isochronous endpoints are not "
+                               "supported for video output devices.\n");
+                       return -EINVAL;
+               }
+       }
 
        return 0;
 }
@@ -971,7 +1090,8 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
                return 0;
        }
 
-       if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)
+       if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+           uvc_no_drop_param)
                video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
        else
                video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
@@ -979,6 +1099,10 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
        if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
                return ret;
 
+       /* Commit the streaming parameters. */
+       if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0)
+               return ret;
+
        return uvc_init_video(video, GFP_KERNEL);
 }
 
index 9a6bc1aafb166bf5533f94494c7a71d68bdae7a1..896b791ece159565553804e8e2efb7db942820bc 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/kernel.h>
 #include <linux/videodev2.h>
 
-
 /*
  * Dynamic controls
  */
@@ -316,6 +315,7 @@ struct uvc_xu_control {
 #define UVC_QUIRK_BUILTIN_ISIGHT       0x00000008
 #define UVC_QUIRK_STREAM_NO_FID                0x00000010
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+#define UVC_QUIRK_PRUNE_CONTROLS       0x00000040
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
@@ -383,6 +383,11 @@ struct uvc_control_mapping {
 
        struct uvc_menu_info *menu_info;
        __u32 menu_count;
+
+       __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
+                     const __u8 *data);
+       void (*set) (struct uvc_control_mapping *mapping, __s32 value,
+                    __u8 *data);
 };
 
 struct uvc_control {
@@ -523,6 +528,7 @@ struct uvc_streaming {
        __u16 maxpsize;
 
        struct uvc_streaming_header header;
+       enum v4l2_buf_type type;
 
        unsigned int nformats;
        struct uvc_format *format;
@@ -558,12 +564,15 @@ struct uvc_buffer {
 #define UVC_QUEUE_DROP_INCOMPLETE      (1 << 2)
 
 struct uvc_video_queue {
+       enum v4l2_buf_type type;
+
        void *mem;
        unsigned int flags;
        __u32 sequence;
 
        unsigned int count;
        unsigned int buf_size;
+       unsigned int buf_used;
        struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
        struct mutex mutex;     /* protects buffers and mainqueue */
        spinlock_t irqlock;     /* protects irqqueue */
@@ -578,8 +587,9 @@ struct uvc_video_device {
        atomic_t active;
        unsigned int frozen : 1;
 
-       struct list_head iterms;
-       struct uvc_entity *oterm;
+       struct list_head iterms;                /* Input terminals */
+       struct uvc_entity *oterm;               /* Output terminal */
+       struct uvc_entity *sterm;               /* USB streaming terminal */
        struct uvc_entity *processing;
        struct uvc_entity *selector;
        struct list_head extensions;
@@ -617,6 +627,7 @@ enum uvc_device_state {
 struct uvc_device {
        struct usb_device *udev;
        struct usb_interface *intf;
+       unsigned long warnings;
        __u32 quirks;
        int intfnum;
        char name[32];
@@ -679,6 +690,10 @@ struct uvc_driver {
 #define UVC_TRACE_SUSPEND      (1 << 8)
 #define UVC_TRACE_STATUS       (1 << 9)
 
+#define UVC_WARN_MINMAX                0
+#define UVC_WARN_PROBE_DEF     1
+
+extern unsigned int uvc_no_drop_param;
 extern unsigned int uvc_trace_param;
 
 #define uvc_trace(flag, msg...) \
@@ -687,6 +702,12 @@ extern unsigned int uvc_trace_param;
                        printk(KERN_DEBUG "uvcvideo: " msg); \
        } while (0)
 
+#define uvc_warn_once(dev, warn, msg...) \
+       do { \
+               if (!test_and_set_bit(warn, &dev->warnings)) \
+                       printk(KERN_INFO "uvcvideo: " msg); \
+       } while (0)
+
 #define uvc_printk(level, msg...) \
        printk(level "uvcvideo: " msg)
 
@@ -709,7 +730,8 @@ extern struct uvc_driver uvc_driver;
 extern void uvc_delete(struct kref *kref);
 
 /* Video buffers queue management. */
-extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern void uvc_queue_init(struct uvc_video_queue *queue,
+               enum v4l2_buf_type type);
 extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
                unsigned int nbuffers, unsigned int buflength);
 extern int uvc_free_buffers(struct uvc_video_queue *queue);
@@ -740,10 +762,10 @@ extern int uvc_video_resume(struct uvc_video_device *video);
 extern int uvc_video_enable(struct uvc_video_device *video, int enable);
 extern int uvc_probe_video(struct uvc_video_device *video,
                struct uvc_streaming_control *probe);
+extern int uvc_commit_video(struct uvc_video_device *video,
+               struct uvc_streaming_control *ctrl);
 extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
                __u8 intfnum, __u8 cs, void *data, __u16 size);
-extern int uvc_set_video_ctrl(struct uvc_video_device *video,
-               struct uvc_streaming_control *ctrl, int probe);
 
 /* Status */
 extern int uvc_status_init(struct uvc_device *dev);
index 846763d7349e3ca73c3dc56f077da8bf98ca08c6..c676b0b0f708340f7644f69d3b6ceaab29fd8eea 100644 (file)
@@ -28,7 +28,7 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Author:     Alan Cox, <alan@redhat.com>
+ * Author:     Alan Cox, <alan@lxorguk.ukuu.org.uk>
  *
  * Fixes:
  */
@@ -58,6 +58,7 @@
 #include <asm/div64.h>
 #define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 
 #include <linux/videodev2.h>
@@ -320,6 +321,19 @@ const char **v4l2_ctrl_get_menu(u32 id)
                "Private packet, IVTV format",
                NULL
        };
+       static const char *camera_power_line_frequency[] = {
+               "Disabled",
+               "50 Hz",
+               "60 Hz",
+               NULL
+       };
+       static const char *camera_exposure_auto[] = {
+               "Auto Mode",
+               "Manual Mode",
+               "Shutter Priority Mode",
+               "Aperture Priority Mode",
+               NULL
+       };
 
        switch (id) {
                case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -352,6 +366,10 @@ const char **v4l2_ctrl_get_menu(u32 id)
                        return mpeg_stream_type;
                case V4L2_CID_MPEG_STREAM_VBI_FMT:
                        return mpeg_stream_vbi_fmt;
+               case V4L2_CID_POWER_LINE_FREQUENCY:
+                       return camera_power_line_frequency;
+               case V4L2_CID_EXPOSURE_AUTO:
+                       return camera_exposure_auto;
                default:
                        return NULL;
        }
@@ -363,17 +381,37 @@ const char *v4l2_ctrl_get_name(u32 id)
 {
        switch (id) {
        /* USER controls */
-       case V4L2_CID_USER_CLASS:       return "User Controls";
-       case V4L2_CID_AUDIO_VOLUME:     return "Volume";
-       case V4L2_CID_AUDIO_MUTE:       return "Mute";
-       case V4L2_CID_AUDIO_BALANCE:    return "Balance";
-       case V4L2_CID_AUDIO_BASS:       return "Bass";
-       case V4L2_CID_AUDIO_TREBLE:     return "Treble";
-       case V4L2_CID_AUDIO_LOUDNESS:   return "Loudness";
-       case V4L2_CID_BRIGHTNESS:       return "Brightness";
-       case V4L2_CID_CONTRAST:         return "Contrast";
-       case V4L2_CID_SATURATION:       return "Saturation";
-       case V4L2_CID_HUE:              return "Hue";
+       case V4L2_CID_USER_CLASS:               return "User Controls";
+       case V4L2_CID_AUDIO_VOLUME:             return "Volume";
+       case V4L2_CID_AUDIO_MUTE:               return "Mute";
+       case V4L2_CID_AUDIO_BALANCE:            return "Balance";
+       case V4L2_CID_AUDIO_BASS:               return "Bass";
+       case V4L2_CID_AUDIO_TREBLE:             return "Treble";
+       case V4L2_CID_AUDIO_LOUDNESS:           return "Loudness";
+       case V4L2_CID_BRIGHTNESS:               return "Brightness";
+       case V4L2_CID_CONTRAST:                 return "Contrast";
+       case V4L2_CID_SATURATION:               return "Saturation";
+       case V4L2_CID_HUE:                      return "Hue";
+       case V4L2_CID_BLACK_LEVEL:              return "Black Level";
+       case V4L2_CID_AUTO_WHITE_BALANCE:       return "White Balance, Automatic";
+       case V4L2_CID_DO_WHITE_BALANCE:         return "Do White Balance";
+       case V4L2_CID_RED_BALANCE:              return "Red Balance";
+       case V4L2_CID_BLUE_BALANCE:             return "Blue Balance";
+       case V4L2_CID_GAMMA:                    return "Gamma";
+       case V4L2_CID_EXPOSURE:                 return "Exposure";
+       case V4L2_CID_AUTOGAIN:                 return "Gain, Automatic";
+       case V4L2_CID_GAIN:                     return "Gain";
+       case V4L2_CID_HFLIP:                    return "Horizontal Flip";
+       case V4L2_CID_VFLIP:                    return "Vertical Flip";
+       case V4L2_CID_HCENTER:                  return "Horizontal Center";
+       case V4L2_CID_VCENTER:                  return "Vertical Center";
+       case V4L2_CID_POWER_LINE_FREQUENCY:     return "Power Line Frequency";
+       case V4L2_CID_HUE_AUTO:                 return "Hue, Automatic";
+       case V4L2_CID_WHITE_BALANCE_TEMPERATURE: return "White Balance Temperature";
+       case V4L2_CID_SHARPNESS:                return "Sharpness";
+       case V4L2_CID_BACKLIGHT_COMPENSATION:   return "Backlight Compensation";
+       case V4L2_CID_CHROMA_AGC:               return "Chroma AGC";
+       case V4L2_CID_COLOR_KILLER:             return "Color Killer";
 
        /* MPEG controls */
        case V4L2_CID_MPEG_CLASS:               return "MPEG Encoder Controls";
@@ -410,6 +448,25 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID";
        case V4L2_CID_MPEG_STREAM_VBI_FMT:      return "Stream VBI Format";
 
+       /* CAMERA controls */
+       case V4L2_CID_CAMERA_CLASS:             return "Camera Controls";
+       case V4L2_CID_EXPOSURE_AUTO:            return "Auto Exposure";
+       case V4L2_CID_EXPOSURE_ABSOLUTE:        return "Exposure Time, Absolute";
+       case V4L2_CID_EXPOSURE_AUTO_PRIORITY:   return "Exposure, Dynamic Framerate";
+       case V4L2_CID_PAN_RELATIVE:             return "Pan, Relative";
+       case V4L2_CID_TILT_RELATIVE:            return "Tilt, Relative";
+       case V4L2_CID_PAN_RESET:                return "Pan, Reset";
+       case V4L2_CID_TILT_RESET:               return "Tilt, Reset";
+       case V4L2_CID_PAN_ABSOLUTE:             return "Pan, Absolute";
+       case V4L2_CID_TILT_ABSOLUTE:            return "Tilt, Absolute";
+       case V4L2_CID_FOCUS_ABSOLUTE:           return "Focus, Absolute";
+       case V4L2_CID_FOCUS_RELATIVE:           return "Focus, Relative";
+       case V4L2_CID_FOCUS_AUTO:               return "Focus, Automatic";
+       case V4L2_CID_ZOOM_ABSOLUTE:            return "Zoom, Absolute";
+       case V4L2_CID_ZOOM_RELATIVE:            return "Zoom, Relative";
+       case V4L2_CID_ZOOM_CONTINUOUS:          return "Zoom, Continuous";
+       case V4L2_CID_PRIVACY:                  return "Privacy";
+
        default:
                return NULL;
        }
@@ -428,14 +485,22 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        switch (qctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
        case V4L2_CID_AUDIO_LOUDNESS:
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+       case V4L2_CID_AUTOGAIN:
+       case V4L2_CID_HFLIP:
+       case V4L2_CID_VFLIP:
+       case V4L2_CID_HUE_AUTO:
        case V4L2_CID_MPEG_AUDIO_MUTE:
        case V4L2_CID_MPEG_VIDEO_MUTE:
        case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
        case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+       case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+       case V4L2_CID_PRIVACY:
                qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
                min = 0;
                max = step = 1;
                break;
+       case V4L2_CID_POWER_LINE_FREQUENCY:
        case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
        case V4L2_CID_MPEG_AUDIO_ENCODING:
        case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
@@ -451,10 +516,12 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
        case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
        case V4L2_CID_MPEG_STREAM_TYPE:
        case V4L2_CID_MPEG_STREAM_VBI_FMT:
+       case V4L2_CID_EXPOSURE_AUTO:
                qctrl->type = V4L2_CTRL_TYPE_MENU;
                step = 1;
                break;
        case V4L2_CID_USER_CLASS:
+       case V4L2_CID_CAMERA_CLASS:
        case V4L2_CID_MPEG_CLASS:
                qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
                qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -801,4 +868,116 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
        return err != -ENOMEM ? 0 : err;
 }
 EXPORT_SYMBOL(v4l2_i2c_attach);
+
+void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+               const struct v4l2_subdev_ops *ops)
+{
+       v4l2_subdev_init(sd, ops);
+       /* the owner is the same as the i2c_client's driver owner */
+       sd->owner = client->driver->driver.owner;
+       /* i2c_client and v4l2_subdev point to one another */
+       v4l2_set_subdevdata(sd, client);
+       i2c_set_clientdata(client, sd);
+       /* initialize name */
+       snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
+               client->driver->driver.name, i2c_adapter_id(client->adapter),
+               client->addr);
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
+
+
+
+/* Load an i2c sub-device. It assumes that i2c_get_adapdata(adapter)
+   returns the v4l2_device and that i2c_get_clientdata(client)
+   returns the v4l2_subdev. */
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
+               const char *module_name, const char *client_type, u8 addr)
+{
+       struct v4l2_device *dev = i2c_get_adapdata(adapter);
+       struct v4l2_subdev *sd = NULL;
+       struct i2c_client *client;
+       struct i2c_board_info info;
+
+       BUG_ON(!dev);
+#ifdef MODULE
+       if (module_name)
+               request_module(module_name);
+#endif
+       /* Setup the i2c board info with the device type and
+          the device address. */
+       memset(&info, 0, sizeof(info));
+       strlcpy(info.type, client_type, sizeof(info.type));
+       info.addr = addr;
+
+       /* Create the i2c client */
+       client = i2c_new_device(adapter, &info);
+       /* Note: it is possible in the future that
+          c->driver is NULL if the driver is still being loaded.
+          We need better support from the kernel so that we
+          can easily wait for the load to finish. */
+       if (client == NULL || client->driver == NULL)
+               return NULL;
+
+       /* Lock the module so we can safely get the v4l2_subdev pointer */
+       if (!try_module_get(client->driver->driver.owner))
+               return NULL;
+       sd = i2c_get_clientdata(client);
+
+       /* Register with the v4l2_device which increases the module's
+          use count as well. */
+       if (v4l2_device_register_subdev(dev, sd))
+               sd = NULL;
+       /* Decrease the module use count to match the first try_module_get. */
+       module_put(client->driver->driver.owner);
+       return sd;
+
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
+
+/* Probe and load an i2c sub-device. It assumes that i2c_get_adapdata(adapter)
+   returns the v4l2_device and that i2c_get_clientdata(client)
+   returns the v4l2_subdev. */
+struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+       const char *module_name, const char *client_type,
+       const unsigned short *addrs)
+{
+       struct v4l2_device *dev = i2c_get_adapdata(adapter);
+       struct v4l2_subdev *sd = NULL;
+       struct i2c_client *client = NULL;
+       struct i2c_board_info info;
+
+       BUG_ON(!dev);
+#ifdef MODULE
+       if (module_name)
+               request_module(module_name);
+#endif
+       /* Setup the i2c board info with the device type and
+          the device address. */
+       memset(&info, 0, sizeof(info));
+       strlcpy(info.type, client_type, sizeof(info.type));
+
+       /* Probe and create the i2c client */
+       client = i2c_new_probed_device(adapter, &info, addrs);
+       /* Note: it is possible in the future that
+          c->driver is NULL if the driver is still being loaded.
+          We need better support from the kernel so that we
+          can easily wait for the load to finish. */
+       if (client == NULL || client->driver == NULL)
+               return NULL;
+
+       /* Lock the module so we can safely get the v4l2_subdev pointer */
+       if (!try_module_get(client->driver->driver.owner))
+               return NULL;
+       sd = i2c_get_clientdata(client);
+
+       /* Register with the v4l2_device which increases the module's
+          use count as well. */
+       if (v4l2_device_register_subdev(dev, sd))
+               sd = NULL;
+       /* Decrease the module use count to match the first try_module_get. */
+       module_put(client->driver->driver.owner);
+       return sd;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
+
 #endif
similarity index 53%
rename from drivers/media/video/compat_ioctl32.c
rename to drivers/media/video/v4l2-compat-ioctl32.c
index 0ea85a05e5c0d86911d9a62fe3445e472cf1e877..d0e1bd3ace6aec3a8f2aeab76a79509e783f762f 100644 (file)
@@ -7,12 +7,14 @@
  * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs
  * Copyright (C) 2003       Pavel Machek (pavel@suse.cz)
  * Copyright (C) 2005       Philippe De Muyter (phdm@macqel.be)
+ * Copyright (C) 2008       Hans Verkuil <hverkuil@xs4all.nl>
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * ioctls.
  */
 
 #include <linux/compat.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <linux/module.h>
@@ -32,7 +34,7 @@ struct video_tuner32 {
 
 static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
 {
-       if(!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
+       if (!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
                get_user(kp->tuner, &up->tuner) ||
                copy_from_user(kp->name, up->name, 32) ||
                get_user(kp->rangelow, &up->rangelow) ||
@@ -46,7 +48,7 @@ static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user
 
 static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
 {
-       if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
                put_user(kp->tuner, &up->tuner) ||
                copy_to_user(up->name, kp->name, 32) ||
                put_user(kp->rangelow, &up->rangelow) ||
@@ -58,7 +60,6 @@ static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user
        return 0;
 }
 
-
 struct video_buffer32 {
        compat_caddr_t base;
        compat_int_t height, width, depth, bytesperline;
@@ -88,7 +89,7 @@ static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u
 {
        u32 tmp = (u32)((unsigned long)kp->base);
 
-       if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
                put_user(tmp, &up->base) ||
                put_user(kp->height, &up->height) ||
                put_user(kp->width, &up->width) ||
@@ -99,7 +100,7 @@ static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __u
 }
 
 struct video_clip32 {
-       s32 x, y, width, height;        /* Its really s32 in videodev.h */
+       s32 x, y, width, height;        /* It's really s32 in videodev.h */
        compat_caddr_t next;
 };
 
@@ -108,29 +109,76 @@ struct video_window32 {
        compat_caddr_t clips;
        compat_int_t clipcount;
 };
-#endif
 
-static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
 {
-       int ret = -ENOIOCTLCMD;
+       struct video_clip __user *uclips;
+       struct video_clip __user *kclips;
+       compat_caddr_t p;
+       int nclips;
 
-       if (file->f_op->unlocked_ioctl)
-               ret = file->f_op->unlocked_ioctl(file, cmd, arg);
-       else if (file->f_op->ioctl) {
-               lock_kernel();
-               ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-               unlock_kernel();
+       if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
+               return -EFAULT;
+
+       if (get_user(nclips, &up->clipcount))
+               return -EFAULT;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)) ||
+           get_user(kp->x, &up->x) ||
+           get_user(kp->y, &up->y) ||
+           get_user(kp->width, &up->width) ||
+           get_user(kp->height, &up->height) ||
+           get_user(kp->chromakey, &up->chromakey) ||
+           get_user(kp->flags, &up->flags) ||
+           get_user(kp->clipcount, &up->clipcount))
+               return -EFAULT;
+
+       nclips = kp->clipcount;
+       kp->clips = NULL;
+
+       if (nclips == 0)
+               return 0;
+       if (get_user(p, &up->clips))
+               return -EFAULT;
+       uclips = compat_ptr(p);
+
+       /* If nclips < 0, then it is a clipping bitmap of size
+          VIDEO_CLIPMAP_SIZE */
+       if (nclips < 0) {
+               if (!access_ok(VERIFY_READ, uclips, VIDEO_CLIPMAP_SIZE))
+                       return -EFAULT;
+               kp->clips = compat_alloc_user_space(VIDEO_CLIPMAP_SIZE);
+               if (copy_in_user(kp->clips, uclips, VIDEO_CLIPMAP_SIZE))
+                       return -EFAULT;
+               return 0;
        }
 
-       return ret;
-}
+       /* Otherwise it is an array of video_clip structs. */
+       if (!access_ok(VERIFY_READ, uclips, nclips * sizeof(struct video_clip)))
+               return -EFAULT;
 
+       kp->clips = compat_alloc_user_space(nclips * sizeof(struct video_clip));
+       kclips = kp->clips;
+       while (nclips--) {
+               int err;
+
+               err = copy_in_user(&kclips->x, &uclips->x, sizeof(kclips->x));
+               err |= copy_in_user(&kclips->y, &uclips->y, sizeof(kclips->y));
+               err |= copy_in_user(&kclips->width, &uclips->width, sizeof(kclips->width));
+               err |= copy_in_user(&kclips->height, &uclips->height, sizeof(kclips->height));
+               kclips->next = NULL;
+               if (err)
+                       return -EFAULT;
+               kclips++;
+               uclips++;
+       }
+       return 0;
+}
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
 /* You get back everything except the clips... */
 static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
 {
-       if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
                put_user(kp->x, &up->x) ||
                put_user(kp->y, &up->y) ||
                put_user(kp->width, &up->width) ||
@@ -141,16 +189,61 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u
                        return -EFAULT;
        return 0;
 }
+
+struct video_code32 {
+       char            loadwhat[16];   /* name or tag of file being passed */
+       compat_int_t    datasize;
+       unsigned char   *data;
+};
+
+static int get_microcode32(struct video_code *kp, struct video_code32 __user *up)
+{
+       if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
+               copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
+               get_user(kp->datasize, &up->datasize) ||
+               copy_from_user(kp->data, up->data, up->datasize))
+                       return -EFAULT;
+       return 0;
+}
+
+#define VIDIOCGTUNER32         _IOWR('v', 4, struct video_tuner32)
+#define VIDIOCSTUNER32         _IOW('v', 5, struct video_tuner32)
+#define VIDIOCGWIN32           _IOR('v', 9, struct video_window32)
+#define VIDIOCSWIN32           _IOW('v', 10, struct video_window32)
+#define VIDIOCGFBUF32          _IOR('v', 11, struct video_buffer32)
+#define VIDIOCSFBUF32          _IOW('v', 12, struct video_buffer32)
+#define VIDIOCGFREQ32          _IOR('v', 14, u32)
+#define VIDIOCSFREQ32          _IOW('v', 15, u32)
+#define VIDIOCSMICROCODE32     _IOW('v', 27, struct video_code32)
+
+#define VIDIOCCAPTURE32                _IOW('v', 8, s32)
+#define VIDIOCSYNC32           _IOW('v', 18, s32)
+#define VIDIOCSWRITEMODE32     _IOW('v', 25, s32)
+
 #endif
 
-struct v4l2_clip32
+static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       int ret = -ENOIOCTLCMD;
+
+       if (file->f_op->unlocked_ioctl)
+               ret = file->f_op->unlocked_ioctl(file, cmd, arg);
+       else if (file->f_op->ioctl) {
+               lock_kernel();
+               ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+               unlock_kernel();
+       }
+
+       return ret;
+}
+
+
+struct v4l2_clip32 {
        struct v4l2_rect        c;
        compat_caddr_t          next;
 };
 
-struct v4l2_window32
-{
+struct v4l2_window32 {
        struct v4l2_rect        w;
        enum v4l2_field         field;
        __u32                   chromakey;
@@ -231,15 +324,28 @@ static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vb
        return 0;
 }
 
-struct v4l2_format32
+static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
+{
+       if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
+               return -EFAULT;
+       return 0;
+}
+
+static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
 {
+       if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
+               return -EFAULT;
+       return 0;
+}
+
+struct v4l2_format32 {
        enum v4l2_buf_type type;
-       union
-       {
-               struct v4l2_pix_format  pix;  // V4L2_BUF_TYPE_VIDEO_CAPTURE
-               struct v4l2_window32    win;  // V4L2_BUF_TYPE_VIDEO_OVERLAY
-               struct v4l2_vbi_format  vbi;  // V4L2_BUF_TYPE_VBI_CAPTURE
-               __u8    raw_data[200];        // user-defined
+       union {
+               struct v4l2_pix_format  pix;
+               struct v4l2_window32    win;
+               struct v4l2_vbi_format  vbi;
+               struct v4l2_sliced_vbi_format   sliced;
+               __u8    raw_data[200];        /* user-defined */
        } fmt;
 };
 
@@ -250,52 +356,62 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
                        return -EFAULT;
        switch (kp->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
                return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
+                       return -EFAULT;
+               return 0;
+       case 0:
+               return -EINVAL;
        default:
-               printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
+               printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
                                                                kp->type);
-               return -ENXIO;
+               return -EINVAL;
        }
 }
 
 static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
 {
-       if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
                put_user(kp->type, &up->type))
                return -EFAULT;
        switch (kp->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
        case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
                return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
        case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
                return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
+       case V4L2_BUF_TYPE_PRIVATE:
+               if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
+                       return -EFAULT;
+               return 0;
+       case 0:
+               return -EINVAL;
        default:
-               return -ENXIO;
+               printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
+                                                               kp->type);
+               return -EINVAL;
        }
 }
 
-static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_standard)))
-               return -EFAULT;
-       return 0;
-
-}
-
-static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_standard)))
-               return -EFAULT;
-       return 0;
-}
-
-struct v4l2_standard32
-{
+struct v4l2_standard32 {
        __u32                index;
        __u32                id[2]; /* __u64 would get the alignment wrong */
        __u8                 name[24];
@@ -315,7 +431,7 @@ static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
 
 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
 {
-       if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
                put_user(kp->index, &up->index) ||
                copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
                copy_to_user(up->name, kp->name, 24) ||
@@ -326,23 +442,7 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32
        return 0;
 }
 
-static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_tuner)))
-               return -EFAULT;
-       return 0;
-
-}
-
-static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_tuner)))
-               return -EFAULT;
-       return 0;
-}
-
-struct v4l2_buffer32
-{
+struct v4l2_buffer32 {
        __u32                   index;
        enum v4l2_buf_type      type;
        __u32                   bytesused;
@@ -373,7 +473,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                get_user(kp->memory, &up->memory) ||
                get_user(kp->input, &up->input))
                        return -EFAULT;
-       switch(kp->memory) {
+       switch (kp->memory) {
        case V4L2_MEMORY_MMAP:
                break;
        case V4L2_MEMORY_USERPTR:
@@ -388,7 +488,7 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                }
                break;
        case V4L2_MEMORY_OVERLAY:
-               if(get_user(kp->m.offset, &up->m.offset))
+               if (get_user(kp->m.offset, &up->m.offset))
                        return -EFAULT;
                break;
        }
@@ -404,7 +504,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
                put_user(kp->memory, &up->memory) ||
                put_user(kp->input, &up->input))
                        return -EFAULT;
-       switch(kp->memory) {
+       switch (kp->memory) {
        case V4L2_MEMORY_MMAP:
                if (put_user(kp->length, &up->length) ||
                        put_user(kp->m.offset, &up->m.offset))
@@ -431,8 +531,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user
        return 0;
 }
 
-struct v4l2_framebuffer32
-{
+struct v4l2_framebuffer32 {
        __u32                   capability;
        __u32                   flags;
        compat_caddr_t          base;
@@ -457,7 +556,7 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
 {
        u32 tmp = (u32)((unsigned long)kp->base);
 
-       if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
                put_user(tmp, &up->base) ||
                put_user(kp->capability, &up->capability) ||
                put_user(kp->flags, &up->flags))
@@ -466,150 +565,145 @@ static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_frame
        return 0;
 }
 
-static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
+struct v4l2_input32 {
+       __u32        index;             /*  Which input */
+       __u8         name[32];          /*  Label */
+       __u32        type;              /*  Type of input */
+       __u32        audioset;          /*  Associated audios (bitfield) */
+       __u32        tuner;             /*  Associated tuner */
+       v4l2_std_id  std;
+       __u32        status;
+       __u32        reserved[4];
+} __attribute__ ((packed));
+
+/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
+   Otherwise it is identical to the 32-bit version. */
+static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
 {
-       if (copy_from_user(kp, up, sizeof(struct v4l2_input) - 4))
+       if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
                return -EFAULT;
        return 0;
 }
 
-static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
+static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
 {
-       if (copy_to_user(up, kp, sizeof(struct v4l2_input) - 4))
+       if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
                return -EFAULT;
        return 0;
 }
 
-static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
-{
-       if (copy_from_user(kp, up, sizeof(struct v4l2_input)))
-               return -EFAULT;
-       return 0;
-}
-
-static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
-{
-       if (copy_to_user(up, kp, sizeof(struct v4l2_input)))
-               return -EFAULT;
-       return 0;
-}
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-struct video_code32
-{
-       char            loadwhat[16];   /* name or tag of file being passed */
-       compat_int_t    datasize;
-       unsigned char   *data;
+struct v4l2_ext_controls32 {
+       __u32 ctrl_class;
+       __u32 count;
+       __u32 error_idx;
+       __u32 reserved[2];
+       compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
 };
 
-static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
+static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
-       if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
-               copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) ||
-               get_user(kp->datasize, &up->datasize) ||
-               copy_from_user(kp->data, up->data, up->datasize))
+       struct v4l2_ext_control __user *ucontrols;
+       struct v4l2_ext_control __user *kcontrols;
+       int n;
+       compat_caddr_t p;
+
+       if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
+               get_user(kp->ctrl_class, &up->ctrl_class) ||
+               get_user(kp->count, &up->count) ||
+               get_user(kp->error_idx, &up->error_idx) ||
+               copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
                        return -EFAULT;
+       n = kp->count;
+       if (n == 0) {
+               kp->controls = NULL;
+               return 0;
+       }
+       if (get_user(p, &up->controls))
+               return -EFAULT;
+       ucontrols = compat_ptr(p);
+       if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
+               return -EFAULT;
+       kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
+       kp->controls = kcontrols;
+       while (--n >= 0) {
+               if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
+                       return -EFAULT;
+               if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
+                       return -EFAULT;
+               /* Note: if the void * part of the union ever becomes relevant
+                  then we need to know the type of the control in order to do
+                  the right thing here. Luckily, that is not yet an issue. */
+               if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
+                       return -EFAULT;
+               ucontrols++;
+               kcontrols++;
+       }
        return 0;
 }
 
-#define VIDIOCGTUNER32         _IOWR('v',4, struct video_tuner32)
-#define VIDIOCSTUNER32         _IOW('v',5, struct video_tuner32)
-#define VIDIOCGWIN32           _IOR('v',9, struct video_window32)
-#define VIDIOCSWIN32           _IOW('v',10, struct video_window32)
-#define VIDIOCGFBUF32          _IOR('v',11, struct video_buffer32)
-#define VIDIOCSFBUF32          _IOW('v',12, struct video_buffer32)
-#define VIDIOCGFREQ32          _IOR('v',14, u32)
-#define VIDIOCSFREQ32          _IOW('v',15, u32)
-#define VIDIOCSMICROCODE32     _IOW('v',27, struct video_code32)
-
-#endif
-
-/* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
-#define VIDIOC_ENUMINPUT32     VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4)
-#define VIDIOC_G_FMT32         _IOWR ('V',  4, struct v4l2_format32)
-#define VIDIOC_S_FMT32         _IOWR ('V',  5, struct v4l2_format32)
-#define VIDIOC_QUERYBUF32      _IOWR ('V',  9, struct v4l2_buffer32)
-#define VIDIOC_G_FBUF32                _IOR  ('V', 10, struct v4l2_framebuffer32)
-#define VIDIOC_S_FBUF32                _IOW  ('V', 11, struct v4l2_framebuffer32)
-/* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
-#define VIDIOC_OVERLAY32       _IOWR ('V', 14, compat_int_t)
-#define VIDIOC_QBUF32          _IOWR ('V', 15, struct v4l2_buffer32)
-#define VIDIOC_DQBUF32         _IOWR ('V', 17, struct v4l2_buffer32)
-#define VIDIOC_STREAMON32      _IOW  ('V', 18, compat_int_t)
-#define VIDIOC_STREAMOFF32     _IOW  ('V', 19, compat_int_t)
-#define VIDIOC_ENUMSTD32       _IOWR ('V', 25, struct v4l2_standard32)
-/* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
-#define VIDIOC_S_CTRL32                _IOW  ('V', 28, struct v4l2_control)
-#define VIDIOC_G_INPUT32       _IOR  ('V', 38, compat_int_t)
-#define VIDIOC_S_INPUT32       _IOWR ('V', 39, compat_int_t)
-#define VIDIOC_TRY_FMT32       _IOWR ('V', 64, struct v4l2_format32)
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-enum {
-       MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
-};
-
-static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
+static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
 {
-       struct video_window32 __user *up = compat_ptr(arg);
-       struct video_window __user *vw;
-       struct video_clip __user *p;
-       int nclips;
-       u32 n;
-
-       if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
-               return -EFAULT;
+       struct v4l2_ext_control __user *ucontrols;
+       struct v4l2_ext_control __user *kcontrols = kp->controls;
+       int n = kp->count;
+       compat_caddr_t p;
+
+       if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
+               put_user(kp->ctrl_class, &up->ctrl_class) ||
+               put_user(kp->count, &up->count) ||
+               put_user(kp->error_idx, &up->error_idx) ||
+               copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
+                       return -EFAULT;
+       if (!kp->count)
+               return 0;
 
-       if (get_user(nclips, &up->clipcount))
+       if (get_user(p, &up->controls))
                return -EFAULT;
-
-       /* Peculiar interface... */
-       if (nclips < 0)
-               nclips = VIDEO_CLIPMAP_SIZE;
-
-       if (nclips > MaxClips)
-               return -ENOMEM;
-
-       vw = compat_alloc_user_space(sizeof(struct video_window) +
-                                   nclips * sizeof(struct video_clip));
-
-       p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
-
-       if (get_user(n, &up->x) || put_user(n, &vw->x) ||
-           get_user(n, &up->y) || put_user(n, &vw->y) ||
-           get_user(n, &up->width) || put_user(n, &vw->width) ||
-           get_user(n, &up->height) || put_user(n, &vw->height) ||
-           get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
-           get_user(n, &up->flags) || put_user(n, &vw->flags) ||
-           get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
-           get_user(n, &up->clips) || put_user(p, &vw->clips))
+       ucontrols = compat_ptr(p);
+       if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
                return -EFAULT;
 
-       if (nclips) {
-               struct video_clip32 __user *u = compat_ptr(n);
-               int i;
-               if (!u)
-                       return -EINVAL;
-               for (i = 0; i < nclips; i++, u++, p++) {
-                       s32 v;
-                       if (!access_ok(VERIFY_READ, u, sizeof(struct video_clip32)) ||
-                           !access_ok(VERIFY_WRITE, p, sizeof(struct video_clip32)) ||
-                           get_user(v, &u->x) ||
-                           put_user(v, &p->x) ||
-                           get_user(v, &u->y) ||
-                           put_user(v, &p->y) ||
-                           get_user(v, &u->width) ||
-                           put_user(v, &p->width) ||
-                           get_user(v, &u->height) ||
-                           put_user(v, &p->height) ||
-                           put_user(NULL, &p->next))
-                               return -EFAULT;
-               }
+       while (--n >= 0) {
+               if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
+                       return -EFAULT;
+               if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
+                                       sizeof(ucontrols->reserved2)))
+                       return -EFAULT;
+               /* Note: if the void * part of the union ever becomes relevant
+                  then we need to know the type of the control in order to do
+                  the right thing here. Luckily, that is not yet an issue. */
+               if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
+                       return -EFAULT;
+               ucontrols++;
+               kcontrols++;
        }
-
-       return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
+       return 0;
 }
+
+#define VIDIOC_G_FMT32         _IOWR('V',  4, struct v4l2_format32)
+#define VIDIOC_S_FMT32         _IOWR('V',  5, struct v4l2_format32)
+#define VIDIOC_QUERYBUF32      _IOWR('V',  9, struct v4l2_buffer32)
+#define VIDIOC_G_FBUF32                _IOR ('V', 10, struct v4l2_framebuffer32)
+#define VIDIOC_S_FBUF32                _IOW ('V', 11, struct v4l2_framebuffer32)
+#define VIDIOC_QBUF32          _IOWR('V', 15, struct v4l2_buffer32)
+#define VIDIOC_DQBUF32         _IOWR('V', 17, struct v4l2_buffer32)
+#define VIDIOC_ENUMSTD32       _IOWR('V', 25, struct v4l2_standard32)
+#define VIDIOC_ENUMINPUT32     _IOWR('V', 26, struct v4l2_input32)
+#define VIDIOC_TRY_FMT32       _IOWR('V', 64, struct v4l2_format32)
+#define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
+#define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
+#define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
+
+#define VIDIOC_OVERLAY32       _IOW ('V', 14, s32)
+#ifdef __OLD_VIDIOC_
+#define VIDIOC_OVERLAY32_OLD   _IOWR('V', 14, s32)
 #endif
+#define VIDIOC_STREAMON32      _IOW ('V', 18, s32)
+#define VIDIOC_STREAMOFF32     _IOW ('V', 19, s32)
+#define VIDIOC_G_INPUT32       _IOR ('V', 38, s32)
+#define VIDIOC_S_INPUT32       _IOWR('V', 39, s32)
+#define VIDIOC_G_OUTPUT32      _IOR ('V', 46, s32)
+#define VIDIOC_S_OUTPUT32      _IOWR('V', 47, s32)
 
 static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
@@ -624,53 +718,60 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
                struct v4l2_format v2f;
                struct v4l2_buffer v2b;
                struct v4l2_framebuffer v2fb;
-               struct v4l2_standard v2s;
                struct v4l2_input v2i;
-               struct v4l2_tuner v2t;
+               struct v4l2_standard v2s;
+               struct v4l2_ext_controls v2ecs;
                unsigned long vx;
+               int vi;
        } karg;
        void __user *up = compat_ptr(arg);
        int compatible_arg = 1;
        int err = 0;
-       int realcmd = cmd;
 
        /* First, convert the command. */
-       switch(cmd) {
+       switch (cmd) {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
-       case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
-       case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
-       case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
-       case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
-       case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
-       case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
-       case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
+       case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
+       case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
+       case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
+       case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
+       case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
+       case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
+       case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
+       case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+       case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
 #endif
-       case VIDIOC_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
-       case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
-       case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
-       case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
-       case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
-       case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
-       case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
-       case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
-       case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
-       case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
-       case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
-       case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
-       case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
-       case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
-       case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
-       case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
-       };
-
-       switch(cmd) {
+       case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
+       case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
+       case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
+       case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
+       case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
+       case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
+       case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
+       case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
+       case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
+       case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+       case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
+       case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
+       case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
+       case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+#ifdef __OLD_VIDIOC_
+       case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
+#endif
+       case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
+       case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
+       case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
+       case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
+       case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
+       case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
+       }
+
+       switch (cmd) {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        case VIDIOCSTUNER:
        case VIDIOCGTUNER:
                err = get_video_tuner32(&karg.vt, up);
                compatible_arg = 0;
-
                break;
 
        case VIDIOCSFBUF:
@@ -678,19 +779,42 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
                compatible_arg = 0;
                break;
 
+       case VIDIOCSWIN:
+               err = get_video_window32(&karg.vw, up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOCGWIN:
+       case VIDIOCGFBUF:
+       case VIDIOCGFREQ:
+               compatible_arg = 0;
+               break;
+
+       case VIDIOCSMICROCODE:
+               err = get_microcode32(&karg.vc, up);
+               compatible_arg = 0;
+               break;
 
        case VIDIOCSFREQ:
+               err = get_user(karg.vx, (u32 __user *)up);
+               compatible_arg = 0;
+               break;
+
+       case VIDIOCCAPTURE:
+       case VIDIOCSYNC:
+       case VIDIOCSWRITEMODE:
 #endif
-       case VIDIOC_S_INPUT:
        case VIDIOC_OVERLAY:
        case VIDIOC_STREAMON:
        case VIDIOC_STREAMOFF:
-               err = get_user(karg.vx, (u32 __user *)up);
-               compatible_arg = 1;
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_OUTPUT:
+               err = get_user(karg.vi, (s32 __user *)up);
+               compatible_arg = 0;
                break;
 
-       case VIDIOC_S_FBUF:
-               err = get_v4l2_framebuffer32(&karg.v2fb, up);
+       case VIDIOC_G_INPUT:
+       case VIDIOC_G_OUTPUT:
                compatible_arg = 0;
                break;
 
@@ -708,122 +832,108 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
                compatible_arg = 0;
                break;
 
-       case VIDIOC_ENUMSTD:
-               err = get_v4l2_standard(&karg.v2s, up);
+       case VIDIOC_S_FBUF:
+               err = get_v4l2_framebuffer32(&karg.v2fb, up);
                compatible_arg = 0;
                break;
 
-       case VIDIOC_ENUMSTD32:
-               err = get_v4l2_standard32(&karg.v2s, up);
+       case VIDIOC_G_FBUF:
                compatible_arg = 0;
                break;
 
-       case VIDIOC_ENUMINPUT:
-               err = get_v4l2_input(&karg.v2i, up);
+       case VIDIOC_ENUMSTD:
+               err = get_v4l2_standard32(&karg.v2s, up);
                compatible_arg = 0;
                break;
 
-       case VIDIOC_ENUMINPUT32:
+       case VIDIOC_ENUMINPUT:
                err = get_v4l2_input32(&karg.v2i, up);
                compatible_arg = 0;
                break;
 
-       case VIDIOC_G_TUNER:
-       case VIDIOC_S_TUNER:
-               err = get_v4l2_tuner(&karg.v2t, up);
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+               err = get_v4l2_ext_controls32(&karg.v2ecs, up);
                compatible_arg = 0;
                break;
+       }
+       if (err)
+               return err;
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCGWIN:
-       case VIDIOCGFBUF:
-       case VIDIOCGFREQ:
-#endif
-       case VIDIOC_G_FBUF:
-       case VIDIOC_G_INPUT:
-               compatible_arg = 0;
-               break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCSMICROCODE:
-               err = microcode32(&karg.vc, up);
-               compatible_arg = 0;
-               break;
-#endif
-       };
-       if(err)
-               goto out;
-
-       if(compatible_arg)
-               err = native_ioctl(file, realcmd, (unsigned long)up);
+       if (compatible_arg)
+               err = native_ioctl(file, cmd, (unsigned long)up);
        else {
                mm_segment_t old_fs = get_fs();
 
                set_fs(KERNEL_DS);
-               err = native_ioctl(file, realcmd, (unsigned long) &karg);
+               err = native_ioctl(file, cmd, (unsigned long)&karg);
                set_fs(old_fs);
        }
-       if(err == 0) {
-               switch(cmd) {
+
+       /* Special case: even after an error we need to put the
+          results back for these ioctls since the error_idx will
+          contain information on which control failed. */
+       switch (cmd) {
+       case VIDIOC_G_EXT_CTRLS:
+       case VIDIOC_S_EXT_CTRLS:
+       case VIDIOC_TRY_EXT_CTRLS:
+               if (put_v4l2_ext_controls32(&karg.v2ecs, up))
+                       err = -EFAULT;
+               break;
+       }
+       if (err)
+               return err;
+
+       switch (cmd) {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-               case VIDIOCGTUNER:
-                       err = put_video_tuner32(&karg.vt, up);
-                       break;
+       case VIDIOCGTUNER:
+               err = put_video_tuner32(&karg.vt, up);
+               break;
 
-               case VIDIOCGWIN:
-                       err = put_video_window32(&karg.vw, up);
-                       break;
+       case VIDIOCGWIN:
+               err = put_video_window32(&karg.vw, up);
+               break;
 
-               case VIDIOCGFBUF:
-                       err = put_video_buffer32(&karg.vb, up);
-                       break;
+       case VIDIOCGFBUF:
+               err = put_video_buffer32(&karg.vb, up);
+               break;
 
+       case VIDIOCGFREQ:
+               err = put_user(((u32)karg.vx), (u32 __user *)up);
+               break;
 #endif
-               case VIDIOC_G_FBUF:
-                       err = put_v4l2_framebuffer32(&karg.v2fb, up);
-                       break;
-
-               case VIDIOC_G_FMT:
-               case VIDIOC_S_FMT:
-               case VIDIOC_TRY_FMT:
-                       err = put_v4l2_format32(&karg.v2f, up);
-                       break;
-
-               case VIDIOC_QUERYBUF:
-               case VIDIOC_QBUF:
-               case VIDIOC_DQBUF:
-                       err = put_v4l2_buffer32(&karg.v2b, up);
-                       break;
-
-               case VIDIOC_ENUMSTD:
-                       err = put_v4l2_standard(&karg.v2s, up);
-                       break;
-
-               case VIDIOC_ENUMSTD32:
-                       err = put_v4l2_standard32(&karg.v2s, up);
-                       break;
-
-               case VIDIOC_G_TUNER:
-               case VIDIOC_S_TUNER:
-                       err = put_v4l2_tuner(&karg.v2t, up);
-                       break;
-
-               case VIDIOC_ENUMINPUT:
-                       err = put_v4l2_input(&karg.v2i, up);
-                       break;
-
-               case VIDIOC_ENUMINPUT32:
-                       err = put_v4l2_input32(&karg.v2i, up);
-                       break;
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_OUTPUT:
+       case VIDIOC_G_INPUT:
+       case VIDIOC_G_OUTPUT:
+               err = put_user(((s32)karg.vi), (s32 __user *)up);
+               break;
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-               case VIDIOCGFREQ:
-#endif
-               case VIDIOC_G_INPUT:
-                       err = put_user(((u32)karg.vx), (u32 __user *)up);
-                       break;
-               };
+       case VIDIOC_G_FBUF:
+               err = put_v4l2_framebuffer32(&karg.v2fb, up);
+               break;
+
+       case VIDIOC_G_FMT:
+       case VIDIOC_S_FMT:
+       case VIDIOC_TRY_FMT:
+               err = put_v4l2_format32(&karg.v2f, up);
+               break;
+
+       case VIDIOC_QUERYBUF:
+       case VIDIOC_QBUF:
+       case VIDIOC_DQBUF:
+               err = put_v4l2_buffer32(&karg.v2b, up);
+               break;
+
+       case VIDIOC_ENUMSTD:
+               err = put_v4l2_standard32(&karg.v2s, up);
+               break;
+
+       case VIDIOC_ENUMINPUT:
+               err = put_v4l2_input32(&karg.v2i, up);
+               break;
        }
-out:
        return err;
 }
 
@@ -836,26 +946,48 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd) {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-       case VIDIOCSWIN32:
-               ret = do_set_window(file, cmd, arg);
-               break;
+       case VIDIOCGCAP:
+       case VIDIOCGCHAN:
+       case VIDIOCSCHAN:
        case VIDIOCGTUNER32:
        case VIDIOCSTUNER32:
+       case VIDIOCGPICT:
+       case VIDIOCSPICT:
+       case VIDIOCCAPTURE32:
        case VIDIOCGWIN32:
+       case VIDIOCSWIN32:
        case VIDIOCGFBUF32:
        case VIDIOCSFBUF32:
+       case VIDIOCKEY:
        case VIDIOCGFREQ32:
        case VIDIOCSFREQ32:
        case VIDIOCGAUDIO:
        case VIDIOCSAUDIO:
+       case VIDIOCSYNC32:
+       case VIDIOCMCAPTURE:
+       case VIDIOCGMBUF:
+       case VIDIOCGUNIT:
+       case VIDIOCGCAPTURE:
+       case VIDIOCSCAPTURE:
+       case VIDIOCSPLAYMODE:
+       case VIDIOCSWRITEMODE32:
+       case VIDIOCGPLAYINFO:
+       case VIDIOCSMICROCODE32:
        case VIDIOCGVBIFMT:
        case VIDIOCSVBIFMT:
+#endif
+#ifdef __OLD_VIDIOC_
+       case VIDIOC_OVERLAY32_OLD:
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_G_AUDIO_OLD:
+       case VIDIOC_G_AUDOUT_OLD:
+       case VIDIOC_CROPCAP_OLD:
 #endif
        case VIDIOC_QUERYCAP:
+       case VIDIOC_RESERVED:
        case VIDIOC_ENUM_FMT:
        case VIDIOC_G_FMT32:
-       case VIDIOC_CROPCAP:
-       case VIDIOC_S_CROP:
        case VIDIOC_S_FMT32:
        case VIDIOC_REQBUFS:
        case VIDIOC_QUERYBUF32:
@@ -870,43 +1002,56 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
        case VIDIOC_S_PARM:
        case VIDIOC_G_STD:
        case VIDIOC_S_STD:
-       case VIDIOC_G_TUNER:
-       case VIDIOC_S_TUNER:
-       case VIDIOC_ENUMSTD:
        case VIDIOC_ENUMSTD32:
-       case VIDIOC_ENUMINPUT:
        case VIDIOC_ENUMINPUT32:
        case VIDIOC_G_CTRL:
        case VIDIOC_S_CTRL:
-       case VIDIOC_S_CTRL32:
-       case VIDIOC_S_FREQUENCY:
-       case VIDIOC_G_FREQUENCY:
+       case VIDIOC_G_TUNER:
+       case VIDIOC_S_TUNER:
+       case VIDIOC_G_AUDIO:
+       case VIDIOC_S_AUDIO:
        case VIDIOC_QUERYCTRL:
+       case VIDIOC_QUERYMENU:
        case VIDIOC_G_INPUT32:
        case VIDIOC_S_INPUT32:
+       case VIDIOC_G_OUTPUT32:
+       case VIDIOC_S_OUTPUT32:
+       case VIDIOC_ENUMOUTPUT:
+       case VIDIOC_G_AUDOUT:
+       case VIDIOC_S_AUDOUT:
+       case VIDIOC_G_MODULATOR:
+       case VIDIOC_S_MODULATOR:
+       case VIDIOC_S_FREQUENCY:
+       case VIDIOC_G_FREQUENCY:
+       case VIDIOC_CROPCAP:
+       case VIDIOC_G_CROP:
+       case VIDIOC_S_CROP:
+       case VIDIOC_G_JPEGCOMP:
+       case VIDIOC_S_JPEGCOMP:
+       case VIDIOC_QUERYSTD:
        case VIDIOC_TRY_FMT32:
-       case VIDIOC_S_HW_FREQ_SEEK:
+       case VIDIOC_ENUMAUDIO:
+       case VIDIOC_ENUMAUDOUT:
+       case VIDIOC_G_PRIORITY:
+       case VIDIOC_S_PRIORITY:
+       case VIDIOC_G_SLICED_VBI_CAP:
+       case VIDIOC_LOG_STATUS:
+       case VIDIOC_G_EXT_CTRLS32:
+       case VIDIOC_S_EXT_CTRLS32:
+       case VIDIOC_TRY_EXT_CTRLS32:
        case VIDIOC_ENUM_FRAMESIZES:
        case VIDIOC_ENUM_FRAMEINTERVALS:
+       case VIDIOC_G_ENC_INDEX:
+       case VIDIOC_ENCODER_CMD:
+       case VIDIOC_TRY_ENCODER_CMD:
+       case VIDIOC_DBG_S_REGISTER:
+       case VIDIOC_DBG_G_REGISTER:
+       case VIDIOC_G_CHIP_IDENT:
+       case VIDIOC_S_HW_FREQ_SEEK:
                ret = do_video_ioctl(file, cmd, arg);
                break;
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-       /* Little v, the video4linux ioctls (conflict?) */
-       case VIDIOCGCAP:
-       case VIDIOCGCHAN:
-       case VIDIOCSCHAN:
-       case VIDIOCGPICT:
-       case VIDIOCSPICT:
-       case VIDIOCCAPTURE:
-       case VIDIOCKEY:
-       case VIDIOCSYNC:
-       case VIDIOCMCAPTURE:
-       case VIDIOCGMBUF:
-       case VIDIOCGUNIT:
-       case VIDIOCGCAPTURE:
-       case VIDIOCSCAPTURE:
-
        /* BTTV specific... */
        case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
        case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
@@ -921,6 +1066,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
 #endif
        default:
                v4l_print_ioctl("compat_ioctl32", cmd);
+               printk(KERN_CONT "\n");
+               break;
        }
        return ret;
 }
index ccd6566a515e1c293ec85f8f067f48fb4fea4643..7ad6711ee32776452f2493f022b9b4dc059de8a9 100644 (file)
@@ -9,7 +9,7 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- * Authors:    Alan Cox, <alan@redhat.com> (version 1)
+ * Authors:    Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
  *              Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
  *
  * Fixes:      20000516  Claudio Matsuoka <claudio@conectiva.com>
@@ -30,6 +30,7 @@
 #include <asm/system.h>
 
 #include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 
 #define VIDEO_NUM_DEVICES      256
 #define VIDEO_NAME              "video4linux"
 static ssize_t show_index(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
-       struct video_device *vfd = container_of(cd, struct video_device, dev);
+       struct video_device *vdev = to_video_device(cd);
 
-       return sprintf(buf, "%i\n", vfd->index);
+       return sprintf(buf, "%i\n", vdev->index);
 }
 
 static ssize_t show_name(struct device *cd,
                         struct device_attribute *attr, char *buf)
 {
-       struct video_device *vfd = container_of(cd, struct video_device, dev);
+       struct video_device *vdev = to_video_device(cd);
 
-       return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
+       return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
 }
 
 static struct device_attribute video_device_attrs[] = {
@@ -73,64 +74,64 @@ struct video_device *video_device_alloc(void)
 }
 EXPORT_SYMBOL(video_device_alloc);
 
-void video_device_release(struct video_device *vfd)
+void video_device_release(struct video_device *vdev)
 {
-       kfree(vfd);
+       kfree(vdev);
 }
 EXPORT_SYMBOL(video_device_release);
 
-void video_device_release_empty(struct video_device *vfd)
+void video_device_release_empty(struct video_device *vdev)
 {
        /* Do nothing */
        /* Only valid when the video_device struct is a static. */
 }
 EXPORT_SYMBOL(video_device_release_empty);
 
-/* Called when the last user of the character device is gone. */
-static void v4l2_chardev_release(struct kobject *kobj)
+static inline void video_get(struct video_device *vdev)
 {
-       struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj);
+       get_device(&vdev->dev);
+}
+
+static inline void video_put(struct video_device *vdev)
+{
+       put_device(&vdev->dev);
+}
+
+/* Called when the last user of the video device exits. */
+static void v4l2_device_release(struct device *cd)
+{
+       struct video_device *vdev = to_video_device(cd);
 
        mutex_lock(&videodev_lock);
-       if (video_device[vfd->minor] != vfd) {
+       if (video_device[vdev->minor] != vdev) {
                mutex_unlock(&videodev_lock);
-               BUG();
+               /* should not happen */
+               WARN_ON(1);
                return;
        }
 
        /* Free up this device for reuse */
-       video_device[vfd->minor] = NULL;
-       clear_bit(vfd->num, video_nums[vfd->vfl_type]);
-       mutex_unlock(&videodev_lock);
+       video_device[vdev->minor] = NULL;
 
-       /* Release the character device */
-       vfd->cdev_release(kobj);
-       /* Release video_device and perform other
-          cleanups as needed. */
-       if (vfd->release)
-               vfd->release(vfd);
-}
+       /* Delete the cdev on this minor as well */
+       cdev_del(vdev->cdev);
+       /* Just in case some driver tries to access this from
+          the release() callback. */
+       vdev->cdev = NULL;
 
-/* The new kobj_type for the character device */
-static struct kobj_type v4l2_ktype_cdev_default = {
-       .release = v4l2_chardev_release,
-};
+       /* Mark minor as free */
+       clear_bit(vdev->num, video_nums[vdev->vfl_type]);
 
-static void video_release(struct device *cd)
-{
-       struct video_device *vfd = container_of(cd, struct video_device, dev);
+       mutex_unlock(&videodev_lock);
 
-       /* It's now safe to delete the char device.
-          This will either trigger the v4l2_chardev_release immediately (if
-          the refcount goes to 0) or later when the last user of the
-          character device closes it. */
-       cdev_del(&vfd->cdev);
+       /* Release video_device and perform other
+          cleanups as needed. */
+       vdev->release(vdev);
 }
 
 static struct class video_class = {
        .name = VIDEO_NAME,
        .dev_attrs = video_device_attrs,
-       .dev_release = video_release,
 };
 
 struct video_device *video_devdata(struct file *file)
@@ -139,13 +140,163 @@ struct video_device *video_devdata(struct file *file)
 }
 EXPORT_SYMBOL(video_devdata);
 
+static ssize_t v4l2_read(struct file *filp, char __user *buf,
+               size_t sz, loff_t *off)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->read)
+               return -EINVAL;
+       if (video_is_unregistered(vdev))
+               return -EIO;
+       return vdev->fops->read(filp, buf, sz, off);
+}
+
+static ssize_t v4l2_write(struct file *filp, const char __user *buf,
+               size_t sz, loff_t *off)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->write)
+               return -EINVAL;
+       if (video_is_unregistered(vdev))
+               return -EIO;
+       return vdev->fops->write(filp, buf, sz, off);
+}
+
+static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->poll || video_is_unregistered(vdev))
+               return DEFAULT_POLLMASK;
+       return vdev->fops->poll(filp, poll);
+}
+
+static int v4l2_ioctl(struct inode *inode, struct file *filp,
+               unsigned int cmd, unsigned long arg)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->ioctl)
+               return -ENOTTY;
+       /* Allow ioctl to continue even if the device was unregistered.
+          Things like dequeueing buffers might still be useful. */
+       return vdev->fops->ioctl(inode, filp, cmd, arg);
+}
+
+static long v4l2_unlocked_ioctl(struct file *filp,
+               unsigned int cmd, unsigned long arg)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->unlocked_ioctl)
+               return -ENOTTY;
+       /* Allow ioctl to continue even if the device was unregistered.
+          Things like dequeueing buffers might still be useful. */
+       return vdev->fops->unlocked_ioctl(filp, cmd, arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long v4l2_compat_ioctl(struct file *filp,
+               unsigned int cmd, unsigned long arg)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->compat_ioctl)
+               return -ENOIOCTLCMD;
+       /* Allow ioctl to continue even if the device was unregistered.
+          Things like dequeueing buffers might still be useful. */
+       return vdev->fops->compat_ioctl(filp, cmd, arg);
+}
+#endif
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
+{
+       struct video_device *vdev = video_devdata(filp);
+
+       if (!vdev->fops->mmap ||
+           video_is_unregistered(vdev))
+               return -ENODEV;
+       return vdev->fops->mmap(filp, vm);
+}
+
+/* Override for the open function */
+static int v4l2_open(struct inode *inode, struct file *filp)
+{
+       struct video_device *vdev;
+       int ret;
+
+       /* Check if the video device is available */
+       mutex_lock(&videodev_lock);
+       vdev = video_devdata(filp);
+       /* return ENODEV if the video device has been removed
+          already or if it is not registered anymore. */
+       if (vdev == NULL || video_is_unregistered(vdev)) {
+               mutex_unlock(&videodev_lock);
+               return -ENODEV;
+       }
+       /* and increase the device refcount */
+       video_get(vdev);
+       mutex_unlock(&videodev_lock);
+       ret = vdev->fops->open(inode, filp);
+       /* decrease the refcount in case of an error */
+       if (ret)
+               video_put(vdev);
+       return ret;
+}
+
+/* Override for the release function */
+static int v4l2_release(struct inode *inode, struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       int ret = vdev->fops->release(inode, filp);
+
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+       video_put(vdev);
+       return ret;
+}
+
+static const struct file_operations v4l2_unlocked_fops = {
+       .owner = THIS_MODULE,
+       .read = v4l2_read,
+       .write = v4l2_write,
+       .open = v4l2_open,
+       .mmap = v4l2_mmap,
+       .unlocked_ioctl = v4l2_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = v4l2_compat_ioctl,
+#endif
+       .release = v4l2_release,
+       .poll = v4l2_poll,
+       .llseek = no_llseek,
+};
+
+static const struct file_operations v4l2_fops = {
+       .owner = THIS_MODULE,
+       .read = v4l2_read,
+       .write = v4l2_write,
+       .open = v4l2_open,
+       .mmap = v4l2_mmap,
+       .ioctl = v4l2_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = v4l2_compat_ioctl,
+#endif
+       .release = v4l2_release,
+       .poll = v4l2_poll,
+       .llseek = no_llseek,
+};
+
 /**
  * get_index - assign stream number based on parent device
- * @vdev: video_device to assign index number to, vdev->dev should be assigned
- * @num: -1 if auto assign, requested number otherwise
+ * @vdev: video_device to assign index number to, vdev->parent should be assigned
+ * @num:  -1 if auto assign, requested number otherwise
  *
+ * Note that when this is called the new device has not yet been registered
+ * in the video_device array.
  *
- * returns -ENFILE if num is already in use, a free index number if
+ * Returns -ENFILE if num is already in use, a free index number if
  * successful.
  */
 static int get_index(struct video_device *vdev, int num)
@@ -162,9 +313,12 @@ static int get_index(struct video_device *vdev, int num)
                return -EINVAL;
        }
 
+       /* Some drivers do not set the parent. In that case always return 0. */
+       if (vdev->parent == NULL)
+               return 0;
+
        for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
                if (video_device[i] != NULL &&
-                   video_device[i] != vdev &&
                    video_device[i]->parent == vdev->parent) {
                        used |= 1 << video_device[i]->index;
                }
@@ -180,17 +334,15 @@ static int get_index(struct video_device *vdev, int num)
        return i > max_index ? -ENFILE : i;
 }
 
-static const struct file_operations video_fops;
-
-int video_register_device(struct video_device *vfd, int type, int nr)
+int video_register_device(struct video_device *vdev, int type, int nr)
 {
-       return video_register_device_index(vfd, type, nr, -1);
+       return video_register_device_index(vdev, type, nr, -1);
 }
 EXPORT_SYMBOL(video_register_device);
 
 /**
  *     video_register_device_index - register video4linux devices
- *     @vfd:  video device structure we want to register
+ *     @vdev: video device structure we want to register
  *     @type: type of device to register
  *     @nr:   which device number (0 == /dev/video0, 1 == /dev/video1, ...
  *             -1 == first free)
@@ -214,8 +366,7 @@ EXPORT_SYMBOL(video_register_device);
  *
  *     %VFL_TYPE_RADIO - A radio card
  */
-
-int video_register_device_index(struct video_device *vfd, int type, int nr,
+int video_register_device_index(struct video_device *vdev, int type, int nr,
                                        int index)
 {
        int i = 0;
@@ -223,14 +374,19 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
        int minor_offset = 0;
        int minor_cnt = VIDEO_NUM_DEVICES;
        const char *name_base;
-       void *priv = video_get_drvdata(vfd);
+       void *priv = video_get_drvdata(vdev);
 
-       /* the release callback MUST be present */
-       BUG_ON(!vfd->release);
+       /* A minor value of -1 marks this video device as never
+          having been registered */
+       if (vdev)
+               vdev->minor = -1;
 
-       if (vfd == NULL)
+       /* the release callback MUST be present */
+       WARN_ON(!vdev || !vdev->release);
+       if (!vdev || !vdev->release)
                return -EINVAL;
 
+       /* Part 1: check device type */
        switch (type) {
        case VFL_TYPE_GRABBER:
                name_base = "video";
@@ -250,8 +406,12 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
                return -EINVAL;
        }
 
-       vfd->vfl_type = type;
+       vdev->vfl_type = type;
+       vdev->cdev = NULL;
+       if (vdev->v4l2_dev)
+               vdev->parent = vdev->v4l2_dev->dev;
 
+       /* Part 2: find a free minor, kernel number and device index. */
 #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
        /* Keep the ranges for the first four types for historical
         * reasons.
@@ -282,10 +442,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
        }
 #endif
 
-       /* Initialize the character device */
-       cdev_init(&vfd->cdev, vfd->fops);
-       vfd->cdev.owner = vfd->fops->owner;
-       /* pick a minor number */
+       /* Pick a minor number */
        mutex_lock(&videodev_lock);
        nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr);
        if (nr == minor_cnt)
@@ -309,72 +466,92 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
                return -ENFILE;
        }
 #endif
-       vfd->minor = i + minor_offset;
-       vfd->num = nr;
+       vdev->minor = i + minor_offset;
+       vdev->num = nr;
        set_bit(nr, video_nums[type]);
-       BUG_ON(video_device[vfd->minor]);
-       video_device[vfd->minor] = vfd;
-
-       ret = get_index(vfd, index);
-       vfd->index = ret;
-
+       /* Should not happen since we thought this minor was free */
+       WARN_ON(video_device[vdev->minor] != NULL);
+       ret = vdev->index = get_index(vdev, index);
        mutex_unlock(&videodev_lock);
 
        if (ret < 0) {
                printk(KERN_ERR "%s: get_index failed\n", __func__);
-               goto fail_minor;
+               goto cleanup;
        }
 
-       ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1);
+       /* Part 3: Initialize the character device */
+       vdev->cdev = cdev_alloc();
+       if (vdev->cdev == NULL) {
+               ret = -ENOMEM;
+               goto cleanup;
+       }
+       if (vdev->fops->unlocked_ioctl)
+               vdev->cdev->ops = &v4l2_unlocked_fops;
+       else
+               vdev->cdev->ops = &v4l2_fops;
+       vdev->cdev->owner = vdev->fops->owner;
+       ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
        if (ret < 0) {
                printk(KERN_ERR "%s: cdev_add failed\n", __func__);
-               goto fail_minor;
+               kfree(vdev->cdev);
+               vdev->cdev = NULL;
+               goto cleanup;
        }
-       /* sysfs class */
-       memset(&vfd->dev, 0, sizeof(vfd->dev));
+
+       /* Part 4: register the device with sysfs */
+       memset(&vdev->dev, 0, sizeof(vdev->dev));
        /* The memset above cleared the device's drvdata, so
           put back the copy we made earlier. */
-       video_set_drvdata(vfd, priv);
-       vfd->dev.class = &video_class;
-       vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
-       if (vfd->parent)
-               vfd->dev.parent = vfd->parent;
-       sprintf(vfd->dev.bus_id, "%s%d", name_base, nr);
-       ret = device_register(&vfd->dev);
+       video_set_drvdata(vdev, priv);
+       vdev->dev.class = &video_class;
+       vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
+       if (vdev->parent)
+               vdev->dev.parent = vdev->parent;
+       dev_set_name(&vdev->dev, "%s%d", name_base, nr);
+       ret = device_register(&vdev->dev);
        if (ret < 0) {
                printk(KERN_ERR "%s: device_register failed\n", __func__);
-               goto del_cdev;
+               goto cleanup;
        }
-       /* Remember the cdev's release function */
-       vfd->cdev_release = vfd->cdev.kobj.ktype->release;
-       /* Install our own */
-       vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default;
-       return 0;
+       /* Register the release callback that will be called when the last
+          reference to the device goes away. */
+       vdev->dev.release = v4l2_device_release;
 
-del_cdev:
-       cdev_del(&vfd->cdev);
+       /* Part 5: Activate this minor. The char device can now be used. */
+       mutex_lock(&videodev_lock);
+       video_device[vdev->minor] = vdev;
+       mutex_unlock(&videodev_lock);
+       return 0;
 
-fail_minor:
+cleanup:
        mutex_lock(&videodev_lock);
-       video_device[vfd->minor] = NULL;
-       clear_bit(vfd->num, video_nums[type]);
+       if (vdev->cdev)
+               cdev_del(vdev->cdev);
+       clear_bit(vdev->num, video_nums[type]);
        mutex_unlock(&videodev_lock);
-       vfd->minor = -1;
+       /* Mark this video device as never having been registered. */
+       vdev->minor = -1;
        return ret;
 }
 EXPORT_SYMBOL(video_register_device_index);
 
 /**
  *     video_unregister_device - unregister a video4linux device
- *     @vfd: the device to unregister
+ *     @vdev: the device to unregister
  *
- *     This unregisters the passed device and deassigns the minor
- *     number. Future open calls will be met with errors.
+ *     This unregisters the passed device. Future open calls will
+ *     be met with errors.
  */
-
-void video_unregister_device(struct video_device *vfd)
+void video_unregister_device(struct video_device *vdev)
 {
-       device_unregister(&vfd->dev);
+       /* Check if vdev was ever registered at all */
+       if (!vdev || vdev->minor < 0)
+               return;
+
+       mutex_lock(&videodev_lock);
+       set_bit(V4L2_FL_UNREGISTERED, &vdev->flags);
+       mutex_unlock(&videodev_lock);
+       device_unregister(&vdev->dev);
 }
 EXPORT_SYMBOL(video_unregister_device);
 
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
new file mode 100644 (file)
index 0000000..9eefde0
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+    V4L2 device support.
+
+    Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+
+int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
+{
+       if (dev == NULL || v4l2_dev == NULL)
+               return -EINVAL;
+       /* Warn if we apparently re-register a device */
+       WARN_ON(dev_get_drvdata(dev));
+       INIT_LIST_HEAD(&v4l2_dev->subdevs);
+       spin_lock_init(&v4l2_dev->lock);
+       v4l2_dev->dev = dev;
+       snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
+                       dev->driver->name, dev->bus_id);
+       dev_set_drvdata(dev, v4l2_dev);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_register);
+
+void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
+{
+       struct v4l2_subdev *sd, *next;
+
+       if (v4l2_dev == NULL || v4l2_dev->dev == NULL)
+               return;
+       dev_set_drvdata(v4l2_dev->dev, NULL);
+       /* unregister subdevs */
+       list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
+               v4l2_device_unregister_subdev(sd);
+
+       v4l2_dev->dev = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_unregister);
+
+int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd)
+{
+       /* Check for valid input */
+       if (dev == NULL || sd == NULL || !sd->name[0])
+               return -EINVAL;
+       /* Warn if we apparently re-register a subdev */
+       WARN_ON(sd->dev);
+       if (!try_module_get(sd->owner))
+               return -ENODEV;
+       sd->dev = dev;
+       spin_lock(&dev->lock);
+       list_add_tail(&sd->list, &dev->subdevs);
+       spin_unlock(&dev->lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);
+
+void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
+{
+       /* return if it isn't registered */
+       if (sd == NULL || sd->dev == NULL)
+               return;
+       spin_lock(&sd->dev->lock);
+       list_del(&sd->list);
+       spin_unlock(&sd->dev->lock);
+       sd->dev = NULL;
+       module_put(sd->owner);
+}
+EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
index 710e1a40c422b1f787ce55b677b39ae4f029acff..b063381f4b3b99af4e75ae4e96c7ebd26b38d9d7 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * Authors:    Alan Cox, <alan@redhat.com> (version 1)
+ * Authors:    Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
  *              Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
  */
 
@@ -393,10 +393,8 @@ video_fix_command(unsigned int cmd)
  * Obsolete usercopy function - Should be removed soon
  */
 int
-video_usercopy(struct inode *inode, struct file *file,
-              unsigned int cmd, unsigned long arg,
-              int (*func)(struct inode *inode, struct file *file,
-                          unsigned int cmd, void *arg))
+video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+               v4l2_kioctl func)
 {
        char    sbuf[128];
        void    *mbuf = NULL;
@@ -458,7 +456,7 @@ video_usercopy(struct inode *inode, struct file *file,
        }
 
        /* call driver */
-       err = func(inode, file, cmd, parg);
+       err = func(file, cmd, parg);
        if (err == -ENOIOCTLCMD)
                err = -EINVAL;
        if (is_ext_ctrl) {
@@ -1481,9 +1479,15 @@ static int __video_do_ioctl(struct file *file,
        case VIDIOC_G_CROP:
        {
                struct v4l2_crop *p = arg;
+               __u32 type;
 
                if (!ops->vidioc_g_crop)
                        break;
+
+               type = p->type;
+               memset(p, 0, sizeof(*p));
+               p->type = type;
+
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_g_crop(file, fh, p);
                if (!ret)
@@ -1504,10 +1508,16 @@ static int __video_do_ioctl(struct file *file,
        case VIDIOC_CROPCAP:
        {
                struct v4l2_cropcap *p = arg;
+               __u32 type;
 
                /*FIXME: Should also show v4l2_fract pixelaspect */
                if (!ops->vidioc_cropcap)
                        break;
+
+               type = p->type;
+               memset(p, 0, sizeof(*p));
+               p->type = type;
+
                dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
                ret = ops->vidioc_cropcap(file, fh, p);
                if (!ret) {
@@ -1522,6 +1532,9 @@ static int __video_do_ioctl(struct file *file,
 
                if (!ops->vidioc_g_jpegcomp)
                        break;
+
+               memset(p, 0, sizeof(*p));
+
                ret = ops->vidioc_g_jpegcomp(file, fh, p);
                if (!ret)
                        dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1749,6 +1762,77 @@ static int __video_do_ioctl(struct file *file,
                ret = ops->vidioc_s_hw_freq_seek(file, fh, p);
                break;
        }
+       case VIDIOC_ENUM_FRAMESIZES:
+       {
+               struct v4l2_frmsizeenum *p = arg;
+
+               if (!ops->vidioc_enum_framesizes)
+                       break;
+
+               memset(p, 0, sizeof(*p));
+
+               ret = ops->vidioc_enum_framesizes(file, fh, p);
+               dbgarg(cmd,
+                       "index=%d, pixelformat=%d, type=%d ",
+                       p->index, p->pixel_format, p->type);
+               switch (p->type) {
+               case V4L2_FRMSIZE_TYPE_DISCRETE:
+                       dbgarg2("width = %d, height=%d\n",
+                               p->discrete.width, p->discrete.height);
+                       break;
+               case V4L2_FRMSIZE_TYPE_STEPWISE:
+                       dbgarg2("min %dx%d, max %dx%d, step %dx%d\n",
+                               p->stepwise.min_width,  p->stepwise.min_height,
+                               p->stepwise.step_width, p->stepwise.step_height,
+                               p->stepwise.max_width,  p->stepwise.max_height);
+                       break;
+               case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+                       dbgarg2("continuous\n");
+                       break;
+               default:
+                       dbgarg2("- Unknown type!\n");
+               }
+
+               break;
+       }
+       case VIDIOC_ENUM_FRAMEINTERVALS:
+       {
+               struct v4l2_frmivalenum *p = arg;
+
+               if (!ops->vidioc_enum_frameintervals)
+                       break;
+
+               memset(p, 0, sizeof(*p));
+
+               ret = ops->vidioc_enum_frameintervals(file, fh, p);
+               dbgarg(cmd,
+                       "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
+                       p->index, p->pixel_format,
+                       p->width, p->height, p->type);
+               switch (p->type) {
+               case V4L2_FRMIVAL_TYPE_DISCRETE:
+                       dbgarg2("fps=%d/%d\n",
+                               p->discrete.numerator,
+                               p->discrete.denominator);
+                       break;
+               case V4L2_FRMIVAL_TYPE_STEPWISE:
+                       dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n",
+                               p->stepwise.min.numerator,
+                               p->stepwise.min.denominator,
+                               p->stepwise.max.numerator,
+                               p->stepwise.max.denominator,
+                               p->stepwise.step.numerator,
+                               p->stepwise.step.denominator);
+                       break;
+               case V4L2_FRMIVAL_TYPE_CONTINUOUS:
+                       dbgarg2("continuous\n");
+                       break;
+               default:
+                       dbgarg2("- Unknown type!\n");
+               }
+               break;
+       }
+
        default:
        {
                if (!ops->vidioc_default)
@@ -1768,7 +1852,7 @@ static int __video_do_ioctl(struct file *file,
        return ret;
 }
 
-int __video_ioctl2(struct file *file,
+long __video_ioctl2(struct file *file,
               unsigned int cmd, unsigned long arg)
 {
        char    sbuf[128];
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
new file mode 100644 (file)
index 0000000..e3612f2
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+    V4L2 sub-device support.
+
+    Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+
+int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg)
+{
+       switch (cmd) {
+       case VIDIOC_QUERYCTRL:
+               return v4l2_subdev_call(sd, core, querymenu, arg);
+       case VIDIOC_G_CTRL:
+               return v4l2_subdev_call(sd, core, g_ctrl, arg);
+       case VIDIOC_S_CTRL:
+               return v4l2_subdev_call(sd, core, s_ctrl, arg);
+       case VIDIOC_QUERYMENU:
+               return v4l2_subdev_call(sd, core, queryctrl, arg);
+       case VIDIOC_LOG_STATUS:
+               return v4l2_subdev_call(sd, core, log_status);
+       case VIDIOC_G_CHIP_IDENT:
+               return v4l2_subdev_call(sd, core, g_chip_ident, arg);
+       case VIDIOC_INT_S_STANDBY:
+               return v4l2_subdev_call(sd, core, s_standby, arg ? (*(u32 *)arg) : 0);
+       case VIDIOC_INT_RESET:
+               return v4l2_subdev_call(sd, core, reset, arg ? (*(u32 *)arg) : 0);
+       case VIDIOC_INT_S_GPIO:
+               return v4l2_subdev_call(sd, core, s_gpio, arg ? (*(u32 *)arg) : 0);
+       case VIDIOC_INT_INIT:
+               return v4l2_subdev_call(sd, core, init, arg ? (*(u32 *)arg) : 0);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       case VIDIOC_DBG_G_REGISTER:
+               return v4l2_subdev_call(sd, core, g_register, arg);
+       case VIDIOC_DBG_S_REGISTER:
+               return v4l2_subdev_call(sd, core, s_register, arg);
+#endif
+
+       case VIDIOC_INT_S_TUNER_MODE:
+               return v4l2_subdev_call(sd, tuner, s_mode, *(enum v4l2_tuner_type *)arg);
+       case AUDC_SET_RADIO:
+               return v4l2_subdev_call(sd, tuner, s_radio);
+       case VIDIOC_S_TUNER:
+               return v4l2_subdev_call(sd, tuner, s_tuner, arg);
+       case VIDIOC_G_TUNER:
+               return v4l2_subdev_call(sd, tuner, g_tuner, arg);
+       case VIDIOC_S_STD:
+               return v4l2_subdev_call(sd, tuner, s_std, *(v4l2_std_id *)arg);
+       case VIDIOC_S_FREQUENCY:
+               return v4l2_subdev_call(sd, tuner, s_frequency, arg);
+       case VIDIOC_G_FREQUENCY:
+               return v4l2_subdev_call(sd, tuner, g_frequency, arg);
+       case TUNER_SET_TYPE_ADDR:
+               return v4l2_subdev_call(sd, tuner, s_type_addr, arg);
+       case TUNER_SET_CONFIG:
+               return v4l2_subdev_call(sd, tuner, s_config, arg);
+
+       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+               return v4l2_subdev_call(sd, audio, s_clock_freq, *(u32 *)arg);
+       case VIDIOC_INT_S_AUDIO_ROUTING:
+               return v4l2_subdev_call(sd, audio, s_routing, arg);
+       case VIDIOC_INT_I2S_CLOCK_FREQ:
+               return v4l2_subdev_call(sd, audio, s_i2s_clock_freq, *(u32 *)arg);
+
+       case VIDIOC_INT_S_VIDEO_ROUTING:
+               return v4l2_subdev_call(sd, video, s_routing, arg);
+       case VIDIOC_INT_S_CRYSTAL_FREQ:
+               return v4l2_subdev_call(sd, video, s_crystal_freq, arg);
+       case VIDIOC_INT_DECODE_VBI_LINE:
+               return v4l2_subdev_call(sd, video, decode_vbi_line, arg);
+       case VIDIOC_INT_S_VBI_DATA:
+               return v4l2_subdev_call(sd, video, s_vbi_data, arg);
+       case VIDIOC_INT_G_VBI_DATA:
+               return v4l2_subdev_call(sd, video, g_vbi_data, arg);
+       case VIDIOC_G_SLICED_VBI_CAP:
+               return v4l2_subdev_call(sd, video, g_sliced_vbi_cap, arg);
+       case VIDIOC_S_FMT:
+               return v4l2_subdev_call(sd, video, s_fmt, arg);
+       case VIDIOC_G_FMT:
+               return v4l2_subdev_call(sd, video, g_fmt, arg);
+       case VIDIOC_INT_S_STD_OUTPUT:
+               return v4l2_subdev_call(sd, video, s_std_output, *(v4l2_std_id *)arg);
+       case VIDIOC_STREAMON:
+               return v4l2_subdev_call(sd, video, s_stream, 1);
+       case VIDIOC_STREAMOFF:
+               return v4l2_subdev_call(sd, video, s_stream, 0);
+
+       default:
+               return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
+       }
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_command);
index 1efc5f3462c6ce8fa6e8edc45c45c7aceb445499..a72a361daade1b33b92a5f6911d998e6bfe13685 100644 (file)
@@ -4237,8 +4237,7 @@ error:
        return ret;
 }
 
-static int vino_do_ioctl(struct inode *inode, struct file *file,
-                     unsigned int cmd, void *arg)
+static int vino_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct vino_channel_settings *vcs = video_drvdata(file);
 
@@ -4353,7 +4352,7 @@ static int vino_ioctl(struct inode *inode, struct file *file,
        if (mutex_lock_interruptible(&vcs->mutex))
                return -EINTR;
 
-       ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl);
+       ret = video_usercopy(file, cmd, arg, vino_do_ioctl);
 
        mutex_unlock(&vcs->mutex);
 
index 577956c5410bf44b478ff8f8166b3a38edb5026a..f72b859486ada73f1725641f9a7cedcd4b272767 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 
@@ -40,13 +40,20 @@ MODULE_LICENSE("GPL");
 /* ----------------------------------------------------------------------- */
 
 struct vp27smpx_state {
+       struct v4l2_subdev sd;
        int radio;
        u32 audmode;
 };
 
-static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
+static inline struct vp27smpx_state *to_state(struct v4l2_subdev *sd)
 {
-       struct vp27smpx_state *state = i2c_get_clientdata(client);
+       return container_of(sd, struct vp27smpx_state, sd);
+}
+
+static void vp27smpx_set_audmode(struct v4l2_subdev *sd, u32 audmode)
+{
+       struct vp27smpx_state *state = to_state(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        u8 data[3] = { 0x00, 0x00, 0x04 };
 
        switch (audmode) {
@@ -63,55 +70,89 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
        }
 
        if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
-               v4l_err(client, "%s: I/O error setting audmode\n",
-                               client->name);
+               v4l2_err(sd, "I/O error setting audmode\n");
        else
                state->audmode = audmode;
 }
 
-static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int vp27smpx_s_radio(struct v4l2_subdev *sd)
 {
-       struct vp27smpx_state *state = i2c_get_clientdata(client);
-       struct v4l2_tuner *vt = arg;
+       struct vp27smpx_state *state = to_state(sd);
 
-       switch (cmd) {
-       case AUDC_SET_RADIO:
-               state->radio = 1;
-               break;
+       state->radio = 1;
+       return 0;
+}
 
-       case VIDIOC_S_STD:
-               state->radio = 0;
-               break;
+static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       struct vp27smpx_state *state = to_state(sd);
 
-       case VIDIOC_S_TUNER:
-               if (!state->radio)
-                       vp27smpx_set_audmode(client, vt->audmode);
-               break;
+       state->radio = 0;
+       return 0;
+}
 
-       case VIDIOC_G_TUNER:
-               if (state->radio)
-                       break;
-               vt->audmode = state->audmode;
-               vt->capability = V4L2_TUNER_CAP_STEREO |
-                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
-               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
-               break;
+static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct vp27smpx_state *state = to_state(sd);
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client, arg,
-                               V4L2_IDENT_VP27SMPX, 0);
+       if (!state->radio)
+               vp27smpx_set_audmode(sd, vt->audmode);
+       return 0;
+}
 
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
-                               state->radio ? " (Radio)" : "");
-               break;
+static int vp27smpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+       struct vp27smpx_state *state = to_state(sd);
+
+       if (state->radio)
+               return 0;
+       vt->audmode = state->audmode;
+       vt->capability = V4L2_TUNER_CAP_STEREO |
+               V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+       return 0;
+}
 
-       default:
-               return -EINVAL;
-       }
+static int vp27smpx_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_VP27SMPX, 0);
+}
+
+static int vp27smpx_log_status(struct v4l2_subdev *sd)
+{
+       struct vp27smpx_state *state = to_state(sd);
+
+       v4l2_info(sd, "Audio Mode: %u%s\n", state->audmode,
+                       state->radio ? " (Radio)" : "");
        return 0;
 }
 
+static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
+       .log_status = vp27smpx_log_status,
+       .g_chip_ident = vp27smpx_g_chip_ident,
+};
+
+static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = {
+       .s_radio = vp27smpx_s_radio,
+       .s_std = vp27smpx_s_std,
+       .s_tuner = vp27smpx_s_tuner,
+       .g_tuner = vp27smpx_g_tuner,
+};
+
+static const struct v4l2_subdev_ops vp27smpx_ops = {
+       .core = &vp27smpx_core_ops,
+       .tuner = &vp27smpx_tuner_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 /* i2c implementation */
@@ -125,6 +166,7 @@ static int vp27smpx_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
        struct vp27smpx_state *state;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -136,17 +178,21 @@ static int vp27smpx_probe(struct i2c_client *client,
        state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &vp27smpx_ops);
        state->audmode = V4L2_TUNER_MODE_STEREO;
-       i2c_set_clientdata(client, state);
 
        /* initialize vp27smpx */
-       vp27smpx_set_audmode(client, state->audmode);
+       vp27smpx_set_audmode(sd, state->audmode);
        return 0;
 }
 
 static int vp27smpx_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index b2dbe48a92bbd72360b1fec3dea0e59806dc671f..56c570c267ea1f6f110678867809d606642c3e7f 100644 (file)
@@ -727,8 +727,7 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
  *     Video4linux interfacing
  */
 
-static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg)
+static int w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct w9966_dev *cam = video_drvdata(file);
 
@@ -881,7 +880,7 @@ static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file,
 static int w9966_v4l_ioctl(struct inode *inode, struct file *file,
                           unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, w9966_v4l_do_ioctl);
+       return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl);
 }
 
 // Capture data
index 54ac3fe26ec2ad4afe2371ae069caa25f9aa1597..12a31e7a5f6de31fbebce5fe93aa8ebfe0797f16 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv.h>
 
@@ -52,6 +52,7 @@ enum {
 };
 
 struct wm8739_state {
+       struct v4l2_subdev sd;
        u32 clock_freq;
        u8 muted;
        u16 volume;
@@ -60,43 +61,49 @@ struct wm8739_state {
        u8 vol_r;               /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
 };
 
+static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct wm8739_state, sd);
+}
+
 /* ------------------------------------------------------------------------ */
 
-static int wm8739_write(struct i2c_client *client, int reg, u16 val)
+static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int i;
 
        if (reg < 0 || reg >= TOT_REGS) {
-               v4l_err(client, "Invalid register R%d\n", reg);
+               v4l2_err(sd, "Invalid register R%d\n", reg);
                return -1;
        }
 
-       v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
+       v4l2_dbg(1, debug, sd, "write: %02x %02x\n", reg, val);
 
        for (i = 0; i < 3; i++)
                if (i2c_smbus_write_byte_data(client,
                                (reg << 1) | (val >> 8), val & 0xff) == 0)
                        return 0;
-       v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+       v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
 
 /* write regs to set audio volume etc */
-static void wm8739_set_audio(struct i2c_client *client)
+static void wm8739_set_audio(struct v4l2_subdev *sd)
 {
-       struct wm8739_state *state = i2c_get_clientdata(client);
+       struct wm8739_state *state = to_state(sd);
        u16 mute = state->muted ? 0x80 : 0;
 
        /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
         * Default setting: 0x17 = 0 dB
         */
-       wm8739_write(client, R0, (state->vol_l & 0x1f) | mute);
-       wm8739_write(client, R1, (state->vol_r & 0x1f) | mute);
+       wm8739_write(sd, R0, (state->vol_l & 0x1f) | mute);
+       wm8739_write(sd, R1, (state->vol_r & 0x1f) | mute);
 }
 
-static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int wm8739_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct wm8739_state *state = i2c_get_clientdata(client);
+       struct wm8739_state *state = to_state(sd);
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
@@ -117,9 +124,9 @@ static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        return 0;
 }
 
-static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int wm8739_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-       struct wm8739_state *state = i2c_get_clientdata(client);
+       struct wm8739_state *state = to_state(sd);
        unsigned int work_l, work_r;
 
        switch (ctrl->id) {
@@ -147,7 +154,7 @@ static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
        state->vol_r = (long)work_r * 31 / 65535;
 
        /* set audio volume etc. */
-       wm8739_set_audio(client);
+       wm8739_set_audio(sd);
        return 0;
 }
 
@@ -186,77 +193,89 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
 
 /* ------------------------------------------------------------------------ */
 
-static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
 {
-       struct wm8739_state *state = i2c_get_clientdata(client);
-
-       switch (cmd) {
-       case VIDIOC_INT_AUDIO_CLOCK_FREQ:
-       {
-               u32 audiofreq = *(u32 *)arg;
-
-               state->clock_freq = audiofreq;
-               /* de-activate */
-               wm8739_write(client, R9, 0x000);
-               switch (audiofreq) {
-               case 44100:
-                       /* 256fps, fs=44.1k */
-                       wm8739_write(client, R8, 0x020);
-                       break;
-               case 48000:
-                       /* 256fps, fs=48k */
-                       wm8739_write(client, R8, 0x000);
-                       break;
-               case 32000:
-                       /* 256fps, fs=32k */
-                       wm8739_write(client, R8, 0x018);
-                       break;
-               default:
-                       break;
-               }
-               /* activate */
-               wm8739_write(client, R9, 0x001);
+       struct wm8739_state *state = to_state(sd);
+
+       state->clock_freq = audiofreq;
+       /* de-activate */
+       wm8739_write(sd, R9, 0x000);
+       switch (audiofreq) {
+       case 44100:
+               /* 256fps, fs=44.1k */
+               wm8739_write(sd, R8, 0x020);
+               break;
+       case 48000:
+               /* 256fps, fs=48k */
+               wm8739_write(sd, R8, 0x000);
+               break;
+       case 32000:
+               /* 256fps, fs=32k */
+               wm8739_write(sd, R8, 0x018);
+               break;
+       default:
                break;
        }
+       /* activate */
+       wm8739_write(sd, R9, 0x001);
+       return 0;
+}
 
-       case VIDIOC_G_CTRL:
-               return wm8739_get_ctrl(client, arg);
-
-       case VIDIOC_S_CTRL:
-               return wm8739_set_ctrl(client, arg);
+static int wm8739_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       int i;
 
-       case VIDIOC_QUERYCTRL:
-       {
-               struct v4l2_queryctrl *qc = arg;
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
-                       if (qc->id && qc->id == wm8739_qctrl[i].id) {
-                               memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
-                               return 0;
-                       }
-               return -EINVAL;
-       }
+       for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++)
+               if (qc->id && qc->id == wm8739_qctrl[i].id) {
+                       memcpy(qc, &wm8739_qctrl[i], sizeof(*qc));
+                       return 0;
+               }
+       return -EINVAL;
+}
 
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client,
-                               arg, V4L2_IDENT_WM8739, 0);
+static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
 
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
-               v4l_info(client, "Volume L:  %02x%s\n", state->vol_l & 0x1f,
-                               state->muted ? " (muted)" : "");
-               v4l_info(client, "Volume R:  %02x%s\n", state->vol_r & 0x1f,
-                               state->muted ? " (muted)" : "");
-               break;
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8739, 0);
+}
 
-       default:
-               return -EINVAL;
-       }
+static int wm8739_log_status(struct v4l2_subdev *sd)
+{
+       struct wm8739_state *state = to_state(sd);
 
+       v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq);
+       v4l2_info(sd, "Volume L:  %02x%s\n", state->vol_l & 0x1f,
+                       state->muted ? " (muted)" : "");
+       v4l2_info(sd, "Volume R:  %02x%s\n", state->vol_r & 0x1f,
+                       state->muted ? " (muted)" : "");
        return 0;
 }
 
+static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops wm8739_core_ops = {
+       .log_status = wm8739_log_status,
+       .g_chip_ident = wm8739_g_chip_ident,
+       .queryctrl = wm8739_queryctrl,
+       .g_ctrl = wm8739_g_ctrl,
+       .s_ctrl = wm8739_s_ctrl,
+};
+
+static const struct v4l2_subdev_audio_ops wm8739_audio_ops = {
+       .s_clock_freq = wm8739_s_clock_freq,
+};
+
+static const struct v4l2_subdev_ops wm8739_ops = {
+       .core = &wm8739_core_ops,
+       .audio = &wm8739_audio_ops,
+};
+
 /* ------------------------------------------------------------------------ */
 
 /* i2c implementation */
@@ -265,6 +284,7 @@ static int wm8739_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct wm8739_state *state;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -276,6 +296,8 @@ static int wm8739_probe(struct i2c_client *client,
        state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &wm8739_ops);
        state->vol_l = 0x17; /* 0dB */
        state->vol_r = 0x17; /* 0dB */
        state->muted = 0;
@@ -283,31 +305,33 @@ static int wm8739_probe(struct i2c_client *client,
        /* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */
        state->volume = ((long)state->vol_l + 1) * 65535 / 31;
        state->clock_freq = 48000;
-       i2c_set_clientdata(client, state);
 
        /* Initialize wm8739 */
 
        /* reset */
-       wm8739_write(client, R15, 0x00);
+       wm8739_write(sd, R15, 0x00);
        /* filter setting, high path, offet clear */
-       wm8739_write(client, R5, 0x000);
+       wm8739_write(sd, R5, 0x000);
        /* ADC, OSC, Power Off mode Disable */
-       wm8739_write(client, R6, 0x000);
+       wm8739_write(sd, R6, 0x000);
        /* Digital Audio interface format:
           Enable Master mode, 24 bit, MSB first/left justified */
-       wm8739_write(client, R7, 0x049);
+       wm8739_write(sd, R7, 0x049);
        /* sampling control: normal, 256fs, 48KHz sampling rate */
-       wm8739_write(client, R8, 0x000);
+       wm8739_write(sd, R8, 0x000);
        /* activate */
-       wm8739_write(client, R9, 0x001);
+       wm8739_write(sd, R9, 0x001);
        /* set volume/mute */
-       wm8739_set_audio(client);
+       wm8739_set_audio(sd);
        return 0;
 }
 
 static int wm8739_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index 48df661d4fc320aa8426b1c7ffc085941730e90b..d0220b0ec0bcf331320ad89d67b398f617609773 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
 #include <linux/videodev2.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-i2c-drv-legacy.h>
 
@@ -54,16 +54,23 @@ enum {
 };
 
 struct wm8775_state {
+       struct v4l2_subdev sd;
        u8 input;               /* Last selected input (0-0xf) */
        u8 muted;
 };
 
-static int wm8775_write(struct i2c_client *client, int reg, u16 val)
+static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
 {
+       return container_of(sd, struct wm8775_state, sd);
+}
+
+static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
        int i;
 
        if (reg < 0 || reg >= TOT_REGS) {
-               v4l_err(client, "Invalid register R%d\n", reg);
+               v4l2_err(sd, "Invalid register R%d\n", reg);
                return -1;
        }
 
@@ -71,84 +78,117 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
                if (i2c_smbus_write_byte_data(client,
                                (reg << 1) | (val >> 8), val & 0xff) == 0)
                        return 0;
-       v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+       v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
        return -1;
 }
 
-static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
+static int wm8775_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
 {
-       struct wm8775_state *state = i2c_get_clientdata(client);
-       struct v4l2_routing *route = arg;
-       struct v4l2_control *ctrl = arg;
-
-       switch (cmd) {
-       case VIDIOC_INT_G_AUDIO_ROUTING:
-               route->input = state->input;
-               route->output = 0;
-               break;
-
-       case VIDIOC_INT_S_AUDIO_ROUTING:
-               /* There are 4 inputs and one output. Zero or more inputs
-                  are multiplexed together to the output. Hence there are
-                  16 combinations.
-                  If only one input is active (the normal case) then the
-                  input values 1, 2, 4 or 8 should be used. */
-               if (route->input > 15) {
-                       v4l_err(client, "Invalid input %d.\n", route->input);
-                       return -EINVAL;
-               }
-               state->input = route->input;
-               if (state->muted)
-                       break;
-               wm8775_write(client, R21, 0x0c0);
-               wm8775_write(client, R14, 0x1d4);
-               wm8775_write(client, R15, 0x1d4);
-               wm8775_write(client, R21, 0x100 + state->input);
-               break;
-
-       case VIDIOC_G_CTRL:
-               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               ctrl->value = state->muted;
-               break;
-
-       case VIDIOC_S_CTRL:
-               if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-                       return -EINVAL;
-               state->muted = ctrl->value;
-               wm8775_write(client, R21, 0x0c0);
-               wm8775_write(client, R14, 0x1d4);
-               wm8775_write(client, R15, 0x1d4);
-               if (!state->muted)
-                       wm8775_write(client, R21, 0x100 + state->input);
-               break;
-
-       case VIDIOC_G_CHIP_IDENT:
-               return v4l2_chip_ident_i2c_client(client,
-                               arg, V4L2_IDENT_WM8775, 0);
-
-       case VIDIOC_LOG_STATUS:
-               v4l_info(client, "Input: %d%s\n", state->input,
-                           state->muted ? " (muted)" : "");
-               break;
-
-       case VIDIOC_S_FREQUENCY:
-               /* If I remove this, then it can happen that I have no
-                  sound the first time I tune from static to a valid channel.
-                  It's difficult to reproduce and is almost certainly related
-                  to the zero cross detect circuit. */
-               wm8775_write(client, R21, 0x0c0);
-               wm8775_write(client, R14, 0x1d4);
-               wm8775_write(client, R15, 0x1d4);
-               wm8775_write(client, R21, 0x100 + state->input);
-               break;
-
-       default:
+       struct wm8775_state *state = to_state(sd);
+
+       /* There are 4 inputs and one output. Zero or more inputs
+          are multiplexed together to the output. Hence there are
+          16 combinations.
+          If only one input is active (the normal case) then the
+          input values 1, 2, 4 or 8 should be used. */
+       if (route->input > 15) {
+               v4l2_err(sd, "Invalid input %d.\n", route->input);
                return -EINVAL;
        }
+       state->input = route->input;
+       if (state->muted)
+               return 0;
+       wm8775_write(sd, R21, 0x0c0);
+       wm8775_write(sd, R14, 0x1d4);
+       wm8775_write(sd, R15, 0x1d4);
+       wm8775_write(sd, R21, 0x100 + state->input);
+       return 0;
+}
+
+static int wm8775_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct wm8775_state *state = to_state(sd);
+
+       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       ctrl->value = state->muted;
+       return 0;
+}
+
+static int wm8775_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct wm8775_state *state = to_state(sd);
+
+       if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+               return -EINVAL;
+       state->muted = ctrl->value;
+       wm8775_write(sd, R21, 0x0c0);
+       wm8775_write(sd, R14, 0x1d4);
+       wm8775_write(sd, R15, 0x1d4);
+       if (!state->muted)
+               wm8775_write(sd, R21, 0x100 + state->input);
+       return 0;
+}
+
+static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_WM8775, 0);
+}
+
+static int wm8775_log_status(struct v4l2_subdev *sd)
+{
+       struct wm8775_state *state = to_state(sd);
+
+       v4l2_info(sd, "Input: %d%s\n", state->input,
+                       state->muted ? " (muted)" : "");
        return 0;
 }
 
+static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+{
+       struct wm8775_state *state = to_state(sd);
+
+       /* If I remove this, then it can happen that I have no
+          sound the first time I tune from static to a valid channel.
+          It's difficult to reproduce and is almost certainly related
+          to the zero cross detect circuit. */
+       wm8775_write(sd, R21, 0x0c0);
+       wm8775_write(sd, R14, 0x1d4);
+       wm8775_write(sd, R15, 0x1d4);
+       wm8775_write(sd, R21, 0x100 + state->input);
+       return 0;
+}
+
+static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+       return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops wm8775_core_ops = {
+       .log_status = wm8775_log_status,
+       .g_chip_ident = wm8775_g_chip_ident,
+       .g_ctrl = wm8775_g_ctrl,
+       .s_ctrl = wm8775_s_ctrl,
+};
+
+static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
+       .s_frequency = wm8775_s_frequency,
+};
+
+static const struct v4l2_subdev_audio_ops wm8775_audio_ops = {
+       .s_routing = wm8775_s_routing,
+};
+
+static const struct v4l2_subdev_ops wm8775_ops = {
+       .core = &wm8775_core_ops,
+       .tuner = &wm8775_tuner_ops,
+       .audio = &wm8775_audio_ops,
+};
+
 /* ----------------------------------------------------------------------- */
 
 /* i2c implementation */
@@ -162,56 +202,61 @@ static int wm8775_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct wm8775_state *state;
+       struct v4l2_subdev *sd;
 
        /* Check if the adapter supports the needed features */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       v4l_info(client, "chip found @ 0x%x (%s)\n",
+       v4l_info(client, "chip found @ 0x%02x (%s)\n",
                        client->addr << 1, client->adapter->name);
 
        state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
        if (state == NULL)
                return -ENOMEM;
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
        state->input = 2;
        state->muted = 0;
-       i2c_set_clientdata(client, state);
 
        /* Initialize wm8775 */
 
        /* RESET */
-       wm8775_write(client, R23, 0x000);
+       wm8775_write(sd, R23, 0x000);
        /* Disable zero cross detect timeout */
-       wm8775_write(client, R7, 0x000);
+       wm8775_write(sd, R7, 0x000);
        /* Left justified, 24-bit mode */
-       wm8775_write(client, R11, 0x021);
+       wm8775_write(sd, R11, 0x021);
        /* Master mode, clock ratio 256fs */
-       wm8775_write(client, R12, 0x102);
+       wm8775_write(sd, R12, 0x102);
        /* Powered up */
-       wm8775_write(client, R13, 0x000);
+       wm8775_write(sd, R13, 0x000);
        /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(client, R14, 0x1d4);
+       wm8775_write(sd, R14, 0x1d4);
        /* ADC gain +2.5dB, enable zero cross */
-       wm8775_write(client, R15, 0x1d4);
+       wm8775_write(sd, R15, 0x1d4);
        /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
-       wm8775_write(client, R16, 0x1bf);
+       wm8775_write(sd, R16, 0x1bf);
        /* Enable gain control, use zero cross detection,
           ALC hold time 42.6 ms */
-       wm8775_write(client, R17, 0x185);
+       wm8775_write(sd, R17, 0x185);
        /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
-       wm8775_write(client, R18, 0x0a2);
+       wm8775_write(sd, R18, 0x0a2);
        /* Enable noise gate, threshold -72dBfs */
-       wm8775_write(client, R19, 0x005);
+       wm8775_write(sd, R19, 0x005);
        /* Transient window 4ms, lower PGA gain limit -1dB */
-       wm8775_write(client, R20, 0x07a);
+       wm8775_write(sd, R20, 0x07a);
        /* LRBOTH = 1, use input 2. */
-       wm8775_write(client, R21, 0x102);
+       wm8775_write(sd, R21, 0x102);
        return 0;
 }
 
 static int wm8775_remove(struct i2c_client *client)
 {
-       kfree(i2c_get_clientdata(client));
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
        return 0;
 }
 
index 9fc58170763827d241e50c7deb28a4077941e1c4..9d00e6056491b1a9baeb6fc305e48ee87bdd9f31 100644 (file)
@@ -1020,7 +1020,7 @@ zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
 
        strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
        if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+               strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
                        sizeof(cap.bus_info));
 
        if (copy_to_user(arg, &cap, sizeof(cap)))
index fa5f2f8f518a1e37dab4e2ba6150e41c71295c24..05f39195372e00def2749ee47428db426f63c7a1 100644 (file)
@@ -153,12 +153,6 @@ MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
 MODULE_AUTHOR("Serguei Miridonov");
 MODULE_LICENSE("GPL");
 
-static struct pci_device_id zr36067_pci_tbl[] = {
-       {PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       {0}
-};
-MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
 
 int zoran_num;                 /* number of Buzs in use */
 struct zoran *zoran[BUZ_MAX];
index db11ab9e60da289e9073c792dce72415b4ca632c..00b97d97aeaa612275e7cab190a7823fbcf1a1da 100644 (file)
@@ -1940,11 +1940,7 @@ zoran_set_input (struct zoran *zr,
  *   ioctl routine
  */
 
-static int
-zoran_do_ioctl (struct inode *inode,
-               struct file  *file,
-               unsigned int  cmd,
-               void         *arg)
+static int zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct zoran_fh *fh = file->private_data;
        struct zoran *zr = fh->zr;
@@ -4201,7 +4197,7 @@ zoran_ioctl (struct inode *inode,
             unsigned int  cmd,
             unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, zoran_do_ioctl);
+       return video_usercopy(file, cmd, arg, zoran_do_ioctl);
 }
 
 static unsigned int
index e4c0db4dc7b199cfad30f9f4e318c54bc31d0e61..9e485459f63b389c0a63a7139dcb18bbab6bba2e 100644 (file)
@@ -474,9 +474,9 @@ static __init int asic3_gpio_probe(struct platform_device *pdev,
        u16 dir_reg[ASIC3_NUM_GPIO_BANKS];
        int i;
 
-       memzero(alt_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
-       memzero(out_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
-       memzero(dir_reg, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
+       memset(alt_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
+       memset(out_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
+       memset(dir_reg, 0, ASIC3_NUM_GPIO_BANKS * sizeof(u16));
 
        /* Enable all GPIOs */
        asic3_write_register(asic, ASIC3_GPIO_OFFSET(A, MASK), 0xffff);
index b4ed57e027291ae3d3dcbec83e2cd8761d3fb70c..6063dc2b52e8878d2bd60b01b7a99b632dccdb79 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <asm/system.h>
 
 #include "mcp.h"
index 28380b20bc70475677943e11ba1cc79c871f1255..62b32dabf629e9a98ba15407ad28a1542a294abe 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/system.h>
index 61aeaf79640dc7d9632b8fe15c73aaea4b71dc22..86fed4870f933bed1d8682d10556e12503c5265e 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 #include "ucb1x00.h"
 
index a316f1b759332ff763e76b4a04f9d897daed3130..6860c924f3643a6f8ab679485a8b2e322cb1ac01 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/hardware.h>
 
 #include "ucb1x00.h"
index 44762ca86a8d45bbe41e640d7a4d22c2e098ac83..61b7d3eb9a2f524da4707e6dd828516cffb30b38 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/slab.h>
 #include <linux/kthread.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/collie.h>
 #include <asm/mach-types.h>
 
index 2f0fcdb869b76995904c361af677b686bc986ca3..eb29b1d933acbcae19611300805f7151ac4ec859 100644 (file)
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Changed to conform redesigned i.MX scatter gather DMA interface
- *
- *  2005-11-04 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             Updated for 2.6.14 kernel
- *
- *  2005-12-13 Jay Monkman <jtm@smoothsmoothie.com>
- *             Found and corrected problems in the write path
- *
- *  2005-12-30 Pavel Pisa <pisa@cmp.felk.cvut.cz>
- *             The event handling rewritten right way in softirq.
- *             Added many ugly hacks and delays to overcome SDHC
- *             deficiencies
- *
  */
 
 #include <linux/module.h>
@@ -37,9 +23,9 @@
 #include <linux/mmc/card.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <asm/dma.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/sizes.h>
 #include <mach/mmc.h>
 #define DRIVER_NAME "imx-mmc"
 
 #define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
-                     INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
-                     INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
+                                INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
+                                INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
 
 struct imxmci_host {
        struct mmc_host         *mmc;
        spinlock_t              lock;
        struct resource         *res;
+       void __iomem            *base;
        int                     irq;
        imx_dmach_t             dma;
-       unsigned int            clkrt;
-       unsigned int            cmdat;
        volatile unsigned int   imask;
        unsigned int            power_mode;
        unsigned int            present;
@@ -74,7 +59,7 @@ struct imxmci_host {
        struct tasklet_struct   tasklet;
        unsigned int            status_reg;
        unsigned long           pending_events;
-       /* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */
+       /* Next two fields are there for CPU driven transfers to overcome SDHC deficiencies */
        u16                     *data_ptr;
        unsigned int            data_cnt;
        atomic_t                stuck_timeout;
@@ -114,14 +99,22 @@ struct imxmci_host {
 static void imxmci_stop_clock(struct imxmci_host *host)
 {
        int i = 0;
-       MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK;
-       while(i < 0x1000) {
-               if(!(i & 0x7f))
-                       MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK;
+       u16 reg;
+
+       reg = readw(host->base + MMC_REG_STR_STP_CLK);
+       writew(reg & ~STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
+       while (i < 0x1000) {
+               if (!(i & 0x7f)) {
+                       reg = readw(host->base + MMC_REG_STR_STP_CLK);
+                       writew(reg | STR_STP_CLK_STOP_CLK,
+                                       host->base + MMC_REG_STR_STP_CLK);
+               }
 
-               if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) {
+               reg = readw(host->base + MMC_REG_STATUS);
+               if (!(reg & STATUS_CARD_BUS_CLK_RUN)) {
                        /* Check twice before cut */
-                       if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN))
+                       reg = readw(host->base + MMC_REG_STATUS);
+                       if (!(reg & STATUS_CARD_BUS_CLK_RUN))
                                return;
                }
 
@@ -135,8 +128,10 @@ static int imxmci_start_clock(struct imxmci_host *host)
        unsigned int trials = 0;
        unsigned int delay_limit = 128;
        unsigned long flags;
+       u16 reg;
 
-       MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK;
+       reg = readw(host->base + MMC_REG_STR_STP_CLK);
+       writew(reg & ~STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
 
        clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
 
@@ -145,18 +140,21 @@ static int imxmci_start_clock(struct imxmci_host *host)
         * then 6 delay loops, but during card detection (low clockrate)
         * it takes up to 5000 delay loops and sometimes fails for the first time
         */
-       MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+       reg = readw(host->base + MMC_REG_STR_STP_CLK);
+       writew(reg | STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
 
        do {
                unsigned int delay = delay_limit;
 
-               while(delay--){
-                       if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+               while (delay--) {
+                       reg = readw(host->base + MMC_REG_STATUS);
+                       if (reg & STATUS_CARD_BUS_CLK_RUN)
                                /* Check twice before cut */
-                               if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)
+                               reg = readw(host->base + MMC_REG_STATUS);
+                               if (reg & STATUS_CARD_BUS_CLK_RUN)
                                        return 0;
 
-                       if(test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
+                       if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
                                return 0;
                }
 
@@ -167,58 +165,59 @@ static int imxmci_start_clock(struct imxmci_host *host)
                 * IRQ or schedule delays this function execution and the clocks has
                 * been already stopped by other means (response processing, SDHC HW)
                 */
-               if(!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
-                       MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK;
+               if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) {
+                       reg = readw(host->base + MMC_REG_STR_STP_CLK);
+                       writew(reg | STR_STP_CLK_START_CLK,
+                                       host->base + MMC_REG_STR_STP_CLK);
+               }
                local_irq_restore(flags);
 
-       } while(++trials<256);
+       } while (++trials < 256);
 
        dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
 
        return -1;
 }
 
-static void imxmci_softreset(void)
+static void imxmci_softreset(struct imxmci_host *host)
 {
+       int i;
+
        /* reset sequence */
-       MMC_STR_STP_CLK = 0x8;
-       MMC_STR_STP_CLK = 0xD;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-       MMC_STR_STP_CLK = 0x5;
-
-       MMC_RES_TO = 0xff;
-       MMC_BLK_LEN = 512;
-       MMC_NOB = 1;
+       writew(0x08, host->base + MMC_REG_STR_STP_CLK);
+       writew(0x0D, host->base + MMC_REG_STR_STP_CLK);
+
+       for (i = 0; i < 8; i++)
+               writew(0x05, host->base + MMC_REG_STR_STP_CLK);
+
+       writew(0xff, host->base + MMC_REG_RES_TO);
+       writew(512, host->base + MMC_REG_BLK_LEN);
+       writew(1, host->base + MMC_REG_NOB);
 }
 
 static int imxmci_busy_wait_for_status(struct imxmci_host *host,
-                       unsigned int *pstat, unsigned int stat_mask,
-                       int timeout, const char *where)
+                                      unsigned int *pstat, unsigned int stat_mask,
+                                      int timeout, const char *where)
 {
-       int loops=0;
-       while(!(*pstat & stat_mask)) {
-               loops+=2;
-               if(loops >= timeout) {
+       int loops = 0;
+
+       while (!(*pstat & stat_mask)) {
+               loops += 2;
+               if (loops >= timeout) {
                        dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
                                where, *pstat, stat_mask);
                        return -1;
                }
                udelay(2);
-               *pstat |= MMC_STATUS;
+               *pstat |= readw(host->base + MMC_REG_STATUS);
        }
-       if(!loops)
+       if (!loops)
                return 0;
 
        /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
-       if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000))
+       if (!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock >= 8000000))
                dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
-                       loops, where, *pstat, stat_mask);
+                        loops, where, *pstat, stat_mask);
        return loops;
 }
 
@@ -235,8 +234,8 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
        host->data = data;
        data->bytes_xfered = 0;
 
-       MMC_NOB = nob;
-       MMC_BLK_LEN = blksz;
+       writew(nob, host->base + MMC_REG_NOB);
+       writew(blksz, host->base + MMC_REG_BLK_LEN);
 
        /*
         * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
@@ -252,14 +251,14 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
                        host->dma_dir = DMA_FROM_DEVICE;
 
                        /* Hack to enable read SCR */
-                       MMC_NOB = 1;
-                       MMC_BLK_LEN = 512;
+                       writew(1, host->base + MMC_REG_NOB);
+                       writew(512, host->base + MMC_REG_BLK_LEN);
                } else {
                        host->dma_dir = DMA_TO_DEVICE;
                }
 
                /* Convert back to virtual address */
-               host->data_ptr = (u16*)sg_virt(data->sg);
+               host->data_ptr = (u16 *)sg_virt(data->sg);
                host->data_cnt = 0;
 
                clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
@@ -271,10 +270,11 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
        if (data->flags & MMC_DATA_READ) {
                host->dma_dir = DMA_FROM_DEVICE;
                host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                               data->sg_len,  host->dma_dir);
+                                            data->sg_len,  host->dma_dir);
 
                imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
-                       host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ);
+                                host->res->start + MMC_REG_BUFFER_ACCESS,
+                                DMA_MODE_READ);
 
                /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
                CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
@@ -282,10 +282,11 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
                host->dma_dir = DMA_TO_DEVICE;
 
                host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
-                                               data->sg_len,  host->dma_dir);
+                                            data->sg_len,  host->dma_dir);
 
                imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
-                       host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE);
+                                host->res->start + MMC_REG_BUFFER_ACCESS,
+                                DMA_MODE_WRITE);
 
                /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
                CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
@@ -293,12 +294,12 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
 
 #if 1  /* This code is there only for consistency checking and can be disabled in future */
        host->dma_size = 0;
-       for(i=0; i<host->dma_nents; i++)
-               host->dma_size+=data->sg[i].length;
+       for (i = 0; i < host->dma_nents; i++)
+               host->dma_size += data->sg[i].length;
 
        if (datasz > host->dma_size) {
                dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
-                      datasz, host->dma_size);
+                       datasz, host->dma_size);
        }
 #endif
 
@@ -306,7 +307,7 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
 
        wmb();
 
-       if(host->actual_bus_width == MMC_BUS_WIDTH_4)
+       if (host->actual_bus_width == MMC_BUS_WIDTH_4)
                BLR(host->dma) = 0;     /* burst 64 byte read / 64 bytes write */
        else
                BLR(host->dma) = 16;    /* burst 16 byte read / 16 bytes write */
@@ -317,9 +318,8 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
        clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
 
        /* start DMA engine for read, write is delayed after initial response */
-       if (host->dma_dir == DMA_FROM_DEVICE) {
+       if (host->dma_dir == DMA_FROM_DEVICE)
                imx_dma_enable(host->dma);
-       }
 }
 
 static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
@@ -351,16 +351,16 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
                break;
        }
 
-       if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) )
+       if (test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events))
                cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
 
-       if ( host->actual_bus_width == MMC_BUS_WIDTH_4 )
+       if (host->actual_bus_width == MMC_BUS_WIDTH_4)
                cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
 
-       MMC_CMD = cmd->opcode;
-       MMC_ARGH = cmd->arg >> 16;
-       MMC_ARGL = cmd->arg & 0xffff;
-       MMC_CMD_DAT_CONT = cmdat;
+       writew(cmd->opcode, host->base + MMC_REG_CMD);
+       writew(cmd->arg >> 16, host->base + MMC_REG_ARGH);
+       writew(cmd->arg & 0xffff, host->base + MMC_REG_ARGL);
+       writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
 
        atomic_set(&host->stuck_timeout, 0);
        set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
@@ -368,18 +368,18 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd,
 
        imask = IMXMCI_INT_MASK_DEFAULT;
        imask &= ~INT_MASK_END_CMD_RES;
-       if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) {
-               /*imask &= ~INT_MASK_BUF_READY;*/
+       if (cmdat & CMD_DAT_CONT_DATA_ENABLE) {
+               /* imask &= ~INT_MASK_BUF_READY; */
                imask &= ~INT_MASK_DATA_TRAN;
-               if ( cmdat & CMD_DAT_CONT_WRITE )
+               if (cmdat & CMD_DAT_CONT_WRITE)
                        imask &= ~INT_MASK_WRITE_OP_DONE;
-               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+               if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
                        imask &= ~INT_MASK_BUF_READY;
        }
 
        spin_lock_irqsave(&host->lock, flags);
        host->imask = imask;
-       MMC_INT_MASK = host->imask;
+       writew(host->imask, host->base + MMC_REG_INT_MASK);
        spin_unlock_irqrestore(&host->lock, flags);
 
        dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
@@ -395,14 +395,14 @@ static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *
        spin_lock_irqsave(&host->lock, flags);
 
        host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
-                       IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
+                                 IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
 
        host->imask = IMXMCI_INT_MASK_DEFAULT;
-       MMC_INT_MASK = host->imask;
+       writew(host->imask, host->base + MMC_REG_INT_MASK);
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       if(req && req->cmd)
+       if (req && req->cmd)
                host->prev_cmd_code = req->cmd->opcode;
 
        host->req = NULL;
@@ -416,17 +416,17 @@ static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
        struct mmc_data *data = host->data;
        int data_error;
 
-       if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){
+       if (test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
                imx_dma_disable(host->dma);
                dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
                             host->dma_dir);
        }
 
-       if ( stat & STATUS_ERR_MASK ) {
-               dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
-               if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
+       if (stat & STATUS_ERR_MASK) {
+               dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", stat);
+               if (stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
                        data->error = -EILSEQ;
-               else if(stat & STATUS_TIME_OUT_READ)
+               else if (stat & STATUS_TIME_OUT_READ)
                        data->error = -ETIMEDOUT;
                else
                        data->error = -EIO;
@@ -445,7 +445,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
 {
        struct mmc_command *cmd = host->cmd;
        int i;
-       u32 a,b,c;
+       u32 a, b, c;
        struct mmc_data *data = host->data;
 
        if (!cmd)
@@ -461,18 +461,18 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
                cmd->error = -EILSEQ;
        }
 
-       if(cmd->flags & MMC_RSP_PRESENT) {
-               if(cmd->flags & MMC_RSP_136) {
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
                        for (i = 0; i < 4; i++) {
-                               u32 a = MMC_RES_FIFO & 0xffff;
-                               u32 b = MMC_RES_FIFO & 0xffff;
-                               cmd->resp[i] = a<<16 | b;
+                               a = readw(host->base + MMC_REG_RES_FIFO);
+                               b = readw(host->base + MMC_REG_RES_FIFO);
+                               cmd->resp[i] = a << 16 | b;
                        }
                } else {
-                       a = MMC_RES_FIFO & 0xffff;
-                       b = MMC_RES_FIFO & 0xffff;
-                       c = MMC_RES_FIFO & 0xffff;
-                       cmd->resp[0] = a<<24 | b<<8 | c>>8;
+                       a = readw(host->base + MMC_REG_RES_FIFO);
+                       b = readw(host->base + MMC_REG_RES_FIFO);
+                       c = readw(host->base + MMC_REG_RES_FIFO);
+                       cmd->resp[0] = a << 24 | b << 8 | c >> 8;
                }
        }
 
@@ -484,36 +484,34 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
 
                        /* Wait for FIFO to be empty before starting DMA write */
 
-                       stat = MMC_STATUS;
-                       if(imxmci_busy_wait_for_status(host, &stat,
-                               STATUS_APPL_BUFF_FE,
-                               40, "imxmci_cmd_done DMA WR") < 0) {
+                       stat = readw(host->base + MMC_REG_STATUS);
+                       if (imxmci_busy_wait_for_status(host, &stat,
+                                                       STATUS_APPL_BUFF_FE,
+                                                       40, "imxmci_cmd_done DMA WR") < 0) {
                                cmd->error = -EIO;
                                imxmci_finish_data(host, stat);
-                               if(host->req)
+                               if (host->req)
                                        imxmci_finish_request(host, host->req);
                                dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
-                                      stat);
+                                        stat);
                                return 0;
                        }
 
-                       if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+                       if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
                                imx_dma_enable(host->dma);
-                       }
                }
        } else {
                struct mmc_request *req;
                imxmci_stop_clock(host);
                req = host->req;
 
-               if(data)
+               if (data)
                        imxmci_finish_data(host, stat);
 
-               if( req ) {
+               if (req)
                        imxmci_finish_request(host, req);
-               } else {
+               else
                        dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
-               }
        }
 
        return 1;
@@ -535,11 +533,10 @@ static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
        } else {
                struct mmc_request *req;
                req = host->req;
-               if( req ) {
+               if (req)
                        imxmci_finish_request(host, req);
-               } else {
+               else
                        dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
-               }
        }
 
        return 1;
@@ -552,7 +549,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
        int trans_done = 0;
        unsigned int stat = *pstat;
 
-       if(host->actual_bus_width != MMC_BUS_WIDTH_4)
+       if (host->actual_bus_width != MMC_BUS_WIDTH_4)
                burst_len = 16;
        else
                burst_len = 64;
@@ -563,44 +560,44 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
 
        udelay(20);     /* required for clocks < 8MHz*/
 
-       if(host->dma_dir == DMA_FROM_DEVICE) {
+       if (host->dma_dir == DMA_FROM_DEVICE) {
                imxmci_busy_wait_for_status(host, &stat,
-                               STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
-                               STATUS_TIME_OUT_READ,
-                               50, "imxmci_cpu_driven_data read");
+                                           STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
+                                           STATUS_TIME_OUT_READ,
+                                           50, "imxmci_cpu_driven_data read");
 
-               while((stat & (STATUS_APPL_BUFF_FF |  STATUS_DATA_TRANS_DONE)) &&
-                     !(stat & STATUS_TIME_OUT_READ) &&
-                     (host->data_cnt < 512)) {
+               while ((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) &&
+                      !(stat & STATUS_TIME_OUT_READ) &&
+                      (host->data_cnt < 512)) {
 
                        udelay(20);     /* required for clocks < 8MHz*/
 
-                       for(i = burst_len; i>=2 ; i-=2) {
+                       for (i = burst_len; i >= 2 ; i -= 2) {
                                u16 data;
-                               data = MMC_BUFFER_ACCESS;
+                               data = readw(host->base + MMC_REG_BUFFER_ACCESS);
                                udelay(10);     /* required for clocks < 8MHz*/
-                               if(host->data_cnt+2 <= host->dma_size) {
+                               if (host->data_cnt+2 <= host->dma_size) {
                                        *(host->data_ptr++) = data;
                                } else {
-                                       if(host->data_cnt < host->dma_size)
-                                               *(u8*)(host->data_ptr) = data;
+                                       if (host->data_cnt < host->dma_size)
+                                               *(u8 *)(host->data_ptr) = data;
                                }
                                host->data_cnt += 2;
                        }
 
-                       stat = MMC_STATUS;
+                       stat = readw(host->base + MMC_REG_STATUS);
 
                        dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
                                host->data_cnt, burst_len, stat);
                }
 
-               if((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
+               if ((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
                        trans_done = 1;
 
-               if(host->dma_size & 0x1ff)
+               if (host->dma_size & 0x1ff)
                        stat &= ~STATUS_CRC_READ_ERR;
 
-               if(stat & STATUS_TIME_OUT_READ) {
+               if (stat & STATUS_TIME_OUT_READ) {
                        dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n",
                                stat);
                        trans_done = -1;
@@ -608,12 +605,12 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
 
        } else {
                imxmci_busy_wait_for_status(host, &stat,
-                               STATUS_APPL_BUFF_FE,
-                               20, "imxmci_cpu_driven_data write");
+                                           STATUS_APPL_BUFF_FE,
+                                           20, "imxmci_cpu_driven_data write");
 
-               while((stat & STATUS_APPL_BUFF_FE) &&
-                     (host->data_cnt < host->dma_size)) {
-                       if(burst_len >= host->dma_size - host->data_cnt) {
+               while ((stat & STATUS_APPL_BUFF_FE) &&
+                      (host->data_cnt < host->dma_size)) {
+                       if (burst_len >= host->dma_size - host->data_cnt) {
                                burst_len = host->dma_size - host->data_cnt;
                                host->data_cnt = host->dma_size;
                                trans_done = 1;
@@ -621,10 +618,10 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
                                host->data_cnt += burst_len;
                        }
 
-                       for(i = burst_len; i>0 ; i-=2)
-                               MMC_BUFFER_ACCESS = *(host->data_ptr++);
+                       for (i = burst_len; i > 0 ; i -= 2)
+                               writew(*(host->data_ptr++), host->base + MMC_REG_BUFFER_ACCESS);
 
-                       stat = MMC_STATUS;
+                       stat = readw(host->base + MMC_REG_STATUS);
 
                        dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
                                burst_len, stat);
@@ -639,7 +636,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
 static void imxmci_dma_irq(int dma, void *devid)
 {
        struct imxmci_host *host = devid;
-       uint32_t stat = MMC_STATUS;
+       u32 stat = readw(host->base + MMC_REG_STATUS);
 
        atomic_set(&host->stuck_timeout, 0);
        host->status_reg = stat;
@@ -650,10 +647,11 @@ static void imxmci_dma_irq(int dma, void *devid)
 static irqreturn_t imxmci_irq(int irq, void *devid)
 {
        struct imxmci_host *host = devid;
-       uint32_t stat = MMC_STATUS;
+       u32 stat = readw(host->base + MMC_REG_STATUS);
        int handled = 1;
 
-       MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT;
+       writew(host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT,
+                       host->base + MMC_REG_INT_MASK);
 
        atomic_set(&host->stuck_timeout, 0);
        host->status_reg = stat;
@@ -671,10 +669,10 @@ static void imxmci_tasklet_fnc(unsigned long data)
        unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */
        int timeout = 0;
 
-       if(atomic_read(&host->stuck_timeout) > 4) {
+       if (atomic_read(&host->stuck_timeout) > 4) {
                char *what;
                timeout = 1;
-               stat = MMC_STATUS;
+               stat = readw(host->base + MMC_REG_STATUS);
                host->status_reg = stat;
                if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
                        if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
@@ -683,29 +681,37 @@ static void imxmci_tasklet_fnc(unsigned long data)
                                what = "RESP";
                else
                        if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
-                               if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
+                               if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
                                        what = "DATA";
                                else
                                        what = "DMA";
                        else
                                what = "???";
 
-               dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
-                      what, stat, MMC_INT_MASK);
-               dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
-                      MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
+               dev_err(mmc_dev(host->mmc),
+                       "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
+                       what, stat,
+                       readw(host->base + MMC_REG_INT_MASK));
+               dev_err(mmc_dev(host->mmc),
+                       "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
+                       readw(host->base + MMC_REG_CMD_DAT_CONT),
+                       readw(host->base + MMC_REG_BLK_LEN),
+                       readw(host->base + MMC_REG_NOB),
+                       CCR(host->dma));
                dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
-                      host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1<<host->actual_bus_width, host->dma_size);
+                       host->cmd ? host->cmd->opcode : 0,
+                       host->prev_cmd_code,
+                       1 << host->actual_bus_width, host->dma_size);
        }
 
-       if(!host->present || timeout)
+       if (!host->present || timeout)
                host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
-                                   STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
+                       STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
 
-       if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
+       if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
                clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
 
-               stat = MMC_STATUS;
+               stat = readw(host->base + MMC_REG_STATUS);
                /*
                 * This is not required in theory, but there is chance to miss some flag
                 * which clears automatically by mask write, FreeScale original code keeps
@@ -713,63 +719,62 @@ static void imxmci_tasklet_fnc(unsigned long data)
                 */
                stat |= host->status_reg;
 
-               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
+               if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
                        stat &= ~STATUS_CRC_READ_ERR;
 
-               if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+               if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
                        imxmci_busy_wait_for_status(host, &stat,
-                                       STATUS_END_CMD_RESP | STATUS_ERR_MASK,
-                                       20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
+                                                   STATUS_END_CMD_RESP | STATUS_ERR_MASK,
+                                                   20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
                }
 
-               if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
-                       if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+               if (stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
+                       if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
                                imxmci_cmd_done(host, stat);
-                       if(host->data && (stat & STATUS_ERR_MASK))
+                       if (host->data && (stat & STATUS_ERR_MASK))
                                imxmci_data_done(host, stat);
                }
 
-               if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
-                       stat |= MMC_STATUS;
-                       if(imxmci_cpu_driven_data(host, &stat)){
-                               if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
+               if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
+                       stat |= readw(host->base + MMC_REG_STATUS);
+                       if (imxmci_cpu_driven_data(host, &stat)) {
+                               if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
                                        imxmci_cmd_done(host, stat);
                                atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
-                                                       &host->pending_events);
+                                                 &host->pending_events);
                                imxmci_data_done(host, stat);
                        }
                }
        }
 
-       if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
-          !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
+       if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
+           !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
 
-               stat = MMC_STATUS;
+               stat = readw(host->base + MMC_REG_STATUS);
                /* Same as above */
                stat |= host->status_reg;
 
-               if(host->dma_dir == DMA_TO_DEVICE) {
+               if (host->dma_dir == DMA_TO_DEVICE)
                        data_dir_mask = STATUS_WRITE_OP_DONE;
-               } else {
+               else
                        data_dir_mask = STATUS_DATA_TRANS_DONE;
-               }
 
-               if(stat & data_dir_mask) {
+               if (stat & data_dir_mask) {
                        clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
                        imxmci_data_done(host, stat);
                }
        }
 
-       if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
+       if (test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
 
-               if(host->cmd)
+               if (host->cmd)
                        imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
 
-               if(host->data)
+               if (host->data)
                        imxmci_data_done(host, STATUS_TIME_OUT_READ |
                                         STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
 
-               if(host->req)
+               if (host->req)
                        imxmci_finish_request(host, host->req);
 
                mmc_detect_change(host->mmc, msecs_to_jiffies(100));
@@ -796,9 +801,8 @@ static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
                if (req->data->flags & MMC_DATA_WRITE)
                        cmdat |= CMD_DAT_CONT_WRITE;
 
-               if (req->data->flags & MMC_DATA_STREAM) {
+               if (req->data->flags & MMC_DATA_STREAM)
                        cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
-               }
        }
 
        imxmci_start_cmd(host, req->cmd, cmdat);
@@ -811,36 +815,37 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct imxmci_host *host = mmc_priv(mmc);
        int prescaler;
 
-       if( ios->bus_width==MMC_BUS_WIDTH_4 ) {
+       if (ios->bus_width == MMC_BUS_WIDTH_4) {
                host->actual_bus_width = MMC_BUS_WIDTH_4;
                imx_gpio_mode(PB11_PF_SD_DAT3);
-       }else{
+       } else {
                host->actual_bus_width = MMC_BUS_WIDTH_1;
                imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
        }
 
-       if ( host->power_mode != ios->power_mode ) {
+       if (host->power_mode != ios->power_mode) {
                switch (ios->power_mode) {
                case MMC_POWER_OFF:
-                       break;
+                       break;
                case MMC_POWER_UP:
                        set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
-                       break;
+                       break;
                case MMC_POWER_ON:
-                       break;
+                       break;
                }
                host->power_mode = ios->power_mode;
        }
 
-       if ( ios->clock ) {
+       if (ios->clock) {
                unsigned int clk;
+               u16 reg;
 
                /* The prescaler is 5 for PERCLK2 equal to 96MHz
                 * then 96MHz / 5 = 19.2 MHz
                 */
                clk = clk_get_rate(host->clk);
-               prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE;
-               switch(prescaler) {
+               prescaler = (clk + (CLK_RATE * 7) / 8) / CLK_RATE;
+               switch (prescaler) {
                case 0:
                case 1: prescaler = 0;
                        break;
@@ -858,24 +863,29 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
                        clk, prescaler);
 
-               for(clk=0; clk<8; clk++) {
+               for (clk = 0; clk < 8; clk++) {
                        int x;
-                       x = CLK_RATE / (1<<clk);
-                       ifx <= ios->clock)
+                       x = CLK_RATE / (1 << clk);
+                       if (x <= ios->clock)
                                break;
                }
 
-               MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */
+               /* enable controller */
+               reg = readw(host->base + MMC_REG_STR_STP_CLK);
+               writew(reg | STR_STP_CLK_ENABLE,
+                               host->base + MMC_REG_STR_STP_CLK);
 
                imxmci_stop_clock(host);
-               MMC_CLK_RATE = (prescaler<<3) | clk;
+               writew((prescaler << 3) | clk, host->base + MMC_REG_CLK_RATE);
                /*
                 * Under my understanding, clock should not be started there, because it would
                 * initiate SDHC sequencer and send last or random command into card
                 */
-               /*imxmci_start_clock(host);*/
+               /* imxmci_start_clock(host); */
 
-               dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE);
+               dev_dbg(mmc_dev(host->mmc),
+                       "MMC_CLK_RATE: 0x%08x\n",
+                       readw(host->base + MMC_REG_CLK_RATE));
        } else {
                imxmci_stop_clock(host);
        }
@@ -915,10 +925,10 @@ static void imxmci_check_status(unsigned long data)
                tasklet_schedule(&host->tasklet);
        }
 
-       if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
-          test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
+       if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
+           test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
                atomic_inc(&host->stuck_timeout);
-               if(atomic_read(&host->stuck_timeout) > 4)
+               if (atomic_read(&host->stuck_timeout) > 4)
                        tasklet_schedule(&host->tasklet);
        } else {
                atomic_set(&host->stuck_timeout, 0);
@@ -934,6 +944,7 @@ static int imxmci_probe(struct platform_device *pdev)
        struct imxmci_host *host = NULL;
        struct resource *r;
        int ret = 0, irq;
+       u16 rev_no;
 
        printk(KERN_INFO "i.MX mmc driver\n");
 
@@ -942,7 +953,8 @@ static int imxmci_probe(struct platform_device *pdev)
        if (!r || irq < 0)
                return -ENXIO;
 
-       if (!request_mem_region(r->start, 0x100, pdev->name))
+       r = request_mem_region(r->start, resource_size(r), pdev->name);
+       if (!r)
                return -EBUSY;
 
        mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
@@ -966,6 +978,12 @@ static int imxmci_probe(struct platform_device *pdev)
        mmc->max_blk_count = 65535;
 
        host = mmc_priv(mmc);
+       host->base = ioremap(r->start, resource_size(r));
+       if (!host->base) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
        host->mmc = mmc;
        host->dma_allocated = 0;
        host->pdata = pdev->dev.platform_data;
@@ -993,18 +1011,20 @@ static int imxmci_probe(struct platform_device *pdev)
        imx_gpio_mode(PB12_PF_SD_CLK);
        imx_gpio_mode(PB13_PF_SD_CMD);
 
-       imxmci_softreset();
+       imxmci_softreset(host);
 
-       if ( MMC_REV_NO != 0x390 ) {
+       rev_no = readw(host->base + MMC_REG_REV_NO);
+       if (rev_no != 0x390) {
                dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
-                       MMC_REV_NO);
+                       readw(host->base + MMC_REG_REV_NO));
                goto out;
        }
 
-       MMC_READ_TO = 0x2db4; /* recommended in data sheet */
+       /* recommended in data sheet */
+       writew(0x2db4, host->base + MMC_REG_READ_TO);
 
        host->imask = IMXMCI_INT_MASK_DEFAULT;
-       MMC_INT_MASK = host->imask;
+       writew(host->imask, host->base + MMC_REG_INT_MASK);
 
        host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
        if(host->dma < 0) {
@@ -1012,7 +1032,7 @@ static int imxmci_probe(struct platform_device *pdev)
                ret = -EBUSY;
                goto out;
        }
-       host->dma_allocated=1;
+       host->dma_allocated = 1;
        imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
 
        tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
@@ -1032,7 +1052,7 @@ static int imxmci_probe(struct platform_device *pdev)
        host->timer.data = (unsigned long)host;
        host->timer.function = imxmci_check_status;
        add_timer(&host->timer);
-       mod_timer(&host->timer, jiffies + (HZ>>1));
+       mod_timer(&host->timer, jiffies + (HZ >> 1));
 
        platform_set_drvdata(pdev, mmc);
 
@@ -1042,18 +1062,20 @@ static int imxmci_probe(struct platform_device *pdev)
 
 out:
        if (host) {
-               if(host->dma_allocated){
+               if (host->dma_allocated) {
                        imx_dma_free(host->dma);
-                       host->dma_allocated=0;
+                       host->dma_allocated = 0;
                }
                if (host->clk) {
                        clk_disable(host->clk);
                        clk_put(host->clk);
                }
+               if (host->base)
+                       iounmap(host->base);
        }
        if (mmc)
                mmc_free_host(mmc);
-       release_mem_region(r->start, 0x100);
+       release_mem_region(r->start, resource_size(r));
        return ret;
 }
 
@@ -1072,9 +1094,10 @@ static int imxmci_remove(struct platform_device *pdev)
                mmc_remove_host(mmc);
 
                free_irq(host->irq, host);
-               if(host->dma_allocated){
+               iounmap(host->base);
+               if (host->dma_allocated) {
                        imx_dma_free(host->dma);
-                       host->dma_allocated=0;
+                       host->dma_allocated = 0;
                }
 
                tasklet_kill(&host->tasklet);
@@ -1082,7 +1105,7 @@ static int imxmci_remove(struct platform_device *pdev)
                clk_disable(host->clk);
                clk_put(host->clk);
 
-               release_mem_region(host->res->start, 0x100);
+               release_mem_region(host->res->start, resource_size(host->res));
 
                mmc_free_host(mmc);
        }
@@ -1109,7 +1132,7 @@ static int imxmci_resume(struct platform_device *dev)
 
        if (mmc) {
                host = mmc_priv(mmc);
-               if(host)
+               if (host)
                        set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
                ret = mmc_resume_host(mmc);
        }
index e5339e334dbb3525a1e5175989153441024af729..09d5d4ee3a7709a1ebc4a5328a105f27649ee119 100644 (file)
@@ -1,24 +1,21 @@
+#define MMC_REG_STR_STP_CLK            0x00
+#define MMC_REG_STATUS                 0x04
+#define MMC_REG_CLK_RATE               0x08
+#define MMC_REG_CMD_DAT_CONT           0x0C
+#define MMC_REG_RES_TO                 0x10
+#define MMC_REG_READ_TO                        0x14
+#define MMC_REG_BLK_LEN                        0x18
+#define MMC_REG_NOB                    0x1C
+#define MMC_REG_REV_NO                 0x20
+#define MMC_REG_INT_MASK               0x24
+#define MMC_REG_CMD                    0x28
+#define MMC_REG_ARGH                   0x2C
+#define MMC_REG_ARGL                   0x30
+#define MMC_REG_RES_FIFO               0x34
+#define MMC_REG_BUFFER_ACCESS          0x38
 
-# define __REG16(x)    (*((volatile u16 *)IO_ADDRESS(x)))
-
-#define MMC_STR_STP_CLK  __REG16(IMX_MMC_BASE + 0x00)
-#define MMC_STATUS       __REG16(IMX_MMC_BASE + 0x04)
-#define MMC_CLK_RATE     __REG16(IMX_MMC_BASE + 0x08)
-#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C)
-#define MMC_RES_TO       __REG16(IMX_MMC_BASE + 0x10)
-#define MMC_READ_TO      __REG16(IMX_MMC_BASE + 0x14)
-#define MMC_BLK_LEN      __REG16(IMX_MMC_BASE + 0x18)
-#define MMC_NOB          __REG16(IMX_MMC_BASE + 0x1C)
-#define MMC_REV_NO       __REG16(IMX_MMC_BASE + 0x20)
-#define MMC_INT_MASK     __REG16(IMX_MMC_BASE + 0x24)
-#define MMC_CMD          __REG16(IMX_MMC_BASE + 0x28)
-#define MMC_ARGH         __REG16(IMX_MMC_BASE + 0x2C)
-#define MMC_ARGL         __REG16(IMX_MMC_BASE + 0x30)
-#define MMC_RES_FIFO     __REG16(IMX_MMC_BASE + 0x34)
-#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38)
-#define MMC_BUFFER_ACCESS_OFS 0x38
-
-
+#define STR_STP_CLK_IPG_CLK_GATE_DIS    (1<<15)
+#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14)
 #define STR_STP_CLK_ENDIAN              (1<<5)
 #define STR_STP_CLK_RESET               (1<<3)
 #define STR_STP_CLK_ENABLE              (1<<2)
index 2fadf323c696d381f1fe23fb062e108c1e97a59f..1bcbdd6763ace8d1dc3a91db7a5b1d0c76a67b63 100644 (file)
@@ -500,7 +500,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
        }
 
        host = mmc_priv(mmc);
-       host->clk = clk_get(&dev->dev, "MCLK");
+       host->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                host->clk = NULL;
index 1b9fc3c6b8752240c591aa23ed6a7d0f13bbea44..67d7b7fef084f1a064d4f7834a37af0059c96f99 100644 (file)
@@ -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].wires >= 4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
        mmc->ops = &mmc_omap_ops;
@@ -1451,6 +1451,7 @@ 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;
index ebfaa99609394b14d47d3028cb5b6bc393608409..f88cc74063541a151107527772378fbb35535010 100644 (file)
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/mmc/host.h>
+#include <linux/io.h>
 
-#include <asm/dma.h>
-#include <asm/io.h>
 #include <asm/sizes.h>
 
+#include <mach/dma.h>
+#include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 #include <mach/mmc.h>
 
@@ -533,7 +534,7 @@ static int pxamci_probe(struct platform_device *pdev)
        host->pdata = pdev->dev.platform_data;
        host->clkrt = CLKRT_OFF;
 
-       host->clk = clk_get(&pdev->dev, "MMCCLK");
+       host->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                host->clk = NULL;
index 3b2085b57769b5f72836aefb2a06de89df7d56fd..fcc98a4cce3cc887a597d87d1bd88cb3d3bd5e8a 100644 (file)
@@ -25,7 +25,7 @@
 #include <mach/regs-sdi.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/mci.h>
+#include <plat/mci.h>
 
 #include "s3cmci.h"
 
index 3aa018c092f893369ac7d4ff9b4073efa7af861f..42969fe051b219b5ec0788f60f51c1141d1e4770 100644 (file)
@@ -32,16 +32,15 @@ static struct mtd_info *dc21285_mtd;
  */
 static void nw_en_write(void)
 {
-       extern spinlock_t gpio_lock;
        unsigned long flags;
 
        /*
         * we want to write a bit pattern XXX1 to Xilinx to enable
         * the write gate, which will be open for about the next 2ms.
         */
-       spin_lock_irqsave(&gpio_lock, flags);
-       cpld_modify(1, 1);
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       nw_cpld_modify(CPLD_FLASH_WR_ENABLE, CPLD_FLASH_WR_ENABLE);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
 
        /*
         * let the ISA bus to catch on...
index dcdb1f17577db3ba909219ef7160744abb8040b8..3ea1de9be7203aedb92ae1014db058eba4d3620e 100644 (file)
@@ -170,7 +170,7 @@ static int ixp2000_flash_probe(struct platform_device *dev)
                err = -ENOMEM;
                goto Error;
        }
-       memzero(info, sizeof(struct ixp2000_flash_info));
+       memset(info, 0, sizeof(struct ixp2000_flash_info));
 
        platform_set_drvdata(dev, info);
 
index 9c7a5fbd4e512e93c58de1f08ee2d2b388ca8af7..16555cbeaea4572e383189ea88f3f153338431b8 100644 (file)
@@ -201,7 +201,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
                err = -ENOMEM;
                goto Error;
        }
-       memzero(info, sizeof(struct ixp4xx_flash_info));
+       memset(info, 0, sizeof(struct ixp4xx_flash_info));
 
        platform_set_drvdata(dev, info);
 
index 1c2e9450d663ca9e7c2c3fd8a8a5a8b98b26755c..f8ae0400c49c0bf16d312ded2d0958e5d1b26501 100644 (file)
@@ -408,7 +408,7 @@ config MTD_NAND_FSL_UPM
 
 config MTD_NAND_MXC
        tristate "MXC NAND support"
-       depends on ARCH_MX2
+       depends on ARCH_MX2 || ARCH_MX3
        help
          This enables the driver for the NAND flash controller on the
          MXC processors.
index 15f0a26730aea38e4c65708aac43473a8da02122..fc41444956108fd007fa818b3f80e658a718d3a6 100644 (file)
@@ -20,8 +20,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/irq.h>
-#include <asm/dma.h>
 
+#include <mach/dma.h>
 #include <mach/pxa-regs.h>
 #include <mach/pxa3xx_nand.h>
 
@@ -1080,7 +1080,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        this = &info->nand_chip;
        mtd->priv = info;
 
-       info->clk = clk_get(&pdev->dev, "NANDCLK");
+       info->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk)) {
                dev_err(&pdev->dev, "failed to get nand clock\n");
                ret = PTR_ERR(info->clk);
index 556139ed1fdf8b50919dfa078fe74a98626008d6..8e375d5fe231622953a29bc9ac6431bffcd06121 100644 (file)
@@ -45,8 +45,8 @@
 
 #include <asm/io.h>
 
-#include <asm/plat-s3c/regs-nand.h>
-#include <asm/plat-s3c/nand.h>
+#include <plat/regs-nand.h>
+#include <plat/nand.h>
 
 #ifdef CONFIG_MTD_NAND_S3C2410_HWECC
 static int hardware_ecc = 1;
@@ -818,7 +818,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
                goto exit_error;
        }
 
-       memzero(info, sizeof(*info));
+       memset(info, 0, sizeof(*info));
        platform_set_drvdata(pdev, info);
 
        spin_lock_init(&info->controller.lock);
@@ -883,7 +883,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
                goto exit_error;
        }
 
-       memzero(info->mtds, size);
+       memset(info->mtds, 0, size);
 
        /* initialise all possible chips */
 
index a7e4d985f5ef553892a4fba5890647324f1c156c..d1e0b8e7224bfa32a87aa8d5dabb37c657b8ae34 100644 (file)
@@ -149,7 +149,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state)
 
                INIT_COMPLETION(c->irq_done);
                if (c->gpio_irq) {
-                       result = omap_get_gpio_datain(c->gpio_irq);
+                       result = gpio_get_value(c->gpio_irq);
                        if (result == -1) {
                                ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
                                intr = read_reg(c, ONENAND_REG_INTERRUPT);
@@ -634,9 +634,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
                                "OneNAND\n", c->gpio_irq);
                        goto err_iounmap;
        }
-       omap_set_gpio_direction(c->gpio_irq, 1);
+       gpio_direction_input(c->gpio_irq);
 
-       if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq),
+       if ((r = request_irq(gpio_to_irq(c->gpio_irq),
                             omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
                             pdev->dev.driver->name, c)) < 0)
                goto err_release_gpio;
@@ -723,7 +723,7 @@ 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);
+               free_irq(gpio_to_irq(c->gpio_irq), c);
 err_release_gpio:
        if (c->gpio_irq)
                omap_free_gpio(c->gpio_irq);
@@ -760,7 +760,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
        omap2_onenand_shutdown(pdev);
        platform_set_drvdata(pdev, NULL);
        if (c->gpio_irq) {
-               free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+               free_irq(gpio_to_irq(c->gpio_irq), c);
                omap_free_gpio(c->gpio_irq);
        }
        iounmap(c->onenand.base);
index 6ecc600c1bccd05c5e22e17af5248fe998e9ecb0..3ec20cc18b0cb397524f5108cd257086b48f871e 100644 (file)
@@ -307,7 +307,7 @@ poll_some_more:
                }
                spin_unlock_irq(&ep->rx_lock);
 
-               if (more && netif_rx_reschedule(dev, napi))
+               if (more && netif_rx_reschedule(napi))
                        goto poll_some_more;
        }
 
index 26af411fc42819f8b7190fc4b4ba263965f003d8..5fce1d5c1a1a6cf273bc25b9983a10f620201df3 100644 (file)
@@ -504,7 +504,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
                        netif_rx_complete(napi);
                        qmgr_enable_irq(rxq);
                        if (!qmgr_stat_empty(rxq) &&
-                           netif_rx_reschedule(dev, napi)) {
+                           netif_rx_reschedule(napi)) {
 #if DEBUG_RX
                                printk(KERN_DEBUG "%s: eth_poll"
                                       " netif_rx_reschedule successed\n",
index 592daee9dc2815cb7e6f6977dfcdad8485204224..9ad22d1b00fd681d3ee7d1ade6fc2a81d196b669 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-#include <linux/delay.h>
 #include <linux/io.h>
 
 #include <asm/irq.h>
index d548a45d59d563f837b1634335547950210aa043..ff6497658a4538c94ceff39898c5b74f7f75da86 100644 (file)
@@ -170,11 +170,7 @@ static char version[] __initdata =
 /* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
    them to system IRQ numbers. This mapping is card specific and is set to
    the configuration of the Cirrus Eval board for this chip. */
-#ifdef CONFIG_ARCH_CLPS7500
-static unsigned int netcard_portlist[] __used __initdata =
-   { 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
-static unsigned int cs8900_irq_map[] = {12,0,0,0};
-#elif defined(CONFIG_SH_HICOSH4)
+#if defined(CONFIG_SH_HICOSH4)
 static unsigned int netcard_portlist[] __used __initdata =
    { 0x0300, 0};
 static unsigned int cs8900_irq_map[] = {1,0,0,0};
index 707df3fcfe40d9084e427854f41640ad9e989300..dc9c6ea289e95b7e54c8e32dd047d3d00705d8e0 100644 (file)
  */
 
 /* these functions take the SCB status word and test the relevant status bit */
-#define SCB_complete(s) ((s&0x8000)!=0)
-#define SCB_rxdframe(s) ((s&0x4000)!=0)
-#define SCB_CUdead(s)   ((s&0x2000)!=0)
-#define SCB_RUdead(s)   ((s&0x1000)!=0)
-#define SCB_ack(s)      (s & 0xf000)
+#define SCB_complete(s) (((s) & 0x8000) != 0)
+#define SCB_rxdframe(s) (((s) & 0x4000) != 0)
+#define SCB_CUdead(s)   (((s) & 0x2000) != 0)
+#define SCB_RUdead(s)   (((s) & 0x1000) != 0)
+#define SCB_ack(s)      ((s) & 0xf000)
 
 /* Command unit status: 0=idle, 1=suspended, 2=active */
-#define SCB_CUstat(s)   ((s&0x0300)>>8)
+#define SCB_CUstat(s)   (((s)&0x0300)>>8)
 
 /* Receive unit status: 0=idle, 1=suspended, 2=out of resources, 4=ready */
-#define SCB_RUstat(s)   ((s&0x0070)>>4)
+#define SCB_RUstat(s)   (((s)&0x0070)>>4)
 
 /* SCB commands */
 #define SCB_CUnop       0x0000
  * Command block defines
  */
 
-#define Stat_Done(s)    ((s&0x8000)!=0)
-#define Stat_Busy(s)    ((s&0x4000)!=0)
-#define Stat_OK(s)      ((s&0x2000)!=0)
-#define Stat_Abort(s)   ((s&0x1000)!=0)
-#define Stat_STFail     ((s&0x0800)!=0)
-#define Stat_TNoCar(s)  ((s&0x0400)!=0)
-#define Stat_TNoCTS(s)  ((s&0x0200)!=0)
-#define Stat_TNoDMA(s)  ((s&0x0100)!=0)
-#define Stat_TDefer(s)  ((s&0x0080)!=0)
-#define Stat_TColl(s)   ((s&0x0040)!=0)
-#define Stat_TXColl(s)  ((s&0x0020)!=0)
-#define Stat_NoColl(s)  (s&0x000f)
+#define Stat_Done(s)    (((s) & 0x8000) != 0)
+#define Stat_Busy(s)    (((s) & 0x4000) != 0)
+#define Stat_OK(s)      (((s) & 0x2000) != 0)
+#define Stat_Abort(s)   (((s) & 0x1000) != 0)
+#define Stat_STFail     (((s) & 0x0800) != 0)
+#define Stat_TNoCar(s)  (((s) & 0x0400) != 0)
+#define Stat_TNoCTS(s)  (((s) & 0x0200) != 0)
+#define Stat_TNoDMA(s)  (((s) & 0x0100) != 0)
+#define Stat_TDefer(s)  (((s) & 0x0080) != 0)
+#define Stat_TColl(s)   (((s) & 0x0040) != 0)
+#define Stat_TXColl(s)  (((s) & 0x0020) != 0)
+#define Stat_NoColl(s)  ((s) & 0x000f)
 
 /* Cmd_END will end AFTER the command if this is the first
  * command block after an SCB_CUstart, but BEFORE the command
  * Frame Descriptor (Receive block) defines
  */
 
-#define FD_Done(s)  ((s&0x8000)!=0)
-#define FD_Busy(s)  ((s&0x4000)!=0)
-#define FD_OK(s)    ((s&0x2000)!=0)
+#define FD_Done(s)  (((s) & 0x8000) != 0)
+#define FD_Busy(s)  (((s) & 0x4000) != 0)
+#define FD_OK(s)    (((s) & 0x2000) != 0)
 
-#define FD_CRC(s)   ((s&0x0800)!=0)
-#define FD_Align(s) ((s&0x0400)!=0)
-#define FD_Resrc(s) ((s&0x0200)!=0)
-#define FD_DMA(s)   ((s&0x0100)!=0)
-#define FD_Short(s) ((s&0x0080)!=0)
-#define FD_NoEOF(s) ((s&0x0040)!=0)
+#define FD_CRC(s)   (((s) & 0x0800) != 0)
+#define FD_Align(s) (((s) & 0x0400) != 0)
+#define FD_Resrc(s) (((s) & 0x0200) != 0)
+#define FD_DMA(s)   (((s) & 0x0100) != 0)
+#define FD_Short(s) (((s) & 0x0080) != 0)
+#define FD_NoEOF(s) (((s) & 0x0040) != 0)
 
 struct rfd_header {
        volatile unsigned long flags;
index a0ee053181556bd4b600f5f001ae2eba236f901e..004a9aab3a5079b28d2bfe0881f5f003b6d62327 100644 (file)
 #include <net/irda/wrapper.h>
 #include <net/irda/irda_device.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/irda.h>
+#include <mach/hardware.h>
 #include <mach/pxa-regs.h>
+#include <mach/regs-uart.h>
+
+#define FICP           __REG(0x40800000)  /* Start of FICP area */
+#define ICCR0          __REG(0x40800000)  /* ICP Control Register 0 */
+#define ICCR1          __REG(0x40800004)  /* ICP Control Register 1 */
+#define ICCR2          __REG(0x40800008)  /* ICP Control Register 2 */
+#define ICDR           __REG(0x4080000c)  /* ICP Data Register */
+#define ICSR0          __REG(0x40800014)  /* ICP Status Register 0 */
+#define ICSR1          __REG(0x40800018)  /* ICP Status Register 1 */
+
+#define ICCR0_AME      (1 << 7)        /* Address match enable */
+#define ICCR0_TIE      (1 << 6)        /* Transmit FIFO interrupt enable */
+#define ICCR0_RIE      (1 << 5)        /* Recieve FIFO interrupt enable */
+#define ICCR0_RXE      (1 << 4)        /* Receive enable */
+#define ICCR0_TXE      (1 << 3)        /* Transmit enable */
+#define ICCR0_TUS      (1 << 2)        /* Transmit FIFO underrun select */
+#define ICCR0_LBM      (1 << 1)        /* Loopback mode */
+#define ICCR0_ITR      (1 << 0)        /* IrDA transmission */
+
+#define ICCR2_RXP       (1 << 3)       /* Receive Pin Polarity select */
+#define ICCR2_TXP       (1 << 2)       /* Transmit Pin Polarity select */
+#define ICCR2_TRIG     (3 << 0)        /* Receive FIFO Trigger threshold */
+#define ICCR2_TRIG_8    (0 << 0)       /*      >= 8 bytes */
+#define ICCR2_TRIG_16   (1 << 0)       /*      >= 16 bytes */
+#define ICCR2_TRIG_32   (2 << 0)       /*      >= 32 bytes */
+
+#ifdef CONFIG_PXA27x
+#define ICSR0_EOC      (1 << 6)        /* DMA End of Descriptor Chain */
+#endif
+#define ICSR0_FRE      (1 << 5)        /* Framing error */
+#define ICSR0_RFS      (1 << 4)        /* Receive FIFO service request */
+#define ICSR0_TFS      (1 << 3)        /* Transnit FIFO service request */
+#define ICSR0_RAB      (1 << 2)        /* Receiver abort */
+#define ICSR0_TUR      (1 << 1)        /* Trunsmit FIFO underun */
+#define ICSR0_EIF      (1 << 0)        /* End/Error in FIFO */
+
+#define ICSR1_ROR      (1 << 6)        /* Receiver FIFO underrun  */
+#define ICSR1_CRE      (1 << 5)        /* CRC error */
+#define ICSR1_EOF      (1 << 4)        /* End of frame */
+#define ICSR1_TNF      (1 << 3)        /* Transmit FIFO not full */
+#define ICSR1_RNE      (1 << 2)        /* Receive FIFO not empty */
+#define ICSR1_TBY      (1 << 1)        /* Tramsmiter busy flag */
+#define ICSR1_RSY      (1 << 0)        /* Recevier synchronized flag */
 
 #define IrSR_RXPL_NEG_IS_ZERO (1<<4)
 #define IrSR_RXPL_POS_IS_ZERO 0x0
index ccde5829ba21139b6947e4218c9c00492487e0a1..d302bcf4c1485364d8925d76b65e47776a85b616 100644 (file)
@@ -36,7 +36,7 @@
 #include <net/irda/irda_device.h>
 
 #include <asm/irq.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <asm/mach/irda.h>
 
index c1c05852a95ebf34e357f86a6b0465758e5458f9..eda72dd2120f5a3af3291fabc3923ea5c5b94210 100644 (file)
@@ -169,13 +169,10 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
        mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
                mlx4_info(mdev, "Using %d tx rings for port:%d\n",
                          mdev->profile.prof[i].tx_ring_num, i);
-               if (!mdev->profile.prof[i].rx_ring_num) {
-                       mdev->profile.prof[i].rx_ring_num = dev->caps.num_comp_vectors;
-                       mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n",
-                                 mdev->profile.prof[i].rx_ring_num, i);
-               } else
-                       mlx4_info(mdev, "Using %d rx rings for port:%d\n",
-                                 mdev->profile.prof[i].rx_ring_num, i);
+               mdev->profile.prof[i].rx_ring_num =
+                       min_t(int, dev->caps.num_comp_vectors, MAX_RX_RINGS);
+               mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n",
+                         mdev->profile.prof[i].rx_ring_num, i);
        }
 
        /* Create our own workqueue for reset/multicast tasks
index ebada3c7aff2aee26ed5acbc306733be6e126bf6..15bb38d99304466524864f4c63df6aac9a6aaffb 100644 (file)
@@ -552,7 +552,7 @@ static void mlx4_en_linkstate(struct work_struct *work)
 }
 
 
-static int mlx4_en_start_port(struct net_device *dev)
+int mlx4_en_start_port(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
@@ -707,7 +707,7 @@ cq_err:
 }
 
 
-static void mlx4_en_stop_port(struct net_device *dev)
+void mlx4_en_stop_port(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
@@ -826,7 +826,7 @@ static int mlx4_en_close(struct net_device *dev)
        return 0;
 }
 
-static void mlx4_en_free_resources(struct mlx4_en_priv *priv)
+void mlx4_en_free_resources(struct mlx4_en_priv *priv)
 {
        int i;
 
@@ -845,7 +845,7 @@ static void mlx4_en_free_resources(struct mlx4_en_priv *priv)
        }
 }
 
-static int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
+int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
 {
        struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_en_port_profile *prof = priv->prof;
index 047b37f5a7474cc8137753590e3d85858e712ce6..cfeef0f1bacc6ae38a23a74caefb6646a40361fd 100644 (file)
@@ -65,15 +65,6 @@ MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
 MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
                           " Per priority bit mask");
 
-MLX4_EN_PARM_INT(rx_ring_num1, 0, "Number or Rx rings for port 1 (0 = #cores)");
-MLX4_EN_PARM_INT(rx_ring_num2, 0, "Number or Rx rings for port 2 (0 = #cores)");
-
-MLX4_EN_PARM_INT(tx_ring_size1, MLX4_EN_AUTO_CONF, "Tx ring size for port 1");
-MLX4_EN_PARM_INT(tx_ring_size2, MLX4_EN_AUTO_CONF, "Tx ring size for port 2");
-MLX4_EN_PARM_INT(rx_ring_size1, MLX4_EN_AUTO_CONF, "Rx ring size for port 1");
-MLX4_EN_PARM_INT(rx_ring_size2, MLX4_EN_AUTO_CONF, "Rx ring size for port 2");
-
-
 int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
 {
        struct mlx4_en_profile *params = &mdev->profile;
@@ -87,6 +78,8 @@ int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                params->prof[i].rx_ppp = pfcrx;
                params->prof[i].tx_pause = 1;
                params->prof[i].tx_ppp = pfctx;
+               params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
+               params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
        }
        if (pfcrx || pfctx) {
                params->prof[1].tx_ring_num = MLX4_EN_TX_RING_NUM;
@@ -95,32 +88,7 @@ int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                params->prof[1].tx_ring_num = 1;
                params->prof[2].tx_ring_num = 1;
        }
-       params->prof[1].rx_ring_num = min_t(int, rx_ring_num1, MAX_RX_RINGS);
-       params->prof[2].rx_ring_num = min_t(int, rx_ring_num2, MAX_RX_RINGS);
-
-       if (tx_ring_size1 == MLX4_EN_AUTO_CONF)
-               tx_ring_size1 = MLX4_EN_DEF_TX_RING_SIZE;
-       params->prof[1].tx_ring_size =
-               (tx_ring_size1 < MLX4_EN_MIN_TX_SIZE) ?
-                MLX4_EN_MIN_TX_SIZE : roundup_pow_of_two(tx_ring_size1);
-
-       if (tx_ring_size2 == MLX4_EN_AUTO_CONF)
-               tx_ring_size2 = MLX4_EN_DEF_TX_RING_SIZE;
-       params->prof[2].tx_ring_size =
-               (tx_ring_size2 < MLX4_EN_MIN_TX_SIZE) ?
-                MLX4_EN_MIN_TX_SIZE : roundup_pow_of_two(tx_ring_size2);
-
-       if (rx_ring_size1 == MLX4_EN_AUTO_CONF)
-               rx_ring_size1 = MLX4_EN_DEF_RX_RING_SIZE;
-       params->prof[1].rx_ring_size =
-               (rx_ring_size1 < MLX4_EN_MIN_RX_SIZE) ?
-                MLX4_EN_MIN_RX_SIZE : roundup_pow_of_two(rx_ring_size1);
-
-       if (rx_ring_size2 == MLX4_EN_AUTO_CONF)
-               rx_ring_size2 = MLX4_EN_DEF_RX_RING_SIZE;
-       params->prof[2].rx_ring_size =
-               (rx_ring_size2 < MLX4_EN_MIN_RX_SIZE) ?
-                MLX4_EN_MIN_RX_SIZE : roundup_pow_of_two(rx_ring_size2);
+
        return 0;
 }
 
@@ -417,6 +385,54 @@ static void mlx4_en_get_pauseparam(struct net_device *dev,
        pause->rx_pause = priv->prof->rx_pause;
 }
 
+static int mlx4_en_set_ringparam(struct net_device *dev,
+                                struct ethtool_ringparam *param)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = priv->mdev;
+       u32 rx_size, tx_size;
+       int port_up = 0;
+       int err = 0;
+
+       if (param->rx_jumbo_pending || param->rx_mini_pending)
+               return -EINVAL;
+
+       rx_size = roundup_pow_of_two(param->rx_pending);
+       rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE);
+       tx_size = roundup_pow_of_two(param->tx_pending);
+       tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
+
+       if (rx_size == priv->prof->rx_ring_size &&
+           tx_size == priv->prof->tx_ring_size)
+               return 0;
+
+       mutex_lock(&mdev->state_lock);
+       if (priv->port_up) {
+               port_up = 1;
+               mlx4_en_stop_port(dev);
+       }
+
+       mlx4_en_free_resources(priv);
+
+       priv->prof->tx_ring_size = tx_size;
+       priv->prof->rx_ring_size = rx_size;
+
+       err = mlx4_en_alloc_resources(priv);
+       if (err) {
+               mlx4_err(mdev, "Failed reallocating port resources\n");
+               goto out;
+       }
+       if (port_up) {
+               err = mlx4_en_start_port(dev);
+               if (err)
+                       mlx4_err(mdev, "Failed starting port\n");
+       }
+
+out:
+       mutex_unlock(&mdev->state_lock);
+       return err;
+}
+
 static void mlx4_en_get_ringparam(struct net_device *dev,
                                  struct ethtool_ringparam *param)
 {
@@ -456,6 +472,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
        .get_pauseparam = mlx4_en_get_pauseparam,
        .set_pauseparam = mlx4_en_set_pauseparam,
        .get_ringparam = mlx4_en_get_ringparam,
+       .set_ringparam = mlx4_en_set_ringparam,
        .get_flags = ethtool_op_get_flags,
        .set_flags = ethtool_op_set_flags,
 };
index e78209768def3d757547facacc79568cdb4a7c90..2e96c7b2180a86a4010c1b945d3bbe16c06c3b2b 100644 (file)
@@ -489,6 +489,12 @@ void mlx4_en_destroy_netdev(struct net_device *dev);
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                        struct mlx4_en_port_profile *prof);
 
+int mlx4_en_start_port(struct net_device *dev);
+void mlx4_en_stop_port(struct net_device *dev);
+
+void mlx4_en_free_resources(struct mlx4_en_priv *priv);
+int mlx4_en_alloc_resources(struct mlx4_en_priv *priv);
+
 int mlx4_en_get_profile(struct mlx4_en_dev *mdev);
 
 int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
index dcd199045613f3bbc4921ae2bee71d92f743ff62..5b7a574ce571ecef42892f787931ad18ed2f2614 100644 (file)
@@ -954,7 +954,6 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
 {
        const struct pasemi_mac_rxring *rxring = data;
        struct pasemi_mac *mac = rxring->mac;
-       struct net_device *dev = mac->netdev;
        const struct pasemi_dmachan *chan = &rxring->chan;
        unsigned int reg;
 
@@ -1634,7 +1633,6 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev)
 static int pasemi_mac_poll(struct napi_struct *napi, int budget)
 {
        struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi);
-       struct net_device *dev = mac->netdev;
        int pkts;
 
        pasemi_mac_clean_tx(tx_ring(mac));
index cc7d85bdfb3e5034de17312bfa9fce01421558c0..870b4c33f108d87b384b3fe46c506d4f1cb1107e 100644 (file)
@@ -200,6 +200,9 @@ static inline void SMC_outsl(struct smc911x_local *lp, int reg,
 
 
 #ifdef SMC_USE_PXA_DMA
+
+#include <mach/dma.h>
+
 /*
  * Define the request and free functions
  * These are unfortunately architecture specific as no generic allocation
index 3e7c6a3cbc650c8f0a39afa4bc49eb48f7aac191..c4ccd121bc9c648ba90a2bbf8e3c110e2bacb187 100644 (file)
@@ -493,7 +493,8 @@ struct smc_local {
  * as RX which can overrun memory and lose packets.
  */
 #include <linux/dma-mapping.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 
 #ifdef SMC_insl
index 5e989d884dddc9bc13e3f14ca7bde9749332b0cf..dc3f1108884d0709159246031c6252e1f42079f6 100644 (file)
@@ -1484,13 +1484,13 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
        }
 
        if (likely(intsts & inten & INT_STS_RSFL_)) {
-               if (likely(netif_rx_schedule_prep(dev, &pdata->napi))) {
+               if (likely(netif_rx_schedule_prep(&pdata->napi))) {
                        /* Disable Rx interrupts */
                        temp = smsc911x_reg_read(pdata, INT_EN);
                        temp &= (~INT_EN_RSFL_EN_);
                        smsc911x_reg_write(pdata, INT_EN, temp);
                        /* Schedule a NAPI poll */
-                       __netif_rx_schedule(dev, &pdata->napi);
+                       __netif_rx_schedule(&pdata->napi);
                } else {
                        SMSC_WARNING(RX_ERR,
                                "netif_rx_schedule_prep failed");
index c5c123d3af57f00b5930d7cf318f1a3444f5dcd5..88d2c67788dfd2ab8fb692b575b98e2f2066ec6d 100644 (file)
@@ -1277,7 +1277,6 @@ bad_desc:
 static int spider_net_poll(struct napi_struct *napi, int budget)
 {
        struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
-       struct net_device *netdev = card->netdev;
        int packets_done = 0;
 
        while (packets_done < budget) {
index 666c1d98cdaf1d695aece39e195eac212d42e264..69f9a0ec764d3e8503cb46c1d3d4fa380e5b87f3 100644 (file)
@@ -343,7 +343,7 @@ static void tun_net_init(struct net_device *dev)
                break;
 
        case TUN_TAP_DEV:
-               dev->netdev_ops = &tun_netdev_ops;
+               dev->netdev_ops = &tap_netdev_ops;
                /* Ethernet TAP Device */
                ether_setup(dev);
 
index 198ce3cf378ae2b884ce16b21a5fa1ba7a028d5c..9f7896a25f1bfb6df80e1d16db0641305f5e8259 100644 (file)
@@ -2831,7 +2831,7 @@ static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf,
        for (i = 0; i < iface->desc.bNumEndpoints; i++) {
                endp = &iface->endpoint[i].desc;
                if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) &&
-                   ((endp->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == type))
+                   (usb_endpoint_type(endp) == type))
                        return endp;
        }
 
index 0c6802507a79817840e36194a0ec49b0993adb73..2dc241689d37a8f878f6b80202ed38dd95805435 100644 (file)
@@ -654,7 +654,7 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget)
                        netif_rx_complete(dev, napi);
                        qmgr_enable_irq(rxq);
                        if (!qmgr_stat_empty(rxq) &&
-                           netif_rx_reschedule(dev, napi)) {
+                           netif_rx_reschedule(napi)) {
 #if DEBUG_RX
                                printk(KERN_DEBUG "%s: hss_hdlc_poll"
                                       " netif_rx_reschedule succeeded\n",
index 04c1396669656261d87cf6dbc53a6bc1c4b748ff..b5db57d2fcf50d2e6087cc4e90064f5dc2625f5f 100644 (file)
@@ -1065,8 +1065,7 @@ static int eject_installer(struct usb_interface *intf)
        /* Find bulk out endpoint */
        endpoint = &iface_desc->endpoint[1].desc;
        if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
-           (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-           USB_ENDPOINT_XFER_BULK) {
+           usb_endpoint_xfer_bulk(endpoint)) {
                bulk_out_ep = endpoint->bEndpointAddress;
        } else {
                dev_err(&udev->dev,
index b55cd23ffdefc81dfb80409a98c5697c21822b50..737bd9484822498d9db077640ed7acc0859babb9 100644 (file)
@@ -268,18 +268,6 @@ lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
        return cookie;
 }
 
-static void increment_tail(struct oprofile_cpu_buffer *b)
-{
-       unsigned long new_tail = b->tail_pos + 1;
-
-       rmb();  /* be sure fifo pointers are synchromized */
-
-       if (new_tail < b->buffer_size)
-               b->tail_pos = new_tail;
-       else
-               b->tail_pos = 0;
-}
-
 static unsigned long last_cookie = INVALID_COOKIE;
 
 static void add_cpu_switch(int i)
@@ -331,28 +319,25 @@ static void add_trace_begin(void)
 
 #define IBS_FETCH_CODE_SIZE    2
 #define IBS_OP_CODE_SIZE       5
-#define IBS_EIP(offset)                                \
-       (((struct op_sample *)&cpu_buf->buffer[(offset)])->eip)
-#define IBS_EVENT(offset)                              \
-       (((struct op_sample *)&cpu_buf->buffer[(offset)])->event)
 
 /*
  * Add IBS fetch and op entries to event buffer
  */
-static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
-                         struct mm_struct *mm)
+static void add_ibs_begin(int cpu, int code, struct mm_struct *mm)
 {
        unsigned long rip;
        int i, count;
        unsigned long ibs_cookie = 0;
        off_t offset;
+       struct op_sample *sample;
 
-       increment_tail(cpu_buf);        /* move to RIP entry */
-
-       rip = IBS_EIP(cpu_buf->tail_pos);
+       sample = cpu_buffer_read_entry(cpu);
+       if (!sample)
+               goto Error;
+       rip = sample->eip;
 
 #ifdef __LP64__
-       rip += IBS_EVENT(cpu_buf->tail_pos) << 32;
+       rip += sample->event << 32;
 #endif
 
        if (mm) {
@@ -376,8 +361,8 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
        add_event_entry(offset);        /* Offset from Dcookie */
 
        /* we send the Dcookie offset, but send the raw Linear Add also*/
-       add_event_entry(IBS_EIP(cpu_buf->tail_pos));
-       add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+       add_event_entry(sample->eip);
+       add_event_entry(sample->event);
 
        if (code == IBS_FETCH_CODE)
                count = IBS_FETCH_CODE_SIZE;    /*IBS FETCH is 2 int64s*/
@@ -385,10 +370,17 @@ static void add_ibs_begin(struct oprofile_cpu_buffer *cpu_buf, int code,
                count = IBS_OP_CODE_SIZE;       /*IBS OP is 5 int64s*/
 
        for (i = 0; i < count; i++) {
-               increment_tail(cpu_buf);
-               add_event_entry(IBS_EIP(cpu_buf->tail_pos));
-               add_event_entry(IBS_EVENT(cpu_buf->tail_pos));
+               sample = cpu_buffer_read_entry(cpu);
+               if (!sample)
+                       goto Error;
+               add_event_entry(sample->eip);
+               add_event_entry(sample->event);
        }
+
+       return;
+
+Error:
+       return;
 }
 
 #endif
@@ -466,33 +458,6 @@ static inline int is_code(unsigned long val)
 }
 
 
-/* "acquire" as many cpu buffer slots as we can */
-static unsigned long get_slots(struct oprofile_cpu_buffer *b)
-{
-       unsigned long head = b->head_pos;
-       unsigned long tail = b->tail_pos;
-
-       /*
-        * Subtle. This resets the persistent last_task
-        * and in_kernel values used for switching notes.
-        * BUT, there is a small window between reading
-        * head_pos, and this call, that means samples
-        * can appear at the new head position, but not
-        * be prefixed with the notes for switching
-        * kernel mode or a task switch. This small hole
-        * can lead to mis-attribution or samples where
-        * we don't know if it's in the kernel or not,
-        * at the start of an event buffer.
-        */
-       cpu_buffer_reset(b);
-
-       if (head >= tail)
-               return head - tail;
-
-       return head + (b->buffer_size - tail);
-}
-
-
 /* Move tasks along towards death. Any tasks on dead_tasks
  * will definitely have no remaining references in any
  * CPU buffers at this point, because we use two lists,
@@ -559,61 +524,61 @@ typedef enum {
  */
 void sync_buffer(int cpu)
 {
-       struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
        struct mm_struct *mm = NULL;
+       struct mm_struct *oldmm;
        struct task_struct *new;
        unsigned long cookie = 0;
        int in_kernel = 1;
        sync_buffer_state state = sb_buffer_start;
-#ifndef CONFIG_OPROFILE_IBS
        unsigned int i;
        unsigned long available;
-#endif
 
        mutex_lock(&buffer_mutex);
 
        add_cpu_switch(cpu);
 
-       /* Remember, only we can modify tail_pos */
-
-#ifndef CONFIG_OPROFILE_IBS
-       available = get_slots(cpu_buf);
+       cpu_buffer_reset(cpu);
+       available = cpu_buffer_entries(cpu);
 
        for (i = 0; i < available; ++i) {
-#else
-       while (get_slots(cpu_buf)) {
-#endif
-               struct op_sample *s = &cpu_buf->buffer[cpu_buf->tail_pos];
+               struct op_sample *s = cpu_buffer_read_entry(cpu);
+               if (!s)
+                       break;
 
                if (is_code(s->eip)) {
-                       if (s->event <= CPU_IS_KERNEL) {
+                       switch (s->event) {
+                       case 0:
+                       case CPU_IS_KERNEL:
                                /* kernel/userspace switch */
                                in_kernel = s->event;
                                if (state == sb_buffer_start)
                                        state = sb_sample_start;
                                add_kernel_ctx_switch(s->event);
-                       } else if (s->event == CPU_TRACE_BEGIN) {
+                               break;
+                       case CPU_TRACE_BEGIN:
                                state = sb_bt_start;
                                add_trace_begin();
+                               break;
 #ifdef CONFIG_OPROFILE_IBS
-                       } else if (s->event == IBS_FETCH_BEGIN) {
+                       case IBS_FETCH_BEGIN:
                                state = sb_bt_start;
-                               add_ibs_begin(cpu_buf, IBS_FETCH_CODE, mm);
-                       } else if (s->event == IBS_OP_BEGIN) {
+                               add_ibs_begin(cpu, IBS_FETCH_CODE, mm);
+                               break;
+                       case IBS_OP_BEGIN:
                                state = sb_bt_start;
-                               add_ibs_begin(cpu_buf, IBS_OP_CODE, mm);
+                               add_ibs_begin(cpu, IBS_OP_CODE, mm);
+                               break;
 #endif
-                       } else {
-                               struct mm_struct *oldmm = mm;
-
+                       default:
                                /* userspace context switch */
+                               oldmm = mm;
                                new = (struct task_struct *)s->event;
-
                                release_mm(oldmm);
                                mm = take_tasks_mm(new);
                                if (mm != oldmm)
                                        cookie = get_exec_dcookie(mm);
                                add_user_ctx_switch(new, cookie);
+                               break;
                        }
                } else if (state >= sb_bt_start &&
                           !add_sample(mm, s, in_kernel)) {
@@ -622,8 +587,6 @@ void sync_buffer(int cpu)
                                atomic_inc(&oprofile_stats.bt_lost_no_mapping);
                        }
                }
-
-               increment_tail(cpu_buf);
        }
        release_mm(mm);
 
index 01d38e78cde18bd341fca22940249e4a80068217..61090969158facb8ae1843b6eba255202fdf8c4a 100644 (file)
 #include "buffer_sync.h"
 #include "oprof.h"
 
+#define OP_BUFFER_FLAGS        0
+
+/*
+ * Read and write access is using spin locking. Thus, writing to the
+ * buffer by NMI handler (x86) could occur also during critical
+ * sections when reading the buffer. To avoid this, there are 2
+ * buffers for independent read and write access. Read access is in
+ * process context only, write access only in the NMI handler. If the
+ * read buffer runs empty, both buffers are swapped atomically. There
+ * is potentially a small window during swapping where the buffers are
+ * disabled and samples could be lost.
+ *
+ * Using 2 buffers is a little bit overhead, but the solution is clear
+ * and does not require changes in the ring buffer implementation. It
+ * can be changed to a single buffer solution when the ring buffer
+ * access is implemented as non-locking atomic code.
+ */
+struct ring_buffer *op_ring_buffer_read;
+struct ring_buffer *op_ring_buffer_write;
 DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
 
 static void wq_sync_buffer(struct work_struct *work);
@@ -37,12 +56,12 @@ static int work_enabled;
 
 void free_cpu_buffers(void)
 {
-       int i;
-
-       for_each_possible_cpu(i) {
-               vfree(per_cpu(cpu_buffer, i).buffer);
-               per_cpu(cpu_buffer, i).buffer = NULL;
-       }
+       if (op_ring_buffer_read)
+               ring_buffer_free(op_ring_buffer_read);
+       op_ring_buffer_read = NULL;
+       if (op_ring_buffer_write)
+               ring_buffer_free(op_ring_buffer_write);
+       op_ring_buffer_write = NULL;
 }
 
 unsigned long oprofile_get_cpu_buffer_size(void)
@@ -64,14 +83,16 @@ int alloc_cpu_buffers(void)
 
        unsigned long buffer_size = fs_cpu_buffer_size;
 
+       op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS);
+       if (!op_ring_buffer_read)
+               goto fail;
+       op_ring_buffer_write = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS);
+       if (!op_ring_buffer_write)
+               goto fail;
+
        for_each_possible_cpu(i) {
                struct oprofile_cpu_buffer *b = &per_cpu(cpu_buffer, i);
 
-               b->buffer = vmalloc_node(sizeof(struct op_sample) * buffer_size,
-                       cpu_to_node(i));
-               if (!b->buffer)
-                       goto fail;
-
                b->last_task = NULL;
                b->last_is_kernel = -1;
                b->tracing = 0;
@@ -124,57 +145,31 @@ void end_cpu_work(void)
        flush_scheduled_work();
 }
 
-/* Resets the cpu buffer to a sane state. */
-void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf)
-{
-       /* reset these to invalid values; the next sample
-        * collected will populate the buffer with proper
-        * values to initialize the buffer
-        */
-       cpu_buf->last_is_kernel = -1;
-       cpu_buf->last_task = NULL;
-}
-
-/* compute number of available slots in cpu_buffer queue */
-static unsigned long nr_available_slots(struct oprofile_cpu_buffer const *b)
+static inline int
+add_sample(struct oprofile_cpu_buffer *cpu_buf,
+          unsigned long pc, unsigned long event)
 {
-       unsigned long head = b->head_pos;
-       unsigned long tail = b->tail_pos;
+       struct op_entry entry;
+       int ret;
 
-       if (tail > head)
-               return (tail - head) - 1;
+       ret = cpu_buffer_write_entry(&entry);
+       if (ret)
+               return ret;
 
-       return tail + (b->buffer_size - head) - 1;
-}
+       entry.sample->eip = pc;
+       entry.sample->event = event;
 
-static void increment_head(struct oprofile_cpu_buffer *b)
-{
-       unsigned long new_head = b->head_pos + 1;
-
-       /* Ensure anything written to the slot before we
-        * increment is visible */
-       wmb();
-
-       if (new_head < b->buffer_size)
-               b->head_pos = new_head;
-       else
-               b->head_pos = 0;
-}
+       ret = cpu_buffer_write_commit(&entry);
+       if (ret)
+               return ret;
 
-static inline void
-add_sample(struct oprofile_cpu_buffer *cpu_buf,
-          unsigned long pc, unsigned long event)
-{
-       struct op_sample *entry = &cpu_buf->buffer[cpu_buf->head_pos];
-       entry->eip = pc;
-       entry->event = event;
-       increment_head(cpu_buf);
+       return 0;
 }
 
-static inline void
+static inline int
 add_code(struct oprofile_cpu_buffer *buffer, unsigned long value)
 {
-       add_sample(buffer, ESCAPE_CODE, value);
+       return add_sample(buffer, ESCAPE_CODE, value);
 }
 
 /* This must be safe from any context. It's safe writing here
@@ -198,11 +193,6 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
                return 0;
        }
 
-       if (nr_available_slots(cpu_buf) < 3) {
-               cpu_buf->sample_lost_overflow++;
-               return 0;
-       }
-
        is_kernel = !!is_kernel;
 
        task = current;
@@ -210,26 +200,29 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
        /* notice a switch from user->kernel or vice versa */
        if (cpu_buf->last_is_kernel != is_kernel) {
                cpu_buf->last_is_kernel = is_kernel;
-               add_code(cpu_buf, is_kernel);
+               if (add_code(cpu_buf, is_kernel))
+                       goto fail;
        }
 
        /* notice a task switch */
        if (cpu_buf->last_task != task) {
                cpu_buf->last_task = task;
-               add_code(cpu_buf, (unsigned long)task);
+               if (add_code(cpu_buf, (unsigned long)task))
+                       goto fail;
        }
 
-       add_sample(cpu_buf, pc, event);
+       if (add_sample(cpu_buf, pc, event))
+               goto fail;
+
        return 1;
+
+fail:
+       cpu_buf->sample_lost_overflow++;
+       return 0;
 }
 
 static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
 {
-       if (nr_available_slots(cpu_buf) < 4) {
-               cpu_buf->sample_lost_overflow++;
-               return 0;
-       }
-
        add_code(cpu_buf, CPU_TRACE_BEGIN);
        cpu_buf->tracing = 1;
        return 1;
@@ -253,8 +246,10 @@ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
        if (!oprofile_begin_trace(cpu_buf))
                return;
 
-       /* if log_sample() fail we can't backtrace since we lost the source
-        * of this event */
+       /*
+        * if log_sample() fail we can't backtrace since we lost the
+        * source of this event
+        */
        if (log_sample(cpu_buf, pc, is_kernel, event))
                oprofile_ops.backtrace(regs, backtrace_depth);
        oprofile_end_trace(cpu_buf);
@@ -272,49 +267,55 @@ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
 
 #define MAX_IBS_SAMPLE_SIZE 14
 
-void oprofile_add_ibs_sample(struct pt_regs *const regs,
-                            unsigned int *const ibs_sample, int ibs_code)
+void oprofile_add_ibs_sample(struct pt_regs * const regs,
+                            unsigned int * const ibs_sample, int ibs_code)
 {
        int is_kernel = !user_mode(regs);
        struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
        struct task_struct *task;
+       int fail = 0;
 
        cpu_buf->sample_received++;
 
-       if (nr_available_slots(cpu_buf) < MAX_IBS_SAMPLE_SIZE) {
-               /* we can't backtrace since we lost the source of this event */
-               cpu_buf->sample_lost_overflow++;
-               return;
-       }
-
        /* notice a switch from user->kernel or vice versa */
        if (cpu_buf->last_is_kernel != is_kernel) {
+               if (add_code(cpu_buf, is_kernel))
+                       goto fail;
                cpu_buf->last_is_kernel = is_kernel;
-               add_code(cpu_buf, is_kernel);
        }
 
        /* notice a task switch */
        if (!is_kernel) {
                task = current;
                if (cpu_buf->last_task != task) {
+                       if (add_code(cpu_buf, (unsigned long)task))
+                               goto fail;
                        cpu_buf->last_task = task;
-                       add_code(cpu_buf, (unsigned long)task);
                }
        }
 
-       add_code(cpu_buf, ibs_code);
-       add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]);
-       add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]);
-       add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]);
+       fail = fail || add_code(cpu_buf, ibs_code);
+       fail = fail || add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]);
+       fail = fail || add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]);
+       fail = fail || add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]);
 
        if (ibs_code == IBS_OP_BEGIN) {
-               add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]);
-               add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]);
-               add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]);
+               fail = fail || add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]);
+               fail = fail || add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]);
+               fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]);
        }
 
+       if (fail)
+               goto fail;
+
        if (backtrace_depth)
                oprofile_ops.backtrace(regs, backtrace_depth);
+
+       return;
+
+fail:
+       cpu_buf->sample_lost_overflow++;
+       return;
 }
 
 #endif
@@ -332,21 +333,21 @@ void oprofile_add_trace(unsigned long pc)
        if (!cpu_buf->tracing)
                return;
 
-       if (nr_available_slots(cpu_buf) < 1) {
-               cpu_buf->tracing = 0;
-               cpu_buf->sample_lost_overflow++;
-               return;
-       }
+       /*
+        * broken frame can give an eip with the same value as an
+        * escape code, abort the trace if we get it
+        */
+       if (pc == ESCAPE_CODE)
+               goto fail;
 
-       /* broken frame can give an eip with the same value as an escape code,
-        * abort the trace if we get it */
-       if (pc == ESCAPE_CODE) {
-               cpu_buf->tracing = 0;
-               cpu_buf->backtrace_aborted++;
-               return;
-       }
+       if (add_sample(cpu_buf, pc, 0))
+               goto fail;
 
-       add_sample(cpu_buf, pc, 0);
+       return;
+fail:
+       cpu_buf->tracing = 0;
+       cpu_buf->backtrace_aborted++;
+       return;
 }
 
 /*
index d3cc26264db55b60948a71b9f8500a236666a64d..aacb0f0bc56682d37aca262f0d72ad135fb7cedc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/workqueue.h>
 #include <linux/cache.h>
 #include <linux/sched.h>
+#include <linux/ring_buffer.h>
 
 struct task_struct;
 
@@ -32,6 +33,12 @@ struct op_sample {
        unsigned long event;
 };
 
+struct op_entry {
+       struct ring_buffer_event *event;
+       struct op_sample *sample;
+       unsigned long irq_flags;
+};
+
 struct oprofile_cpu_buffer {
        volatile unsigned long head_pos;
        volatile unsigned long tail_pos;
@@ -39,7 +46,6 @@ struct oprofile_cpu_buffer {
        struct task_struct *last_task;
        int last_is_kernel;
        int tracing;
-       struct op_sample *buffer;
        unsigned long sample_received;
        unsigned long sample_lost_overflow;
        unsigned long backtrace_aborted;
@@ -48,9 +54,68 @@ struct oprofile_cpu_buffer {
        struct delayed_work work;
 };
 
+extern struct ring_buffer *op_ring_buffer_read;
+extern struct ring_buffer *op_ring_buffer_write;
 DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
 
-void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf);
+/*
+ * Resets the cpu buffer to a sane state.
+ *
+ * reset these to invalid values; the next sample collected will
+ * populate the buffer with proper values to initialize the buffer
+ */
+static inline void cpu_buffer_reset(int cpu)
+{
+       struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
+
+       cpu_buf->last_is_kernel = -1;
+       cpu_buf->last_task = NULL;
+}
+
+static inline int cpu_buffer_write_entry(struct op_entry *entry)
+{
+       entry->event = ring_buffer_lock_reserve(op_ring_buffer_write,
+                                               sizeof(struct op_sample),
+                                               &entry->irq_flags);
+       if (entry->event)
+               entry->sample = ring_buffer_event_data(entry->event);
+       else
+               entry->sample = NULL;
+
+       if (!entry->sample)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static inline int cpu_buffer_write_commit(struct op_entry *entry)
+{
+       return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event,
+                                        entry->irq_flags);
+}
+
+static inline struct op_sample *cpu_buffer_read_entry(int cpu)
+{
+       struct ring_buffer_event *e;
+       e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
+       if (e)
+               return ring_buffer_event_data(e);
+       if (ring_buffer_swap_cpu(op_ring_buffer_read,
+                                op_ring_buffer_write,
+                                cpu))
+               return NULL;
+       e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
+       if (e)
+               return ring_buffer_event_data(e);
+       return NULL;
+}
+
+/* "acquire" as many cpu buffer slots as we can */
+static inline unsigned long cpu_buffer_entries(int cpu)
+{
+       return ring_buffer_entries_cpu(op_ring_buffer_read, cpu)
+               + ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
+}
 
 /* transient events for the CPU buffer -> event buffer */
 #define CPU_IS_KERNEL 1
index cc106d503acec3cdb2917ba0ea316e267474f724..d8201998b0b7f8d93b5b7f1a654851374256dff9 100644 (file)
 #include "oprofile_stats.h"
 #include "oprof.h"
 
-unsigned long fs_buffer_size = 131072;
-unsigned long fs_cpu_buffer_size = 8192;
-unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
+#define FS_BUFFER_SIZE_DEFAULT         131072
+#define FS_CPU_BUFFER_SIZE_DEFAULT     8192
+#define FS_BUFFER_WATERSHED_DEFAULT    32768   /* FIXME: tune */
+
+unsigned long fs_buffer_size;
+unsigned long fs_cpu_buffer_size;
+unsigned long fs_buffer_watershed;
 
 static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
@@ -120,6 +124,11 @@ static const struct file_operations dump_fops = {
 
 void oprofile_create_files(struct super_block *sb, struct dentry *root)
 {
+       /* reinitialize default values */
+       fs_buffer_size =        FS_BUFFER_SIZE_DEFAULT;
+       fs_cpu_buffer_size =    FS_CPU_BUFFER_SIZE_DEFAULT;
+       fs_buffer_watershed =   FS_BUFFER_WATERSHED_DEFAULT;
+
        oprofilefs_create_file(sb, root, "enable", &enable_fops);
        oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
        oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
index 2de5a3238c947be89213119d9cf468d2fa59e11d..f78371b2252976efb8ab86c7eaf87a7240949ea5 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/pci.h>
 #include <linux/irq.h>
 #include <asm/io_apic.h>
+#include <asm/smp.h>
 #include <linux/intel-iommu.h>
 #include "intr_remapping.h"
 
@@ -19,17 +20,75 @@ struct irq_2_iommu {
        u8  irte_mask;
 };
 
-static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
+#ifdef CONFIG_SPARSE_IRQ
+static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
+{
+       struct irq_2_iommu *iommu;
+       int node;
+
+       node = cpu_to_node(cpu);
+
+       iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
+       printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
+
+       return iommu;
+}
 
 static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
-       return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL;
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+
+       if (WARN_ON_ONCE(!desc))
+               return NULL;
+
+       return desc->irq_2_iommu;
+}
+
+static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
+{
+       struct irq_desc *desc;
+       struct irq_2_iommu *irq_iommu;
+
+       /*
+        * alloc irq desc if not allocated already.
+        */
+       desc = irq_to_desc_alloc_cpu(irq, cpu);
+       if (!desc) {
+               printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+               return NULL;
+       }
+
+       irq_iommu = desc->irq_2_iommu;
+
+       if (!irq_iommu)
+               desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu);
+
+       return desc->irq_2_iommu;
 }
 
+static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
+{
+       return irq_2_iommu_alloc_cpu(irq, boot_cpu_id);
+}
+
+#else /* !CONFIG_SPARSE_IRQ */
+
+static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
+
+static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
+{
+       if (irq < nr_irqs)
+               return &irq_2_iommuX[irq];
+
+       return NULL;
+}
 static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
 {
        return irq_2_iommu(irq);
 }
+#endif
 
 static DEFINE_SPINLOCK(irq_2_ir_lock);
 
@@ -86,9 +145,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        if (!count)
                return -1;
 
+#ifndef CONFIG_SPARSE_IRQ
        /* protect irq_2_iommu_alloc later */
        if (irq >= nr_irqs)
                return -1;
+#endif
 
        /*
         * start the IRTE search from index 0.
@@ -130,6 +191,12 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
                table->base[i].present = 1;
 
        irq_iommu = irq_2_iommu_alloc(irq);
+       if (!irq_iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               printk(KERN_ERR "can't allocate irq_2_iommu\n");
+               return -1;
+       }
+
        irq_iommu->iommu = iommu;
        irq_iommu->irte_index =  index;
        irq_iommu->sub_handle = 0;
@@ -177,6 +244,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 
        irq_iommu = irq_2_iommu_alloc(irq);
 
+       if (!irq_iommu) {
+               spin_unlock(&irq_2_ir_lock);
+               printk(KERN_ERR "can't allocate irq_2_iommu\n");
+               return -1;
+       }
+
        irq_iommu->iommu = iommu;
        irq_iommu->irte_index = index;
        irq_iommu->sub_handle = subhandle;
index 74801f7df9c901ad21017ce2a831e0cd61c8af1c..11a51f8ed3b3b96ffa72820f195c6a7afa4bfa40 100644 (file)
@@ -103,11 +103,11 @@ static void msix_set_enable(struct pci_dev *dev, int enable)
        }
 }
 
-static void msix_flush_writes(unsigned int irq)
+static void msix_flush_writes(struct irq_desc *desc)
 {
        struct msi_desc *entry;
 
-       entry = get_irq_msi(irq);
+       entry = get_irq_desc_msi(desc);
        BUG_ON(!entry || !entry->dev);
        switch (entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
@@ -135,11 +135,11 @@ static void msix_flush_writes(unsigned int irq)
  * Returns 1 if it succeeded in masking the interrupt and 0 if the device
  * doesn't support MSI masking.
  */
-static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
+static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag)
 {
        struct msi_desc *entry;
 
-       entry = get_irq_msi(irq);
+       entry = get_irq_desc_msi(desc);
        BUG_ON(!entry || !entry->dev);
        switch (entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
@@ -172,9 +172,9 @@ static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
        return 1;
 }
 
-void read_msi_msg(unsigned int irq, struct msi_msg *msg)
+void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_msi(irq);
+       struct msi_desc *entry = get_irq_desc_msi(desc);
        switch(entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
        {
@@ -211,9 +211,16 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
        }
 }
 
-void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_msi(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       read_msi_msg_desc(desc, msg);
+}
+
+void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+{
+       struct msi_desc *entry = get_irq_desc_msi(desc);
        switch (entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
        {
@@ -252,21 +259,31 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
        entry->msg = *msg;
 }
 
+void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       write_msi_msg_desc(desc, msg);
+}
+
 void mask_msi_irq(unsigned int irq)
 {
-       msi_set_mask_bits(irq, 1, 1);
-       msix_flush_writes(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       msi_set_mask_bits(desc, 1, 1);
+       msix_flush_writes(desc);
 }
 
 void unmask_msi_irq(unsigned int irq)
 {
-       msi_set_mask_bits(irq, 1, 0);
-       msix_flush_writes(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       msi_set_mask_bits(desc, 1, 0);
+       msix_flush_writes(desc);
 }
 
 static int msi_free_irqs(struct pci_dev* dev);
 
-
 static struct msi_desc* alloc_msi_entry(void)
 {
        struct msi_desc *entry;
@@ -303,9 +320,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
        pci_intx_for_msi(dev, 0);
        msi_set_enable(dev, 0);
        write_msi_msg(dev->irq, &entry->msg);
-       if (entry->msi_attrib.maskbit)
-               msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask,
+       if (entry->msi_attrib.maskbit) {
+               struct irq_desc *desc = irq_to_desc(dev->irq);
+               msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask,
                                  entry->msi_attrib.masked);
+       }
 
        pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
        control &= ~PCI_MSI_FLAGS_QSIZE;
@@ -327,8 +346,9 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
        msix_set_enable(dev, 0);
 
        list_for_each_entry(entry, &dev->msi_list, list) {
+               struct irq_desc *desc = irq_to_desc(entry->irq);
                write_msi_msg(entry->irq, &entry->msg);
-               msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked);
+               msi_set_mask_bits(desc, 1, entry->msi_attrib.masked);
        }
 
        BUG_ON(list_empty(&dev->msi_list));
@@ -596,7 +616,8 @@ void pci_msi_shutdown(struct pci_dev* dev)
        /* Return the the pci reset with msi irqs unmasked */
        if (entry->msi_attrib.maskbit) {
                u32 mask = entry->msi_attrib.maskbits_mask;
-               msi_set_mask_bits(dev->irq, mask, ~mask);
+               struct irq_desc *desc = irq_to_desc(dev->irq);
+               msi_set_mask_bits(desc, mask, ~mask);
        }
        if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
                return;
index 222904411a13a02ef83db412704a40b7d3863ee5..276473543982b521d8f29eb3da93bb315086a57c 100644 (file)
@@ -217,7 +217,7 @@ config PCMCIA_PXA2XX
        depends on ARM && ARCH_PXA && PCMCIA
        depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
                    || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
-                   || ARCH_VIPER)
+                   || ARCH_VIPER || ARCH_PXA_ESERIES)
        help
          Say Y here to include support for the PXA2xx PCMCIA controller
 
index 238629ad7f7c7243da4b18c7e110bc85df289887..bbac46327227e5d0e12a9125179525daf34a4c37 100644 (file)
@@ -72,5 +72,6 @@ pxa2xx-obj-$(CONFIG_ARCH_VIPER)                       += pxa2xx_viper.o
 pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA)            += pxa2xx_trizeps4.o
 pxa2xx-obj-$(CONFIG_MACH_PALMTX)               += pxa2xx_palmtx.o
 pxa2xx-obj-$(CONFIG_MACH_PALMLD)               += pxa2xx_palmld.o
+pxa2xx-obj-$(CONFIG_MACH_E740)                 += pxa2xx_e740.o
 
 obj-$(CONFIG_PCMCIA_PXA2XX)                    += pxa2xx_core.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/pxa2xx_e740.c b/drivers/pcmcia/pxa2xx_e740.c
new file mode 100644 (file)
index 0000000..f663a01
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Toshiba e740 PCMCIA specific routines.
+ *
+ * (c) 2004 Ian Molton <spyro@f2s.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/kernel.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/pxa-regs.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include "soc_common.h"
+
+static struct pcmcia_irqs cd_irqs[] = {
+       {
+               .sock = 0,
+               .irq  = IRQ_GPIO(GPIO_E740_PCMCIA_CD0),
+               .str  = "CF card detect"
+       },
+       {
+               .sock = 1,
+               .irq  = IRQ_GPIO(GPIO_E740_PCMCIA_CD1),
+               .str  = "Wifi switch"
+       },
+};
+
+static int e740_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+       skt->irq = skt->nr == 0 ? IRQ_GPIO(GPIO_E740_PCMCIA_RDY0) :
+                               IRQ_GPIO(GPIO_E740_PCMCIA_RDY1);
+
+       return soc_pcmcia_request_irqs(skt, &cd_irqs[skt->nr], 1);
+}
+
+/*
+ * Release all resources.
+ */
+static void e740_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+       soc_pcmcia_free_irqs(skt, &cd_irqs[skt->nr], 1);
+}
+
+static void e740_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+                                       struct pcmcia_state *state)
+{
+       if (skt->nr == 0) {
+               state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD0) ? 0 : 1;
+               state->ready  = gpio_get_value(GPIO_E740_PCMCIA_RDY0) ? 1 : 0;
+       } else {
+               state->detect = gpio_get_value(GPIO_E740_PCMCIA_CD1) ? 0 : 1;
+               state->ready  = gpio_get_value(GPIO_E740_PCMCIA_RDY1) ? 1 : 0;
+       }
+
+       state->vs_3v  = 1;
+       state->bvd1   = 1;
+       state->bvd2   = 1;
+       state->wrprot = 0;
+       state->vs_Xv  = 0;
+}
+
+static int e740_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+                                       const socket_state_t *state)
+{
+       if (state->flags & SS_RESET) {
+               if (skt->nr == 0)
+                       gpio_set_value(GPIO_E740_PCMCIA_RST0, 1);
+               else
+                       gpio_set_value(GPIO_E740_PCMCIA_RST1, 1);
+       } else {
+               if (skt->nr == 0)
+                       gpio_set_value(GPIO_E740_PCMCIA_RST0, 0);
+               else
+                       gpio_set_value(GPIO_E740_PCMCIA_RST1, 0);
+       }
+
+       switch (state->Vcc) {
+       case 0: /* Socket off */
+               if (skt->nr == 0)
+                       gpio_set_value(GPIO_E740_PCMCIA_PWR0, 0);
+               else
+                       gpio_set_value(GPIO_E740_PCMCIA_PWR1, 1);
+               break;
+       case 50:
+       case 33: /* socket on */
+               if (skt->nr == 0)
+                       gpio_set_value(GPIO_E740_PCMCIA_PWR0, 1);
+               else
+                       gpio_set_value(GPIO_E740_PCMCIA_PWR1, 0);
+               break;
+       default:
+               printk(KERN_ERR "e740_cs: Unsupported Vcc: %d\n", state->Vcc);
+       }
+
+       return 0;
+}
+
+/*
+ * Enable card status IRQs on (re-)initialisation.  This can
+ * be called at initialisation, power management event, or
+ * pcmcia event.
+ */
+static void e740_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+       soc_pcmcia_enable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
+}
+
+/*
+ * Disable card status IRQs on suspend.
+ */
+static void e740_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+       soc_pcmcia_disable_irqs(skt, cd_irqs, ARRAY_SIZE(cd_irqs));
+}
+
+static struct pcmcia_low_level e740_pcmcia_ops = {
+       .owner            = THIS_MODULE,
+       .hw_init          = e740_pcmcia_hw_init,
+       .hw_shutdown      = e740_pcmcia_hw_shutdown,
+       .socket_state     = e740_pcmcia_socket_state,
+       .configure_socket = e740_pcmcia_configure_socket,
+       .socket_init      = e740_pcmcia_socket_init,
+       .socket_suspend   = e740_pcmcia_socket_suspend,
+       .nr               = 2,
+};
+
+static struct platform_device *e740_pcmcia_device;
+
+static int __init e740_pcmcia_init(void)
+{
+       int ret;
+
+       if (!machine_is_e740())
+               return -ENODEV;
+
+       e740_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+       if (!e740_pcmcia_device)
+               return -ENOMEM;
+
+       ret = platform_device_add_data(e740_pcmcia_device, &e740_pcmcia_ops,
+                                       sizeof(e740_pcmcia_ops));
+
+       if (!ret)
+               ret = platform_device_add(e740_pcmcia_device);
+
+       if (ret)
+               platform_device_put(e740_pcmcia_device);
+
+       return ret;
+}
+
+static void __exit e740_pcmcia_exit(void)
+{
+       platform_device_unregister(e740_pcmcia_device);
+}
+
+module_init(e740_pcmcia_init);
+module_exit(e740_pcmcia_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_DESCRIPTION("e740 PCMCIA platform support");
index 2133f37906f2928f8d3ccacf0fc7bcd77aa7d3ce..d5e4e637ddecb5a4f63db385510e3962cb0bb3dc 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <mach/board.h>
 #include <mach/at91_rtt.h>
+#include <mach/cpu.h>
 
 
 /*
index f59277bbedaa2923a7b4f35127d9fdf9b3b3b309..7a568beba3f00b95f483664b03d888fc76059877 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/plat-s3c/regs-rtc.h>
+#include <plat/regs-rtc.h>
 
 /* I have yet to find an S3C implementation with more than one
  * of these rtc blocks in */
index 66a9bb85bbe8698e2b7234b4d26f4b13ef3d52d0..d26a5f82aabaf8eb58c61eb39c678d0f890ed5d1 100644 (file)
 #include <mach/pxa-regs.h>
 #endif
 
-#define TIMER_FREQ             CLOCK_TICK_RATE
 #define RTC_DEF_DIVIDER                32768 - 1
 #define RTC_DEF_TRIM           0
 
 static unsigned long rtc_freq = 1024;
+static unsigned long timer_freq;
 static struct rtc_time rtc_alarm;
 static DEFINE_SPINLOCK(sa1100_rtc_lock);
 
@@ -157,7 +157,7 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
        rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
 
        if (rtc_timer1_count == 1)
-               rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
+               rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2)));
 
        return IRQ_HANDLED;
 }
@@ -166,7 +166,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data)
 {
        if (data & RTC_PF) {
                /* interpolate missed periods and set match for the next */
-               unsigned long period = TIMER_FREQ/rtc_freq;
+               unsigned long period = timer_freq / rtc_freq;
                unsigned long oscr = OSCR;
                unsigned long osmr1 = OSMR1;
                unsigned long missed = (oscr - osmr1)/period;
@@ -263,7 +263,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
                return 0;
        case RTC_PIE_ON:
                spin_lock_irq(&sa1100_rtc_lock);
-               OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
+               OSMR1 = timer_freq / rtc_freq + OSCR;
                OIER |= OIER_E1;
                rtc_timer1_count = 1;
                spin_unlock_irq(&sa1100_rtc_lock);
@@ -271,7 +271,7 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
        case RTC_IRQP_READ:
                return put_user(rtc_freq, (unsigned long *)arg);
        case RTC_IRQP_SET:
-               if (arg < 1 || arg > TIMER_FREQ)
+               if (arg < 1 || arg > timer_freq)
                        return -EINVAL;
                rtc_freq = arg;
                return 0;
@@ -352,6 +352,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
 
+       timer_freq = get_clock_tick_rate();
+
        /*
         * According to the manual we should be able to let RTTR be zero
         * and then a default diviser for a 32.768KHz clock is used.
index 3d442444c618ccb431d7e4d6b6e1b5bc4f16924b..28c90b89f2b464d48e9781e2cd904fdf8a6800f5 100644 (file)
@@ -188,11 +188,13 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
        config = kvm_vq_config(kdev->desc)+index;
 
        err = vmem_add_mapping(config->address,
-                              vring_size(config->num, PAGE_SIZE));
+                              vring_size(config->num,
+                                         KVM_S390_VIRTIO_RING_ALIGN));
        if (err)
                goto out;
 
-       vq = vring_new_virtqueue(config->num, vdev, (void *) config->address,
+       vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN,
+                                vdev, (void *) config->address,
                                 kvm_notify, callback);
        if (!vq) {
                err = -ENOMEM;
@@ -209,7 +211,8 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev,
        return vq;
 unmap:
        vmem_remove_mapping(config->address,
-                           vring_size(config->num, PAGE_SIZE));
+                           vring_size(config->num,
+                                      KVM_S390_VIRTIO_RING_ALIGN));
 out:
        return ERR_PTR(err);
 }
@@ -220,7 +223,8 @@ static void kvm_del_vq(struct virtqueue *vq)
 
        vring_del_virtqueue(vq);
        vmem_remove_mapping(config->address,
-                           vring_size(config->num, PAGE_SIZE));
+                           vring_size(config->num,
+                                      KVM_S390_VIRTIO_RING_ALIGN));
 }
 
 /*
@@ -295,13 +299,29 @@ static void scan_devices(void)
  */
 static void kvm_extint_handler(u16 code)
 {
-       void *data = (void *) *(long *) __LC_PFAULT_INTPARM;
-       u16 subcode = S390_lowcore.cpu_addr;
+       struct virtqueue *vq;
+       u16 subcode;
+       int config_changed;
 
+       subcode = S390_lowcore.cpu_addr;
        if ((subcode & 0xff00) != VIRTIO_SUBCODE_64)
                return;
 
-       vring_interrupt(0, data);
+       /* The LSB might be overloaded, we have to mask it */
+       vq = (struct virtqueue *) ((*(long *) __LC_PFAULT_INTPARM) & ~1UL);
+
+       /* We use the LSB of extparam, to decide, if this interrupt is a config
+        * change or a "standard" interrupt */
+       config_changed =  (*(int *)  __LC_EXT_PARAMS & 1);
+
+       if (config_changed) {
+               struct virtio_driver *drv;
+               drv = container_of(vq->vdev->dev.driver,
+                                  struct virtio_driver, driver);
+               if (drv->config_changed)
+                       drv->config_changed(vq->vdev);
+       } else
+               vring_interrupt(0, vq);
 }
 
 /*
index 2370fd82ebfe365fa477634d8c55d259dd39ab43..c24140aff8e7a3384ce68afe3d5f8bacc34db3ba 100644 (file)
@@ -578,6 +578,8 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
 {
        idescsi_scsi_t *scsi  = scsihost_to_idescsi(cmd->device->host);
        ide_drive_t    *drive = scsi->drive;
+       ide_hwif_t     *hwif;
+       ide_hwgroup_t  *hwgroup;
        int             busy;
        int             ret   = FAILED;
 
@@ -594,13 +596,16 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
                goto no_drive;
        }
 
-       /* First give it some more time, how much is "right" is hard to say :-( */
+       hwif = drive->hwif;
+       hwgroup = hwif->hwgroup;
 
-       busy = ide_wait_not_busy(HWIF(drive), 100);     /* FIXME - uses mdelay which causes latency? */
+       /* First give it some more time, how much is "right" is hard to say :-(
+          FIXME - uses mdelay which causes latency? */
+       busy = ide_wait_not_busy(hwif, 100);
        if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
                printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":"");
 
-       spin_lock_irq(&ide_lock);
+       spin_lock_irq(&hwgroup->lock);
 
        /* If there is no pc running we're done (our interrupt took care of it) */
        pc = drive->pc;
@@ -629,7 +634,7 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
        }
 
 ide_unlock:
-       spin_unlock_irq(&ide_lock);
+       spin_unlock_irq(&hwgroup->lock);
 no_drive:
        if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
                printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed");
@@ -642,6 +647,7 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
        struct request *req;
        idescsi_scsi_t *scsi  = scsihost_to_idescsi(cmd->device->host);
        ide_drive_t    *drive = scsi->drive;
+       ide_hwgroup_t  *hwgroup;
        int             ready = 0;
        int             ret   = SUCCESS;
 
@@ -658,14 +664,18 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
                return FAILED;
        }
 
+       hwgroup = drive->hwif->hwgroup;
+
        spin_lock_irq(cmd->device->host->host_lock);
-       spin_lock(&ide_lock);
+       spin_lock(&hwgroup->lock);
 
        pc = drive->pc;
+       if (pc)
+               req = pc->rq;
 
-       if (pc == NULL || (req = pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
+       if (pc == NULL || req != hwgroup->rq || hwgroup->handler == NULL) {
                printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
-               spin_unlock(&ide_lock);
+               spin_unlock(&hwgroup->lock);
                spin_unlock_irq(cmd->device->host->host_lock);
                return FAILED;
        }
@@ -685,10 +695,10 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
                        BUG();
        }
 
-       HWGROUP(drive)->rq = NULL;
-       HWGROUP(drive)->handler = NULL;
-       HWGROUP(drive)->busy = 1;               /* will set this to zero when ide reset finished */
-       spin_unlock(&ide_lock);
+       hwgroup->rq = NULL;
+       hwgroup->handler = NULL;
+       hwgroup->busy = 1; /* will set this to zero when ide reset finished */
+       spin_unlock(&hwgroup->lock);
 
        ide_do_reset(drive);
 
index 579d63a81aa21d27e783dd28eb776723e1b0b111..b695ab3142d83e2249586623344d4a49ca0c84a9 100644 (file)
@@ -447,7 +447,7 @@ config SERIAL_CLPS711X_CONSOLE
 
 config SERIAL_SAMSUNG
        tristate "Samsung SoC serial support"
-       depends on ARM && PLAT_S3C24XX
+       depends on ARM && PLAT_S3C
        select SERIAL_CORE
        help
          Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -455,6 +455,16 @@ config SERIAL_SAMSUNG
          provide all of these ports, depending on how the serial port
          pins are configured.
 
+config SERIAL_SAMSUNG_UARTS
+       int
+       depends on SERIAL_SAMSUNG
+       default 2 if ARCH_S3C2400
+       default 4 if ARCH_S3C64XX || CPU_S3C2443
+       default 3
+       help
+         Select the number of available UART ports for the Samsung S3C
+         serial driver
+       
 config SERIAL_SAMSUNG_DEBUG
        bool "Samsung SoC serial debug"
        depends on SERIAL_SAMSUNG && DEBUG_LL
@@ -508,7 +518,20 @@ config SERIAL_S3C2440
        help
          Serial port support for the Samsung S3C2440 and S3C2442 SoC
 
+config SERIAL_S3C24A0
+       tristate "Samsung S3C24A0 Serial port support"
+       depends on SERIAL_SAMSUNG && CPU_S3C24A0
+       default y if CPU_S3C24A0
+       help
+         Serial port support for the Samsung S3C24A0 SoC
 
+config SERIAL_S3C6400
+       tristate "Samsung S3C6400/S3C6410 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S3C600 || CPU_S3C6410)
+       default y
+       help
+         Serial port support for the Samsung S3C6400 and S3C6410
+         SoCs
 
 config SERIAL_DZ
        bool "DECstation DZ serial driver"
index 0c17c8ddb19d314be93614760224aed72e838e49..dfe775ac45b227a6badb58c19b1a921d7003f85a 100644 (file)
@@ -41,6 +41,8 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
 obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
 obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
 obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
+obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
+obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
index 71562689116ff4e45f326dbfc6e8cbb10732ad31..e3a5ad5ef1d6003a70ac2c98e87b325d73b1ab79 100644 (file)
@@ -692,7 +692,7 @@ static int pl010_probe(struct amba_device *dev, void *id)
                goto free;
        }
 
-       uap->clk = clk_get(&dev->dev, "UARTCLK");
+       uap->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(uap->clk)) {
                ret = PTR_ERR(uap->clk);
                goto unmap;
index b7180046f8dba082f02767e07775fae72aafc53d..8b2b9700f3e4cecb108b5da816cb777c3424ba6c 100644 (file)
@@ -756,7 +756,7 @@ static int pl011_probe(struct amba_device *dev, void *id)
                goto free;
        }
 
-       uap->clk = clk_get(&dev->dev, "UARTCLK");
+       uap->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(uap->clk)) {
                ret = PTR_ERR(uap->clk);
                goto unmap;
index 3f90f1bbbbcddb728cc026fef1a4a8824995230e..a50954612b60145e7f9eb6acc12d9f05fb8b05d8 100644 (file)
@@ -66,7 +66,7 @@
 #define ONEMS 0xb0 /* One Millisecond register */
 #define UTS   0xb4 /* UART Test Register */
 #endif
-#ifdef CONFIG_ARCH_IMX
+#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
 #define BIPR1 0xb0 /* Incremental Preset Register 1 */
 #define BIPR2 0xb4 /* Incremental Preset Register 2 */
 #define BIPR3 0xb8 /* Incremental Preset Register 3 */
@@ -96,7 +96,7 @@
 #define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
 #define  UCR1_SNDBRK     (1<<4)         /* Send break */
 #define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#ifdef CONFIG_ARCH_IMX
+#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
 #define  UCR1_UARTCLKEN  (1<<2)         /* UART clock enabled */
 #endif
 #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
 #define MAX_INTERNAL_IRQ       IMX_IRQS
 #endif
 
-#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+#ifdef CONFIG_ARCH_MXC
 #define SERIAL_IMX_MAJOR        207
 #define MINOR_START            16
 #define DEV_NAME               "ttymxc"
-#define MAX_INTERNAL_IRQ       MXC_MAX_INT_LINES
+#define MAX_INTERNAL_IRQ       MXC_INTERNAL_IRQS
 #endif
 
 /*
index abc00be55433f428bba85a73bdb0e010d653d123..f6e3b86bb0be7cb26dd1de6ef0a65b60cf805438 100644 (file)
@@ -48,6 +48,7 @@
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <mach/pxa-regs.h>
+#include <mach/regs-uart.h>
 
 
 struct uart_pxa_port {
@@ -766,7 +767,7 @@ static int serial_pxa_probe(struct platform_device *dev)
        if (!sport)
                return -ENOMEM;
 
-       sport->clk = clk_get(&dev->dev, "UARTCLK");
+       sport->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(sport->clk)) {
                ret = PTR_ERR(sport->clk);
                goto err_free;
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
new file mode 100644 (file)
index 0000000..ebf2fd3
--- /dev/null
@@ -0,0 +1,118 @@
+/* linux/drivers/serial/s3c24a0.c
+ *
+ * Driver for Samsung S3C24A0 SoC onboard UARTs.
+ *
+ * Based on drivers/serial/s3c2410.c
+ *
+ * Author: Sandeep Patil <sandeep.patil@azingo.com>
+ *
+ * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can 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/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c24a0_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk") == 0)
+               ucon |= S3C2410_UCON_UCLK;
+       else
+               ucon &= ~S3C2410_UCON_UCLK;
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+static int s3c24a0_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+       clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+       return 0;
+}
+
+static int s3c24a0_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       wr_regl(port, S3C2410_UCON,  cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c24a0_uart_inf = {
+       .name           = "Samsung S3C24A0 UART",
+       .type           = PORT_S3C2410,
+       .fifosize       = 16,
+       .rx_fifomask    = S3C24A0_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C24A0_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C24A0_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C24A0_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C24A0_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C24A0_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c24a0_serial_getsource,
+       .set_clksrc     = s3c24a0_serial_setsource,
+       .reset_port     = s3c24a0_serial_resetport,
+};
+
+static int s3c24a0_serial_probe(struct platform_device *dev)
+{
+       return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
+}
+
+static struct platform_driver s3c24a0_serial_drv = {
+       .probe          = s3c24a0_serial_probe,
+       .remove         = s3c24xx_serial_remove,
+       .driver         = {
+               .name   = "s3c24a0-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf);
+
+static int __init s3c24a0_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf);
+}
+
+static void __exit s3c24a0_serial_exit(void)
+{
+       platform_driver_unregister(&s3c24a0_serial_drv);
+}
+
+module_init(s3c24a0_serial_init);
+module_exit(s3c24a0_serial_exit);
+
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c
new file mode 100644 (file)
index 0000000..06936d1
--- /dev/null
@@ -0,0 +1,151 @@
+/* linux/drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
+ *
+ * Copyright 2008 Openmoko,  Inc.
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can 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/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+
+#include "samsung.h"
+
+static int s3c6400_serial_setsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       if (strcmp(clk->name, "uclk0") == 0) {
+               ucon &= ~S3C6400_UCON_CLKMASK;
+               ucon |= S3C6400_UCON_UCLK0;
+       } else if (strcmp(clk->name, "uclk1") == 0)
+               ucon |= S3C6400_UCON_UCLK1;
+       else if (strcmp(clk->name, "pclk") == 0) {
+               /* See notes about transitioning from UCLK to PCLK */
+               ucon &= ~S3C6400_UCON_UCLK0;
+       } else {
+               printk(KERN_ERR "unknown clock source %s\n", clk->name);
+               return -EINVAL;
+       }
+
+       wr_regl(port, S3C2410_UCON, ucon);
+       return 0;
+}
+
+
+static int s3c6400_serial_getsource(struct uart_port *port,
+                                   struct s3c24xx_uart_clksrc *clk)
+{
+       u32 ucon = rd_regl(port, S3C2410_UCON);
+
+       clk->divisor = 1;
+
+       switch (ucon & S3C6400_UCON_CLKMASK) {
+       case S3C6400_UCON_UCLK0:
+               clk->name = "uclk0";
+               break;
+
+       case S3C6400_UCON_UCLK1:
+               clk->name = "uclk1";
+               break;
+
+       case S3C6400_UCON_PCLK:
+       case S3C6400_UCON_PCLK2:
+               clk->name = "pclk";
+               break;
+       }
+
+       return 0;
+}
+
+static int s3c6400_serial_resetport(struct uart_port *port,
+                                   struct s3c2410_uartcfg *cfg)
+{
+       unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+       dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+           port, port->mapbase, cfg);
+
+       /* ensure we don't change the clock settings... */
+
+       ucon &= S3C6400_UCON_CLKMASK;
+
+       wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
+       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+       /* reset both fifos */
+
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+       wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+       return 0;
+}
+
+static struct s3c24xx_uart_info s3c6400_uart_inf = {
+       .name           = "Samsung S3C6400 UART",
+       .type           = PORT_S3C6400,
+       .fifosize       = 64,
+       .rx_fifomask    = S3C2440_UFSTAT_RXMASK,
+       .rx_fifoshift   = S3C2440_UFSTAT_RXSHIFT,
+       .rx_fifofull    = S3C2440_UFSTAT_RXFULL,
+       .tx_fifofull    = S3C2440_UFSTAT_TXFULL,
+       .tx_fifomask    = S3C2440_UFSTAT_TXMASK,
+       .tx_fifoshift   = S3C2440_UFSTAT_TXSHIFT,
+       .get_clksrc     = s3c6400_serial_getsource,
+       .set_clksrc     = s3c6400_serial_setsource,
+       .reset_port     = s3c6400_serial_resetport,
+};
+
+/* device management */
+
+static int s3c6400_serial_probe(struct platform_device *dev)
+{
+       dbg("s3c6400_serial_probe: dev=%p\n", dev);
+       return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
+}
+
+static struct platform_driver s3c6400_serial_drv = {
+       .probe          = s3c6400_serial_probe,
+       .remove         = s3c24xx_serial_remove,
+       .driver         = {
+               .name   = "s3c6400-uart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+s3c24xx_console_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
+
+static int __init s3c6400_serial_init(void)
+{
+       return s3c24xx_serial_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
+}
+
+static void __exit s3c6400_serial_exit(void)
+{
+       platform_driver_unregister(&s3c6400_serial_drv);
+}
+
+module_init(s3c6400_serial_init);
+module_exit(s3c6400_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c6400-uart");
index 1e219d3d0352b29499c60086000b149ad8a902af..41ac94872b8d952a6b3250cacf3f12432e5ed107 100644 (file)
 #include <linux/serial.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 
 #include <asm/irq.h>
 
 #include <mach/hardware.h>
+#include <mach/map.h>
 
 #include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
 
 #include "samsung.h"
 
 #define S3C24XX_SERIAL_MAJOR   204
 #define S3C24XX_SERIAL_MINOR   64
 
-/* we can support 3 uarts, but not always use them */
-
-#ifdef CONFIG_CPU_S3C2400
-#define NR_PORTS (2)
-#else
-#define NR_PORTS (3)
-#endif
-
-/* port irq numbers */
-
-#define TX_IRQ(port) ((port)->irq + 1)
-#define RX_IRQ(port) ((port)->irq)
-
 /* macros to change one thing to another */
 
 #define tx_enabled(port) ((port)->unused[0])
@@ -136,8 +124,10 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
 
 static void s3c24xx_serial_stop_tx(struct uart_port *port)
 {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
        if (tx_enabled(port)) {
-               disable_irq(TX_IRQ(port));
+               disable_irq(ourport->tx_irq);
                tx_enabled(port) = 0;
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_enable(port);
@@ -146,11 +136,13 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
 
 static void s3c24xx_serial_start_tx(struct uart_port *port)
 {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
        if (!tx_enabled(port)) {
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_disable(port);
 
-               enable_irq(TX_IRQ(port));
+               enable_irq(ourport->tx_irq);
                tx_enabled(port) = 1;
        }
 }
@@ -158,9 +150,11 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
 
 static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+
        if (rx_enabled(port)) {
                dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
-               disable_irq(RX_IRQ(port));
+               disable_irq(ourport->rx_irq);
                rx_enabled(port) = 0;
        }
 }
@@ -384,13 +378,13 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
        if (ourport->tx_claimed) {
-               free_irq(TX_IRQ(port), ourport);
+               free_irq(ourport->tx_irq, ourport);
                tx_enabled(port) = 0;
                ourport->tx_claimed = 0;
        }
 
        if (ourport->rx_claimed) {
-               free_irq(RX_IRQ(port), ourport);
+               free_irq(ourport->rx_irq, ourport);
                ourport->rx_claimed = 0;
                rx_enabled(port) = 0;
        }
@@ -407,12 +401,11 @@ static int s3c24xx_serial_startup(struct uart_port *port)
 
        rx_enabled(port) = 1;
 
-       ret = request_irq(RX_IRQ(port),
-                         s3c24xx_serial_rx_chars, 0,
+       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
                          s3c24xx_serial_portname(port), ourport);
 
        if (ret != 0) {
-               printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
+               printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
                return ret;
        }
 
@@ -422,12 +415,11 @@ static int s3c24xx_serial_startup(struct uart_port *port)
 
        tx_enabled(port) = 1;
 
-       ret = request_irq(TX_IRQ(port),
-                         s3c24xx_serial_tx_chars, 0,
+       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
                          s3c24xx_serial_portname(port), ourport);
 
        if (ret) {
-               printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
+               printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
                goto err;
        }
 
@@ -452,6 +444,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
+       ourport->pm_level = level;
+
        switch (level) {
        case 3:
                if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
@@ -661,6 +655,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 
                ourport->clksrc = clksrc;
                ourport->baudclk = clk;
+               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
        }
 
        switch (termios->c_cflag & CSIZE) {
@@ -752,6 +747,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
                return "S3C2440";
        case PORT_S3C2412:
                return "S3C2412";
+       case PORT_S3C6400:
+               return "S3C6400/10";
        default:
                return NULL;
        }
@@ -827,14 +824,14 @@ static struct uart_ops s3c24xx_serial_ops = {
 static struct uart_driver s3c24xx_uart_drv = {
        .owner          = THIS_MODULE,
        .dev_name       = "s3c2410_serial",
-       .nr             = 3,
+       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
        .cons           = S3C24XX_SERIAL_CONSOLE,
        .driver_name    = S3C24XX_SERIAL_NAME,
        .major          = S3C24XX_SERIAL_MAJOR,
        .minor          = S3C24XX_SERIAL_MINOR,
 };
 
-static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
        [0] = {
                .port = {
                        .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
@@ -859,7 +856,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
                        .line           = 1,
                }
        },
-#if NR_PORTS > 2
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
 
        [2] = {
                .port = {
@@ -872,6 +869,20 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
                        .flags          = UPF_BOOT_AUTOCONF,
                        .line           = 2,
                }
+       },
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+       [3] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX3,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 3,
+               }
        }
 #endif
 };
@@ -890,6 +901,89 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
        return (info->reset_port)(port, cfg);
 }
 
+
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+                                            unsigned long val, void *data)
+{
+       struct s3c24xx_uart_port *port;
+       struct uart_port *uport;
+
+       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+       uport = &port->port;
+
+       /* check to see if port is enabled */
+
+       if (port->pm_level != 0)
+               return 0;
+
+       /* try and work out if the baudrate is changing, we can detect
+        * a change in rate, but we do not have support for detecting
+        * a disturbance in the clock-rate over the change.
+        */
+
+       if (IS_ERR(port->clk))
+               goto exit;
+
+       if (port->baudclk_rate == clk_get_rate(port->clk))
+               goto exit;
+
+       if (val == CPUFREQ_PRECHANGE) {
+               /* we should really shut the port down whilst the
+                * frequency change is in progress. */
+
+       } else if (val == CPUFREQ_POSTCHANGE) {
+               struct ktermios *termios;
+               struct tty_struct *tty;
+
+               if (uport->info == NULL)
+                       goto exit;
+
+               tty = uport->info->port.tty;
+
+               if (tty == NULL)
+                       goto exit;
+
+               termios = tty->termios;
+
+               if (termios == NULL) {
+                       printk(KERN_WARNING "%s: no termios?\n", __func__);
+                       goto exit;
+               }
+
+               s3c24xx_serial_set_termios(uport, termios, NULL);
+       }
+
+ exit:
+       return 0;
+}
+
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+
+       return cpufreq_register_notifier(&port->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+       cpufreq_unregister_notifier(&port->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+       return 0;
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+}
+#endif
+
 /* s3c24xx_serial_init_port
  *
  * initialise a single serial port from the platform device given
@@ -914,8 +1008,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        if (port->mapbase != 0)
                return 0;
 
-       if (cfg->hwport > 3)
-               return -EINVAL;
+       if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
+               printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
+                      cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
+               return -ERANGE;
+       }
 
        /* setup info for port */
        port->dev       = &platdev->dev;
@@ -943,18 +1040,26 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 
        dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
 
-       port->mapbase   = res->start;
-       port->membase   = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
+       port->mapbase = res->start;
+       port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000);
        ret = platform_get_irq(platdev, 0);
        if (ret < 0)
                port->irq = 0;
-       else
+       else {
                port->irq = ret;
+               ourport->rx_irq = ret;
+               ourport->tx_irq = ret + 1;
+       }
+       
+       ret = platform_get_irq(platdev, 1);
+       if (ret > 0)
+               ourport->tx_irq = ret;
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
 
-       dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",
-           port->mapbase, port->membase, port->irq, port->uartclk);
+       dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
+           port->mapbase, port->membase, port->irq,
+           ourport->rx_irq, ourport->tx_irq, port->uartclk);
 
        /* reset the fifos (and setup the uart) */
        s3c24xx_serial_resetport(port, cfg);
@@ -1002,6 +1107,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
        if (ret < 0)
                printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
 
+       ret = s3c24xx_serial_cpufreq_register(ourport);
+       if (ret < 0)
+               dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+
        return 0;
 
  probe_err:
@@ -1015,6 +1124,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
        struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
 
        if (port) {
+               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
                device_remove_file(&dev->dev, &dev_attr_clock_source);
                uart_remove_one_port(&s3c24xx_uart_drv, port);
        }
@@ -1219,7 +1329,7 @@ static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
 
        platdev_ptr = s3c24xx_uart_devs;
 
-       for (i = 0; i < NR_PORTS; i++, ptr++, platdev_ptr++) {
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
                s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
        }
 
@@ -1240,7 +1350,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
 
        /* is this a valid port */
 
-       if (co->index == -1 || co->index >= NR_PORTS)
+       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
                co->index = 0;
 
        port = &s3c24xx_serial_ports[co->index].port;
index 5c92ebbe7d9e6f23918d332f7b20c66c8e91a855..571d6b90d206c4b05bba7ecfc0c2a94bad029aef 100644 (file)
@@ -33,12 +33,21 @@ struct s3c24xx_uart_info {
 struct s3c24xx_uart_port {
        unsigned char                   rx_claimed;
        unsigned char                   tx_claimed;
+       unsigned int                    pm_level;
+       unsigned long                   baudclk_rate;
+
+       unsigned int                    rx_irq;
+       unsigned int                    tx_irq;
 
        struct s3c24xx_uart_info        *info;
        struct s3c24xx_uart_clksrc      *clksrc;
        struct clk                      *clk;
        struct clk                      *baudclk;
        struct uart_port                port;
+
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block           freq_transition;
+#endif
 };
 
 /* conversion functions */
index 61dc8b3daa26ce2c5159febbc05d71f89746ce54..a7bf024a8286085484978ad303213b5e815c6d0d 100644 (file)
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/irq.h>
+#include <mach/hardware.h>
 
 #define DEV_MAJOR      204
 #define DEV_MINOR      16
index cf12f2d84be2c2547fdbe88caf81ea25d733f867..6104f461a3cdf564e6476c8e49a6dd69a851052d 100644 (file)
@@ -32,8 +32,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
-#include <asm/dma.h>
 
+#include <mach/dma.h>
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
 #include <mach/regs-ssp.h>
index c252cbac00f1d14ef273f53dea2ca7f39edd38b5..256d18395a23bdf971589793b0e205a6da839039 100644 (file)
@@ -28,7 +28,7 @@
 #include <mach/hardware.h>
 
 #include <mach/regs-gpio.h>
-#include <asm/plat-s3c24xx/regs-spi.h>
+#include <plat/regs-spi.h>
 #include <mach/spi.h>
 
 struct s3c24xx_spi {
index 2dbc0db0b46c66c5e455b33db339ae452cc25e16..8c5026be79d49af6253d1b45f638badd74c596b0 100644 (file)
@@ -2145,7 +2145,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
        if (irq < 0)
                return -ENODEV;
 
-       dev->clk = clk_get(&pdev->dev, "UDCCLK");
+       dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                retval = PTR_ERR(dev->clk);
                goto err_clk;
index caa37c95802c925ad9f9caff5f71071e69e22383..944e4ff641dfc68b814501dc5a92065593f71198 100644 (file)
@@ -2226,7 +2226,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
        udc->dev = &pdev->dev;
        udc->mach = pdev->dev.platform_data;
 
-       udc->clk = clk_get(&pdev->dev, "UDCCLK");
+       udc->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(udc->clk)) {
                retval = PTR_ERR(udc->clk);
                goto err_clk;
index 00ba06b4475204012498cfdd5028ce03556be948..8d8d651659836d3a9cc5fbef228effc78e994179 100644 (file)
@@ -53,8 +53,8 @@
 #include <mach/hardware.h>
 #include <mach/regs-gpio.h>
 
-#include <asm/plat-s3c24xx/regs-udc.h>
-#include <asm/plat-s3c24xx/udc.h>
+#include <plat/regs-udc.h>
+#include <plat/udc.h>
 
 
 #include "s3c2410_udc.h"
index 5416cf9690056a3f72c526255914fe992f00c0f0..9d487908012e56fb515d82576ccdbd5db71fa480 100644 (file)
@@ -33,8 +33,9 @@
 /*
  * Implement Orion USB controller specification guidelines
  */
-static void orion_usb_setup(struct usb_hcd *hcd)
+static void orion_usb_phy_v1_setup(struct usb_hcd *hcd)
 {
+       /* The below GLs are according to the Orion Errata document */
        /*
         * Clear interrupt cause and mask
         */
@@ -258,9 +259,19 @@ static int __init ehci_orion_drv_probe(struct platform_device *pdev)
                ehci_orion_conf_mbus_windows(hcd, pd->dram);
 
        /*
-        * setup Orion USB controller
+        * setup Orion USB controller.
         */
-       orion_usb_setup(hcd);
+       switch (pd->phy_version) {
+       case EHCI_PHY_NA:       /* dont change USB phy settings */
+               break;
+       case EHCI_PHY_ORION:
+               orion_usb_phy_v1_setup(hcd);
+               break;
+       case EHCI_PHY_DD:
+       case EHCI_PHY_KW:
+       default:
+               printk(KERN_WARNING "Orion ehci -USB phy version isn't supported.\n");
+       }
 
        err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
        if (err)
index 91697bdb399f625eba508a0ea80da21099a1556b..4bbddb73abd99e0277cbf5841529b1cedd406041 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 #include <asm/io.h>
@@ -25,7 +26,6 @@
 
 #include <mach/mux.h>
 #include <mach/irqs.h>
-#include <mach/gpio.h>
 #include <mach/fpga.h>
 #include <mach/usb.h>
 
@@ -254,8 +254,8 @@ static int ohci_omap_init(struct usb_hcd *hcd)
 
                        /* gpio9 for overcurrent detction */
                        omap_cfg_reg(W8_1610_GPIO9);
-                       omap_request_gpio(9);
-                       omap_set_gpio_direction(9, 1 /* IN */);
+                       gpio_request(9, "OHCI overcurrent");
+                       gpio_direction_input(9);
 
                        /* for paranoia's sake:  disable USB.PUEN */
                        omap_cfg_reg(W4_USB_HIGHZ);
@@ -407,7 +407,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
                put_device(ohci->transceiver->dev);
        }
        if (machine_is_omap_osk())
-               omap_free_gpio(9);
+               gpio_free(9);
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
index e294d430733b1b5e92a05cdc6cb837b41b067f8b..e44dc2cbca24006e1b81d57cf589213ee823295c 100644 (file)
@@ -296,7 +296,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
                return -ENXIO;
        }
 
-       usb_clk = clk_get(&pdev->dev, "USBCLK");
+       usb_clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(usb_clk))
                return PTR_ERR(usb_clk);
 
index d0c821992a99ca0dcba772eba1ff6aaf5c63f3ad..6372f8b17b450d31172b1c20fa5cbcf4a58fce85 100644 (file)
@@ -362,7 +362,7 @@ endchoice
 
 config FB_ACORN
        bool "Acorn VIDC support"
-       depends on (FB = y) && ARM && (ARCH_ACORN || ARCH_CLPS7500)
+       depends on (FB = y) && ARM && ARCH_ACORN
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
@@ -1817,6 +1817,11 @@ config FB_PXA
 
          If unsure, say N.
 
+config FB_PXA_OVERLAY
+       bool "Support PXA27x/PXA3xx Overlay(s) as framebuffer"
+       default n
+       depends on FB_PXA && (PXA27x || PXA3xx)
+
 config FB_PXA_SMARTPANEL
        bool "PXA Smartpanel LCD support"
        default n
index a7a1c891bfa2e0646a1e73757f47de70e017b77a..2ac52fd8cc11f67595a6368ea879bf40fde497fa 100644 (file)
@@ -343,14 +343,14 @@ static int clcdfb_register(struct clcd_fb *fb)
 {
        int ret;
 
-       fb->clk = clk_get(&fb->dev->dev, "CLCDCLK");
+       fb->clk = clk_get(&fb->dev->dev, NULL);
        if (IS_ERR(fb->clk)) {
                ret = PTR_ERR(fb->clk);
                goto out;
        }
 
        fb->fb.fix.mmio_start   = fb->dev->res.start;
-       fb->fb.fix.mmio_len     = SZ_4K;
+       fb->fb.fix.mmio_len     = 4096;
 
        fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
        if (!fb->regs) {
index 448d209a0bf2109fa14af7d3c6a3b00e08c7df1b..e6210725b9ab59615958db9796b8b301297ce1bd 100644 (file)
@@ -112,6 +112,23 @@ static int                 vga_video_font_height;
 static int             vga_scan_lines          __read_mostly;
 static unsigned int    vga_rolled_over;
 
+int vgacon_text_mode_force = 0;
+
+bool vgacon_text_force(void)
+{
+       return vgacon_text_mode_force ? true : false;
+}
+EXPORT_SYMBOL(vgacon_text_force);
+
+static int __init text_mode(char *str)
+{
+       vgacon_text_mode_force = 1;
+       return 1;
+}
+
+/* force text mode - used by kernel modesetting */
+__setup("nomodeset", text_mode);
+
 static int __init no_scroll(char *str)
 {
        /*
index 41d62632dcdb06bfc4b62f3266bb0ad6e8bda7ca..39d5d643a50b9397d67a26f37d3f0572c5561b4c 100644 (file)
@@ -1513,7 +1513,7 @@ static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
 
        iop = ioremap(0x3000000, 0x5000);
        if (iop == NULL) {
-               prom_printf("iga5000: cannot map I/O\n");
+               printk(KERN_ERR "iga5000: cannot map I/O\n");
                return -ENOMEM;
        }
 
index ccd986140c95ca71c56778a26819e4985eb89da1..d58c68cd456eda0c9aea90c5f566cfab06fc4cdf 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/video/imxfb.c
- *
  *  Freescale i.MX Frame Buffer device driver
  *
  *  Copyright (C) 2004 Sascha Hauer, Pengutronix
@@ -16,7 +14,6 @@
  *     linux-arm-kernel@lists.arm.linux.org.uk
  */
 
-//#define DEBUG 1
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -32,9 +29,8 @@
 #include <linux/cpufreq.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/io.h>
 
-#include <mach/hardware.h>
-#include <asm/io.h>
 #include <mach/imxfb.h>
 
 /*
  */
 #define DEBUG_VAR 1
 
-#include "imxfb.h"
+#define DRIVER_NAME "imx-fb"
+
+#define LCDC_SSA       0x00
+
+#define LCDC_SIZE      0x04
+#define SIZE_XMAX(x)   ((((x) >> 4) & 0x3f) << 20)
+#define SIZE_YMAX(y)   ((y) & 0x1ff)
+
+#define LCDC_VPW       0x08
+#define VPW_VPW(x)     ((x) & 0x3ff)
+
+#define LCDC_CPOS      0x0C
+#define CPOS_CC1       (1<<31)
+#define CPOS_CC0       (1<<30)
+#define CPOS_OP                (1<<28)
+#define CPOS_CXP(x)    (((x) & 3ff) << 16)
+#define CPOS_CYP(y)    ((y) & 0x1ff)
+
+#define LCDC_LCWHB     0x10
+#define LCWHB_BK_EN    (1<<31)
+#define LCWHB_CW(w)    (((w) & 0x1f) << 24)
+#define LCWHB_CH(h)    (((h) & 0x1f) << 16)
+#define LCWHB_BD(x)    ((x) & 0xff)
+
+#define LCDC_LCHCC     0x14
+#define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11)
+#define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5)
+#define LCHCC_CUR_COL_B(b) ((b) & 0x1f)
+
+#define LCDC_PCR       0x18
+
+#define LCDC_HCR       0x1C
+#define HCR_H_WIDTH(x) (((x) & 0x3f) << 26)
+#define HCR_H_WAIT_1(x)        (((x) & 0xff) << 8)
+#define HCR_H_WAIT_2(x)        ((x) & 0xff)
+
+#define LCDC_VCR       0x20
+#define VCR_V_WIDTH(x) (((x) & 0x3f) << 26)
+#define VCR_V_WAIT_1(x)        (((x) & 0xff) << 8)
+#define VCR_V_WAIT_2(x)        ((x) & 0xff)
+
+#define LCDC_POS       0x24
+#define POS_POS(x)     ((x) & 1f)
+
+#define LCDC_LSCR1     0x28
+/* bit fields in imxfb.h */
+
+#define LCDC_PWMR      0x2C
+/* bit fields in imxfb.h */
+
+#define LCDC_DMACR     0x30
+/* bit fields in imxfb.h */
+
+#define LCDC_RMCR      0x34
+#define RMCR_LCDC_EN   (1<<1)
+#define RMCR_SELF_REF  (1<<0)
+
+#define LCDC_LCDICR    0x38
+#define LCDICR_INT_SYN (1<<2)
+#define LCDICR_INT_CON (1)
+
+#define LCDC_LCDISR    0x40
+#define LCDISR_UDR_ERR (1<<3)
+#define LCDISR_ERR_RES (1<<2)
+#define LCDISR_EOF     (1<<1)
+#define LCDISR_BOF     (1<<0)
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+       struct fb_bitfield      red;
+       struct fb_bitfield      green;
+       struct fb_bitfield      blue;
+       struct fb_bitfield      transp;
+};
+
+struct imxfb_info {
+       struct platform_device  *pdev;
+       void __iomem            *regs;
 
-static struct imxfb_rgb def_rgb_16 = {
-       .red    = { .offset = 8,  .length = 4, },
-       .green  = { .offset = 4,  .length = 4, },
-       .blue   = { .offset = 0,  .length = 4, },
-       .transp = { .offset = 0,  .length = 0, },
+       u_int                   max_bpp;
+       u_int                   max_xres;
+       u_int                   max_yres;
+
+       /*
+        * These are the addresses we mapped
+        * the framebuffer memory region to.
+        */
+       dma_addr_t              map_dma;
+       u_char                  *map_cpu;
+       u_int                   map_size;
+
+       u_char                  *screen_cpu;
+       dma_addr_t              screen_dma;
+       u_int                   palette_size;
+
+       dma_addr_t              dbar1;
+       dma_addr_t              dbar2;
+
+       u_int                   pcr;
+       u_int                   pwmr;
+       u_int                   lscr1;
+       u_int                   dmacr;
+       u_int                   cmap_inverse:1,
+                               cmap_static:1,
+                               unused:30;
+
+       void (*lcd_power)(int);
+       void (*backlight_power)(int);
+};
+
+#define IMX_NAME       "IMX"
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES       64
+#define MIN_YRES       64
+
+static struct imxfb_rgb def_rgb_16_tft = {
+       .red    = {.offset = 11, .length = 5,},
+       .green  = {.offset = 5, .length = 6,},
+       .blue   = {.offset = 0, .length = 5,},
+       .transp = {.offset = 0, .length = 0,},
+};
+
+static struct imxfb_rgb def_rgb_16_stn = {
+       .red    = {.offset = 8, .length = 4,},
+       .green  = {.offset = 4, .length = 4,},
+       .blue   = {.offset = 0, .length = 4,},
+       .transp = {.offset = 0, .length = 0,},
 };
 
 static struct imxfb_rgb def_rgb_8 = {
-       .red    = { .offset = 0,  .length = 8, },
-       .green  = { .offset = 0,  .length = 8, },
-       .blue   = { .offset = 0,  .length = 8, },
-       .transp = { .offset = 0,  .length = 0, },
+       .red    = {.offset = 0, .length = 8,},
+       .green  = {.offset = 0, .length = 8,},
+       .blue   = {.offset = 0, .length = 8,},
+       .transp = {.offset = 0, .length = 0,},
 };
 
-static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int imxfb_activate_var(struct fb_var_screeninfo *var,
+               struct fb_info *info);
 
 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
 {
@@ -67,10 +190,8 @@ static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
        return chan << bf->offset;
 }
 
-#define LCDC_PALETTE(x) __REG2(IMX_LCDC_BASE+0x800, (x)<<2)
-static int
-imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
-                      u_int trans, struct fb_info *info)
+static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+               u_int trans, struct fb_info *info)
 {
        struct imxfb_info *fbi = info->par;
        u_int val, ret = 1;
@@ -81,14 +202,13 @@ imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
                      (CNVT_TOHW(green,4) << 4) |
                      CNVT_TOHW(blue,  4);
 
-               LCDC_PALETTE(regno) = val;
+               writel(val, fbi->regs + 0x800 + (regno << 2));
                ret = 0;
        }
        return ret;
 }
 
-static int
-imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                   u_int trans, struct fb_info *info)
 {
        struct imxfb_info *fbi = info->par;
@@ -148,11 +268,10 @@ imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
  *    bitfields, horizontal timing, vertical timing.
  */
-static int
-imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct imxfb_info *fbi = info->par;
-       int rgbidx;
+       struct imxfb_rgb *rgb;
 
        if (var->xres < MIN_XRES)
                var->xres = MIN_XRES;
@@ -168,23 +287,25 @@ imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel);
        switch (var->bits_per_pixel) {
        case 16:
-               rgbidx = RGB_16;
+       default:
+               if (readl(fbi->regs + LCDC_PCR) & PCR_TFT)
+                       rgb = &def_rgb_16_tft;
+               else
+                       rgb = &def_rgb_16_stn;
                break;
        case 8:
-               rgbidx = RGB_8;
+               rgb = &def_rgb_8;
                break;
-       default:
-               rgbidx = RGB_16;
        }
 
        /*
         * Copy the RGB parameters for this display
         * from the machine specific parameters.
         */
-       var->red    = fbi->rgb[rgbidx]->red;
-       var->green  = fbi->rgb[rgbidx]->green;
-       var->blue   = fbi->rgb[rgbidx]->blue;
-       var->transp = fbi->rgb[rgbidx]->transp;
+       var->red    = rgb->red;
+       var->green  = rgb->green;
+       var->blue   = rgb->blue;
+       var->transp = rgb->transp;
 
        pr_debug("RGBT length = %d:%d:%d:%d\n",
                var->red.length, var->green.length, var->blue.length,
@@ -221,8 +342,7 @@ static int imxfb_set_par(struct fb_info *info)
                info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
        }
 
-       info->fix.line_length = var->xres_virtual *
-                                 var->bits_per_pixel / 8;
+       info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
        fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
 
        imxfb_activate_var(var, info);
@@ -235,22 +355,27 @@ static void imxfb_enable_controller(struct imxfb_info *fbi)
        pr_debug("Enabling LCD controller\n");
 
        /* initialize LCDC */
-       LCDC_RMCR &= ~RMCR_LCDC_EN;             /* just to be safe... */
+       writel(readl(fbi->regs + LCDC_RMCR) & ~RMCR_LCDC_EN,
+               fbi->regs + LCDC_RMCR); /* just to be safe... */
+
+       writel(fbi->screen_dma, fbi->regs + LCDC_SSA);
 
-       LCDC_SSA        = fbi->screen_dma;
        /* physical screen start address            */
-       LCDC_VPW        = VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4);
+       writel(VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4),
+               fbi->regs + LCDC_VPW);
 
-       LCDC_POS        = 0x00000000;   /* panning offset 0 (0 pixel offset)        */
+       /* panning offset 0 (0 pixel offset)        */
+       writel(0x00000000, fbi->regs + LCDC_POS);
 
        /* disable hardware cursor */
-       LCDC_CPOS       &= ~(CPOS_CC0 | CPOS_CC1);
+       writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1),
+               fbi->regs + LCDC_CPOS);
 
-       LCDC_RMCR = RMCR_LCDC_EN;
+       writel(RMCR_LCDC_EN, fbi->regs + LCDC_RMCR);
 
-       if(fbi->backlight_power)
+       if (fbi->backlight_power)
                fbi->backlight_power(1);
-       if(fbi->lcd_power)
+       if (fbi->lcd_power)
                fbi->lcd_power(1);
 }
 
@@ -258,12 +383,12 @@ static void imxfb_disable_controller(struct imxfb_info *fbi)
 {
        pr_debug("Disabling LCD controller\n");
 
-       if(fbi->backlight_power)
+       if (fbi->backlight_power)
                fbi->backlight_power(0);
-       if(fbi->lcd_power)
+       if (fbi->lcd_power)
                fbi->lcd_power(0);
 
-       LCDC_RMCR = 0;
+       writel(0, fbi->regs + LCDC_RMCR);
 }
 
 static int imxfb_blank(int blank, struct fb_info *info)
@@ -340,74 +465,26 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
                        info->fix.id, var->lower_margin);
 #endif
 
-       LCDC_HCR        = HCR_H_WIDTH(var->hsync_len) |
-                         HCR_H_WAIT_1(var->left_margin) |
-                         HCR_H_WAIT_2(var->right_margin);
+       writel(HCR_H_WIDTH(var->hsync_len) |
+               HCR_H_WAIT_1(var->right_margin) |
+               HCR_H_WAIT_2(var->left_margin),
+               fbi->regs + LCDC_HCR);
 
-       LCDC_VCR        = VCR_V_WIDTH(var->vsync_len) |
-                         VCR_V_WAIT_1(var->upper_margin) |
-                         VCR_V_WAIT_2(var->lower_margin);
+       writel(VCR_V_WIDTH(var->vsync_len) |
+               VCR_V_WAIT_1(var->lower_margin) |
+               VCR_V_WAIT_2(var->upper_margin),
+               fbi->regs + LCDC_VCR);
 
-       LCDC_SIZE       = SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres);
-       LCDC_PCR        = fbi->pcr;
-       LCDC_PWMR       = fbi->pwmr;
-       LCDC_LSCR1      = fbi->lscr1;
-       LCDC_DMACR      = fbi->dmacr;
+       writel(SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres),
+                       fbi->regs + LCDC_SIZE);
+       writel(fbi->pcr, fbi->regs + LCDC_PCR);
+       writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+       writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
+       writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
 
        return 0;
 }
 
-static void imxfb_setup_gpio(struct imxfb_info *fbi)
-{
-       int width;
-
-       LCDC_RMCR       &= ~(RMCR_LCDC_EN | RMCR_SELF_REF);
-
-       if( fbi->pcr & PCR_TFT )
-               width = 16;
-       else
-               width = 1 << ((fbi->pcr >> 28) & 0x3);
-
-       switch(width) {
-       case 16:
-               imx_gpio_mode(PD30_PF_LD15);
-               imx_gpio_mode(PD29_PF_LD14);
-               imx_gpio_mode(PD28_PF_LD13);
-               imx_gpio_mode(PD27_PF_LD12);
-               imx_gpio_mode(PD26_PF_LD11);
-               imx_gpio_mode(PD25_PF_LD10);
-               imx_gpio_mode(PD24_PF_LD9);
-               imx_gpio_mode(PD23_PF_LD8);
-       case 8:
-               imx_gpio_mode(PD22_PF_LD7);
-               imx_gpio_mode(PD21_PF_LD6);
-               imx_gpio_mode(PD20_PF_LD5);
-               imx_gpio_mode(PD19_PF_LD4);
-       case 4:
-               imx_gpio_mode(PD18_PF_LD3);
-               imx_gpio_mode(PD17_PF_LD2);
-       case 2:
-               imx_gpio_mode(PD16_PF_LD1);
-       case 1:
-               imx_gpio_mode(PD15_PF_LD0);
-       }
-
-       /* initialize GPIOs */
-       imx_gpio_mode(PD6_PF_LSCLK);
-       imx_gpio_mode(PD11_PF_CONTRAST);
-       imx_gpio_mode(PD14_PF_FLM_VSYNC);
-       imx_gpio_mode(PD13_PF_LP_HSYNC);
-       imx_gpio_mode(PD12_PF_ACD_OE);
-
-       /* These are only needed for Sharp HR TFT displays */
-       if (fbi->pcr & PCR_SHARP) {
-               imx_gpio_mode(PD7_PF_REV);
-               imx_gpio_mode(PD8_PF_CLS);
-               imx_gpio_mode(PD9_PF_PS);
-               imx_gpio_mode(PD10_PF_SPL_SPR);
-       }
-}
-
 #ifdef CONFIG_PM
 /*
  * Power management hooks.  Note that we won't be called from IRQ context,
@@ -416,7 +493,8 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi)
 static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct imxfb_info *fbi = platform_get_drvdata(dev);
-       pr_debug("%s\n",__func__);
+
+       pr_debug("%s\n", __func__);
 
        imxfb_disable_controller(fbi);
        return 0;
@@ -425,7 +503,8 @@ static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
 static int imxfb_resume(struct platform_device *dev)
 {
        struct imxfb_info *fbi = platform_get_drvdata(dev);
-       pr_debug("%s\n",__func__);
+
+       pr_debug("%s\n", __func__);
 
        imxfb_enable_controller(fbi);
        return 0;
@@ -435,149 +514,136 @@ static int imxfb_resume(struct platform_device *dev)
 #define imxfb_resume   NULL
 #endif
 
-static int __init imxfb_init_fbinfo(struct device *dev)
+static int __init imxfb_init_fbinfo(struct platform_device *pdev)
 {
-       struct imxfb_mach_info *inf = dev->platform_data;
-       struct fb_info *info = dev_get_drvdata(dev);
+       struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
+       struct fb_info *info = dev_get_drvdata(&pdev->dev);
        struct imxfb_info *fbi = info->par;
 
        pr_debug("%s\n",__func__);
 
-       info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL);
+       info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
        if (!info->pseudo_palette)
                return -ENOMEM;
 
        memset(fbi, 0, sizeof(struct imxfb_info));
-       fbi->dev = dev;
 
        strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
 
-       info->fix.type  = FB_TYPE_PACKED_PIXELS;
+       info->fix.type                  = FB_TYPE_PACKED_PIXELS;
        info->fix.type_aux              = 0;
        info->fix.xpanstep              = 0;
        info->fix.ypanstep              = 0;
        info->fix.ywrapstep             = 0;
-       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.accel                 = FB_ACCEL_NONE;
 
        info->var.nonstd                = 0;
        info->var.activate              = FB_ACTIVATE_NOW;
        info->var.height                = -1;
        info->var.width = -1;
        info->var.accel_flags           = 0;
-       info->var.vmode = FB_VMODE_NONINTERLACED;
+       info->var.vmode                 = FB_VMODE_NONINTERLACED;
 
        info->fbops                     = &imxfb_ops;
-       info->flags                     = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
-
-       fbi->rgb[RGB_16]                = &def_rgb_16;
-       fbi->rgb[RGB_8]                 = &def_rgb_8;
-
-       fbi->max_xres                   = inf->xres;
-       info->var.xres                  = inf->xres;
-       info->var.xres_virtual          = inf->xres;
-       fbi->max_yres                   = inf->yres;
-       info->var.yres                  = inf->yres;
-       info->var.yres_virtual          = inf->yres;
-       fbi->max_bpp                    = inf->bpp;
-       info->var.bits_per_pixel        = inf->bpp;
-       info->var.nonstd                = inf->nonstd;
-       info->var.pixclock              = inf->pixclock;
-       info->var.hsync_len             = inf->hsync_len;
-       info->var.left_margin           = inf->left_margin;
-       info->var.right_margin          = inf->right_margin;
-       info->var.vsync_len             = inf->vsync_len;
-       info->var.upper_margin          = inf->upper_margin;
-       info->var.lower_margin          = inf->lower_margin;
-       info->var.sync                  = inf->sync;
-       info->var.grayscale             = inf->cmap_greyscale;
-       fbi->cmap_inverse               = inf->cmap_inverse;
-       fbi->cmap_static                = inf->cmap_static;
-       fbi->pcr                        = inf->pcr;
-       fbi->lscr1                      = inf->lscr1;
-       fbi->dmacr                      = inf->dmacr;
-       fbi->pwmr                       = inf->pwmr;
-       fbi->lcd_power                  = inf->lcd_power;
-       fbi->backlight_power            = inf->backlight_power;
+       info->flags                     = FBINFO_FLAG_DEFAULT |
+                                         FBINFO_READS_FAST;
+
+       fbi->max_xres                   = pdata->xres;
+       info->var.xres                  = pdata->xres;
+       info->var.xres_virtual          = pdata->xres;
+       fbi->max_yres                   = pdata->yres;
+       info->var.yres                  = pdata->yres;
+       info->var.yres_virtual          = pdata->yres;
+       fbi->max_bpp                    = pdata->bpp;
+       info->var.bits_per_pixel        = pdata->bpp;
+       info->var.nonstd                = pdata->nonstd;
+       info->var.pixclock              = pdata->pixclock;
+       info->var.hsync_len             = pdata->hsync_len;
+       info->var.left_margin           = pdata->left_margin;
+       info->var.right_margin          = pdata->right_margin;
+       info->var.vsync_len             = pdata->vsync_len;
+       info->var.upper_margin          = pdata->upper_margin;
+       info->var.lower_margin          = pdata->lower_margin;
+       info->var.sync                  = pdata->sync;
+       info->var.grayscale             = pdata->cmap_greyscale;
+       fbi->cmap_inverse               = pdata->cmap_inverse;
+       fbi->cmap_static                = pdata->cmap_static;
+       fbi->pcr                        = pdata->pcr;
+       fbi->lscr1                      = pdata->lscr1;
+       fbi->dmacr                      = pdata->dmacr;
+       fbi->pwmr                       = pdata->pwmr;
+       fbi->lcd_power                  = pdata->lcd_power;
+       fbi->backlight_power            = pdata->backlight_power;
        info->fix.smem_len              = fbi->max_xres * fbi->max_yres *
                                          fbi->max_bpp / 8;
 
        return 0;
 }
 
-/*
- *      Allocates the DRAM memory for the frame buffer.  This buffer is
- *     remapped into a non-cached, non-buffered, memory region to
- *      allow pixel writes to occur without flushing the cache.
- *      Once this area is remapped, all virtual memory access to the
- *      video memory should occur at the new region.
- */
-static int __init imxfb_map_video_memory(struct fb_info *info)
-{
-       struct imxfb_info *fbi = info->par;
-
-       fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
-       fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
-                                       &fbi->map_dma,GFP_KERNEL);
-
-       if (fbi->map_cpu) {
-               info->screen_base = fbi->map_cpu;
-               fbi->screen_cpu = fbi->map_cpu;
-               fbi->screen_dma = fbi->map_dma;
-               info->fix.smem_start = fbi->screen_dma;
-       }
-
-       return fbi->map_cpu ? 0 : -ENOMEM;
-}
-
 static int __init imxfb_probe(struct platform_device *pdev)
 {
        struct imxfb_info *fbi;
        struct fb_info *info;
-       struct imxfb_mach_info *inf;
+       struct imx_fb_platform_data *pdata;
        struct resource *res;
        int ret;
 
        printk("i.MX Framebuffer driver\n");
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if(!res)
+       if (!res)
                return -ENODEV;
 
-       inf = pdev->dev.platform_data;
-       if(!inf) {
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
                dev_err(&pdev->dev,"No platform_data available\n");
                return -ENOMEM;
        }
 
        info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
-       if(!info)
+       if (!info)
                return -ENOMEM;
 
        fbi = info->par;
 
        platform_set_drvdata(pdev, info);
 
-       ret = imxfb_init_fbinfo(&pdev->dev);
-       if( ret < 0 )
+       ret = imxfb_init_fbinfo(pdev);
+       if (ret < 0)
                goto failed_init;
 
-       res = request_mem_region(res->start, res->end - res->start + 1, "IMXFB");
+       res = request_mem_region(res->start, resource_size(res),
+                               DRIVER_NAME);
        if (!res) {
                ret = -EBUSY;
-               goto failed_regs;
+               goto failed_req;
+       }
+
+       fbi->regs = ioremap(res->start, resource_size(res));
+       if (fbi->regs == NULL) {
+               printk(KERN_ERR"Cannot map frame buffer registers\n");
+               goto failed_ioremap;
        }
 
-       if (!inf->fixed_screen_cpu) {
-               ret = imxfb_map_video_memory(info);
-               if (ret) {
+       if (!pdata->fixed_screen_cpu) {
+               fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
+               fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
+                               fbi->map_size, &fbi->map_dma, GFP_KERNEL);
+
+               if (!fbi->map_cpu) {
                        dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
                        ret = -ENOMEM;
                        goto failed_map;
                }
+
+               info->screen_base = fbi->map_cpu;
+               fbi->screen_cpu = fbi->map_cpu;
+               fbi->screen_dma = fbi->map_dma;
+               info->fix.smem_start = fbi->screen_dma;
        } else {
                /* Fixed framebuffer mapping enables location of the screen in eSRAM */
-               fbi->map_cpu = inf->fixed_screen_cpu;
-               fbi->map_dma = inf->fixed_screen_dma;
+               fbi->map_cpu = pdata->fixed_screen_cpu;
+               fbi->map_dma = pdata->fixed_screen_dma;
                info->screen_base = fbi->map_cpu;
                fbi->screen_cpu = fbi->map_cpu;
                fbi->screen_dma = fbi->map_dma;
@@ -590,12 +656,10 @@ static int __init imxfb_probe(struct platform_device *pdev)
         */
        imxfb_check_var(&info->var, info);
 
-       ret = fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+       ret = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
        if (ret < 0)
                goto failed_cmap;
 
-       imxfb_setup_gpio(fbi);
-
        imxfb_set_par(info);
        ret = register_framebuffer(info);
        if (ret < 0) {
@@ -610,20 +674,22 @@ static int __init imxfb_probe(struct platform_device *pdev)
 failed_register:
        fb_dealloc_cmap(&info->cmap);
 failed_cmap:
-       if (!inf->fixed_screen_cpu)
+       if (!pdata->fixed_screen_cpu)
                dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
-                          fbi->map_dma);
+                       fbi->map_dma);
 failed_map:
-       kfree(info->pseudo_palette);
-failed_regs:
+       iounmap(fbi->regs);
+failed_ioremap:
        release_mem_region(res->start, res->end - res->start);
+failed_req:
+       kfree(info->pseudo_palette);
 failed_init:
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(info);
        return ret;
 }
 
-static int imxfb_remove(struct platform_device *pdev)
+static int __devexit imxfb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
        struct imxfb_info *fbi = info->par;
@@ -639,6 +705,7 @@ static int imxfb_remove(struct platform_device *pdev)
        kfree(info->pseudo_palette);
        framebuffer_release(info);
 
+       iounmap(fbi->regs);
        release_mem_region(res->start, res->end - res->start + 1);
        platform_set_drvdata(pdev, NULL);
 
@@ -653,19 +720,18 @@ void  imxfb_shutdown(struct platform_device * dev)
 }
 
 static struct platform_driver imxfb_driver = {
-       .probe          = imxfb_probe,
        .suspend        = imxfb_suspend,
        .resume         = imxfb_resume,
-       .remove         = imxfb_remove,
+       .remove         = __devexit_p(imxfb_remove),
        .shutdown       = imxfb_shutdown,
        .driver         = {
-               .name   = "imx-fb",
+               .name   = DRIVER_NAME,
        },
 };
 
 int __init imxfb_init(void)
 {
-       return platform_driver_register(&imxfb_driver);
+       return platform_driver_probe(&imxfb_driver, imxfb_probe);
 }
 
 static void __exit imxfb_cleanup(void)
diff --git a/drivers/video/imxfb.h b/drivers/video/imxfb.h
deleted file mode 100644 (file)
index e837a8b..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * linux/drivers/video/imxfb.h
- *
- *  Freescale i.MX Frame Buffer device driver
- *
- *  Copyright (C) 2004 S.Hauer, Pengutronix
- *
- *  Copyright (C) 1999 Eric A. Thomas
- *   Based on acornfb.c Copyright (C) Russell King.
- *
- * 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.
- */
-
-/*
- * These are the bitfields for each
- * display depth that we support.
- */
-struct imxfb_rgb {
-       struct fb_bitfield      red;
-       struct fb_bitfield      green;
-       struct fb_bitfield      blue;
-       struct fb_bitfield      transp;
-};
-
-#define RGB_16 (0)
-#define RGB_8  (1)
-#define NR_RGB 2
-
-struct imxfb_info {
-       struct device           *dev;
-       struct imxfb_rgb        *rgb[NR_RGB];
-
-       u_int                   max_bpp;
-       u_int                   max_xres;
-       u_int                   max_yres;
-
-       /*
-        * These are the addresses we mapped
-        * the framebuffer memory region to.
-        */
-       dma_addr_t              map_dma;
-       u_char *                map_cpu;
-       u_int                   map_size;
-
-       u_char *                screen_cpu;
-       dma_addr_t              screen_dma;
-       u_int                   palette_size;
-
-       dma_addr_t              dbar1;
-       dma_addr_t              dbar2;
-
-       u_int                   pcr;
-       u_int                   pwmr;
-       u_int                   lscr1;
-       u_int                   dmacr;
-       u_int                   cmap_inverse:1,
-                               cmap_static:1,
-                               unused:30;
-
-       void (*lcd_power)(int);
-       void (*backlight_power)(int);
-};
-
-#define IMX_NAME       "IMX"
-
-/*
- * Minimum X and Y resolutions
- */
-#define MIN_XRES       64
-#define MIN_YRES       64
-
index cc59c52e1103dfdd48cd161fb37a385023890b5a..48ff701d3a72b9cd1d5a6cb7b345a89e9678e50d 100644 (file)
  *
  *     linux-arm-kernel@lists.arm.linux.org.uk
  *
+ * Add support for overlay1 and overlay2 based on pxafb_overlay.c:
+ *
+ *   Copyright (C) 2004, Intel Corporation
+ *
+ *     2003/08/27: <yu.tang@intel.com>
+ *     2004/03/10: <stanley.cai@intel.com>
+ *     2004/10/28: <yan.yin@intel.com>
+ *
+ *   Copyright (C) 2006-2008 Marvell International Ltd.
+ *   All Rights Reserved
  */
 
 #include <linux/module.h>
@@ -50,7 +60,6 @@
 #include <asm/irq.h>
 #include <asm/div64.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
 #include <mach/bitfield.h>
 #include <mach/pxafb.h>
 
                                         LCCR0_SFM | LCCR0_LDM | LCCR0_ENB)
 
 #define LCCR3_INVALID_CONFIG_MASK      (LCCR3_HSP | LCCR3_VSP |\
-                                        LCCR3_PCD | LCCR3_BPP)
-
-static void (*pxafb_backlight_power)(int);
-static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
+                                        LCCR3_PCD | LCCR3_BPP(0xf))
 
 static int pxafb_activate_var(struct fb_var_screeninfo *var,
                                struct pxafb_info *);
 static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
+static void setup_base_frame(struct pxafb_info *fbi, int branch);
+static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
+                          unsigned long offset, size_t size);
+
+static unsigned long video_mem_size = 0;
 
 static inline unsigned long
 lcd_readl(struct pxafb_info *fbi, unsigned int off)
@@ -156,6 +167,12 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
                val |= ((blue  >> 8) & 0x000000fc);
                ((u32 *)(fbi->palette_cpu))[regno] = val;
                break;
+       case LCCR4_PAL_FOR_3:
+               val  = ((red   << 8) & 0x00ff0000);
+               val |= ((green >> 0) & 0x0000ff00);
+               val |= ((blue  >> 8) & 0x000000ff);
+               ((u32 *)(fbi->palette_cpu))[regno] = val;
+               break;
        }
 
        return 0;
@@ -216,37 +233,110 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        return ret;
 }
 
-/*
- *  pxafb_bpp_to_lccr3():
- *    Convert a bits per pixel value to the correct bit pattern for LCCR3
- */
-static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
+/* calculate pixel depth, transparency bit included, >=16bpp formats _only_ */
+static inline int var_to_depth(struct fb_var_screeninfo *var)
 {
-       int ret = 0;
+       return var->red.length + var->green.length +
+               var->blue.length + var->transp.length;
+}
+
+/* calculate 4-bit BPP value for LCCR3 and OVLxC1 */
+static int pxafb_var_to_bpp(struct fb_var_screeninfo *var)
+{
+       int bpp = -EINVAL;
+
        switch (var->bits_per_pixel) {
-       case 1:  ret = LCCR3_1BPP; break;
-       case 2:  ret = LCCR3_2BPP; break;
-       case 4:  ret = LCCR3_4BPP; break;
-       case 8:  ret = LCCR3_8BPP; break;
-       case 16: ret = LCCR3_16BPP; break;
+       case 1:  bpp = 0; break;
+       case 2:  bpp = 1; break;
+       case 4:  bpp = 2; break;
+       case 8:  bpp = 3; break;
+       case 16: bpp = 4; break;
        case 24:
-               switch (var->red.length + var->green.length +
-                               var->blue.length + var->transp.length) {
-               case 18: ret = LCCR3_18BPP_P | LCCR3_PDFOR_3; break;
-               case 19: ret = LCCR3_19BPP_P; break;
+               switch (var_to_depth(var)) {
+               case 18: bpp = 6; break; /* 18-bits/pixel packed */
+               case 19: bpp = 8; break; /* 19-bits/pixel packed */
+               case 24: bpp = 9; break;
                }
                break;
        case 32:
-               switch (var->red.length + var->green.length +
-                               var->blue.length + var->transp.length) {
-               case 18: ret = LCCR3_18BPP | LCCR3_PDFOR_3; break;
-               case 19: ret = LCCR3_19BPP; break;
-               case 24: ret = LCCR3_24BPP | LCCR3_PDFOR_3; break;
-               case 25: ret = LCCR3_25BPP; break;
+               switch (var_to_depth(var)) {
+               case 18: bpp = 5; break; /* 18-bits/pixel unpacked */
+               case 19: bpp = 7; break; /* 19-bits/pixel unpacked */
+               case 25: bpp = 10; break;
                }
                break;
        }
-       return ret;
+       return bpp;
+}
+
+/*
+ *  pxafb_var_to_lccr3():
+ *    Convert a bits per pixel value to the correct bit pattern for LCCR3
+ *
+ *  NOTE: for PXA27x with overlays support, the LCCR3_PDFOR_x bits have an
+ *  implication of the acutal use of transparency bit,  which we handle it
+ *  here separatedly. See PXA27x Developer's Manual, Section <<7.4.6 Pixel
+ *  Formats>> for the valid combination of PDFOR, PAL_FOR for various BPP.
+ *
+ *  Transparency for palette pixel formats is not supported at the moment.
+ */
+static uint32_t pxafb_var_to_lccr3(struct fb_var_screeninfo *var)
+{
+       int bpp = pxafb_var_to_bpp(var);
+       uint32_t lccr3;
+
+       if (bpp < 0)
+               return 0;
+
+       lccr3 = LCCR3_BPP(bpp);
+
+       switch (var_to_depth(var)) {
+       case 16: lccr3 |= var->transp.length ? LCCR3_PDFOR_3 : 0; break;
+       case 18: lccr3 |= LCCR3_PDFOR_3; break;
+       case 24: lccr3 |= var->transp.length ? LCCR3_PDFOR_2 : LCCR3_PDFOR_3;
+                break;
+       case 19:
+       case 25: lccr3 |= LCCR3_PDFOR_0; break;
+       }
+       return lccr3;
+}
+
+#define SET_PIXFMT(v, r, g, b, t)                              \
+({                                                             \
+       (v)->transp.offset = (t) ? (r) + (g) + (b) : 0;         \
+       (v)->transp.length = (t) ? (t) : 0;                     \
+       (v)->blue.length   = (b); (v)->blue.offset = 0;         \
+       (v)->green.length  = (g); (v)->green.offset = (b);      \
+       (v)->red.length    = (r); (v)->red.offset = (b) + (g);  \
+})
+
+/* set the RGBT bitfields of fb_var_screeninf according to
+ * var->bits_per_pixel and given depth
+ */
+static void pxafb_set_pixfmt(struct fb_var_screeninfo *var, int depth)
+{
+       if (depth == 0)
+               depth = var->bits_per_pixel;
+
+       if (var->bits_per_pixel < 16) {
+               /* indexed pixel formats */
+               var->red.offset    = 0; var->red.length    = 8;
+               var->green.offset  = 0; var->green.length  = 8;
+               var->blue.offset   = 0; var->blue.length   = 8;
+               var->transp.offset = 0; var->transp.length = 8;
+       }
+
+       switch (depth) {
+       case 16: var->transp.length ?
+                SET_PIXFMT(var, 5, 5, 5, 1) :          /* RGBT555 */
+                SET_PIXFMT(var, 5, 6, 5, 0); break;    /* RGB565 */
+       case 18: SET_PIXFMT(var, 6, 6, 6, 0); break;    /* RGB666 */
+       case 19: SET_PIXFMT(var, 6, 6, 6, 1); break;    /* RGBT666 */
+       case 24: var->transp.length ?
+                SET_PIXFMT(var, 8, 8, 7, 1) :          /* RGBT887 */
+                SET_PIXFMT(var, 8, 8, 8, 0); break;    /* RGB888 */
+       case 25: SET_PIXFMT(var, 8, 8, 8, 1); break;    /* RGBT888 */
+       }
 }
 
 #ifdef CONFIG_CPU_FREQ
@@ -308,8 +398,49 @@ static void pxafb_setmode(struct fb_var_screeninfo *var,
        var->lower_margin       = mode->lower_margin;
        var->sync               = mode->sync;
        var->grayscale          = mode->cmap_greyscale;
-       var->xres_virtual       = var->xres;
-       var->yres_virtual       = var->yres;
+
+       /* set the initial RGBA bitfields */
+       pxafb_set_pixfmt(var, mode->depth);
+}
+
+static int pxafb_adjust_timing(struct pxafb_info *fbi,
+                              struct fb_var_screeninfo *var)
+{
+       int line_length;
+
+       var->xres = max_t(int, var->xres, MIN_XRES);
+       var->yres = max_t(int, var->yres, MIN_YRES);
+
+       if (!(fbi->lccr0 & LCCR0_LCDT)) {
+               clamp_val(var->hsync_len, 1, 64);
+               clamp_val(var->vsync_len, 1, 64);
+               clamp_val(var->left_margin,  1, 255);
+               clamp_val(var->right_margin, 1, 255);
+               clamp_val(var->upper_margin, 1, 255);
+               clamp_val(var->lower_margin, 1, 255);
+       }
+
+       /* make sure each line is aligned on word boundary */
+       line_length = var->xres * var->bits_per_pixel / 8;
+       line_length = ALIGN(line_length, 4);
+       var->xres = line_length * 8 / var->bits_per_pixel;
+
+       /* we don't support xpan, force xres_virtual to be equal to xres */
+       var->xres_virtual = var->xres;
+
+       if (var->accel_flags & FB_ACCELF_TEXT)
+               var->yres_virtual = fbi->fb.fix.smem_len / line_length;
+       else
+               var->yres_virtual = max(var->yres_virtual, var->yres);
+
+       /* check for limits */
+       if (var->xres > MAX_XRES || var->yres > MAX_YRES)
+               return -EINVAL;
+
+       if (var->yres > var->yres_virtual)
+               return -EINVAL;
+
+       return 0;
 }
 
 /*
@@ -325,11 +456,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct pxafb_info *fbi = (struct pxafb_info *)info;
        struct pxafb_mach_info *inf = fbi->dev->platform_data;
-
-       if (var->xres < MIN_XRES)
-               var->xres = MIN_XRES;
-       if (var->yres < MIN_YRES)
-               var->yres = MIN_YRES;
+       int err;
 
        if (inf->fixed_modes) {
                struct pxafb_mode_info *mode;
@@ -338,74 +465,18 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
                if (!mode)
                        return -EINVAL;
                pxafb_setmode(var, mode);
-       } else {
-               if (var->xres > inf->modes->xres)
-                       return -EINVAL;
-               if (var->yres > inf->modes->yres)
-                       return -EINVAL;
-               if (var->bits_per_pixel > inf->modes->bpp)
-                       return -EINVAL;
        }
 
-       var->xres_virtual =
-               max(var->xres_virtual, var->xres);
-       var->yres_virtual =
-               max(var->yres_virtual, var->yres);
+       /* do a test conversion to BPP fields to check the color formats */
+       err = pxafb_var_to_bpp(var);
+       if (err < 0)
+               return err;
 
-       /*
-        * Setup the RGB parameters for this display.
-        *
-        * The pixel packing format is described on page 7-11 of the
-        * PXA2XX Developer's Manual.
-        */
-       if (var->bits_per_pixel == 16) {
-               var->red.offset   = 11; var->red.length   = 5;
-               var->green.offset = 5;  var->green.length = 6;
-               var->blue.offset  = 0;  var->blue.length  = 5;
-               var->transp.offset = var->transp.length = 0;
-       } else if (var->bits_per_pixel > 16) {
-               struct pxafb_mode_info *mode;
+       pxafb_set_pixfmt(var, var_to_depth(var));
 
-               mode = pxafb_getmode(inf, var);
-               if (!mode)
-                       return -EINVAL;
-
-               switch (mode->depth) {
-               case 18: /* RGB666 */
-                       var->transp.offset = var->transp.length     = 0;
-                       var->red.offset    = 12; var->red.length    = 6;
-                       var->green.offset  = 6;  var->green.length  = 6;
-                       var->blue.offset   = 0;  var->blue.length   = 6;
-                       break;
-               case 19: /* RGBT666 */
-                       var->transp.offset = 18; var->transp.length = 1;
-                       var->red.offset    = 12; var->red.length    = 6;
-                       var->green.offset  = 6;  var->green.length  = 6;
-                       var->blue.offset   = 0;  var->blue.length   = 6;
-                       break;
-               case 24: /* RGB888 */
-                       var->transp.offset = var->transp.length     = 0;
-                       var->red.offset    = 16; var->red.length    = 8;
-                       var->green.offset  = 8;  var->green.length  = 8;
-                       var->blue.offset   = 0;  var->blue.length   = 8;
-                       break;
-               case 25: /* RGBT888 */
-                       var->transp.offset = 24; var->transp.length = 1;
-                       var->red.offset    = 16; var->red.length    = 8;
-                       var->green.offset  = 8;  var->green.length  = 8;
-                       var->blue.offset   = 0;  var->blue.length   = 8;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else {
-               var->red.offset = var->green.offset = 0;
-               var->blue.offset = var->transp.offset = 0;
-               var->red.length   = 8;
-               var->green.length = 8;
-               var->blue.length  = 8;
-               var->transp.length = 0;
-       }
+       err = pxafb_adjust_timing(fbi, var);
+       if (err)
+               return err;
 
 #ifdef CONFIG_CPU_FREQ
        pr_debug("pxafb: dma period = %d ps\n",
@@ -415,11 +486,6 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-static inline void pxafb_set_truecolor(u_int is_true_color)
-{
-       /* do your machine-specific setup if needed */
-}
-
 /*
  * pxafb_set_par():
  *     Set the user defined part of the display for the specified console
@@ -452,11 +518,6 @@ static int pxafb_set_par(struct fb_info *info)
 
        fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0];
 
-       /*
-        * Set (any) board control register to handle new color depth
-        */
-       pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
-
        if (fbi->fb.var.bits_per_pixel >= 16)
                fb_dealloc_cmap(&fbi->fb.cmap);
        else
@@ -467,6 +528,24 @@ static int pxafb_set_par(struct fb_info *info)
        return 0;
 }
 
+static int pxafb_pan_display(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct pxafb_info *fbi = (struct pxafb_info *)info;
+       int dma = DMA_MAX + DMA_BASE;
+
+       if (fbi->state != C_ENABLE)
+               return 0;
+
+       setup_base_frame(fbi, 1);
+
+       if (fbi->lccr0 & LCCR0_SDS)
+               lcd_writel(fbi, FBR1, fbi->fdadr[dma + 1] | 0x1);
+
+       lcd_writel(fbi, FBR0, fbi->fdadr[dma] | 0x1);
+       return 0;
+}
+
 /*
  * pxafb_blank():
  *     Blank the display by setting all palette values to zero.  Note, the
@@ -502,32 +581,342 @@ static int pxafb_blank(int blank, struct fb_info *info)
        return 0;
 }
 
-static int pxafb_mmap(struct fb_info *info,
-                     struct vm_area_struct *vma)
-{
-       struct pxafb_info *fbi = (struct pxafb_info *)info;
-       unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
-
-       if (off < info->fix.smem_len) {
-               vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
-               return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
-                                            fbi->map_dma, fbi->map_size);
-       }
-       return -EINVAL;
-}
-
 static struct fb_ops pxafb_ops = {
        .owner          = THIS_MODULE,
        .fb_check_var   = pxafb_check_var,
        .fb_set_par     = pxafb_set_par,
+       .fb_pan_display = pxafb_pan_display,
        .fb_setcolreg   = pxafb_setcolreg,
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
        .fb_blank       = pxafb_blank,
-       .fb_mmap        = pxafb_mmap,
 };
 
+#ifdef CONFIG_FB_PXA_OVERLAY
+static void overlay1fb_setup(struct pxafb_layer *ofb)
+{
+       int size = ofb->fb.fix.line_length * ofb->fb.var.yres_virtual;
+       unsigned long start = ofb->video_mem_phys;
+       setup_frame_dma(ofb->fbi, DMA_OV1, PAL_NONE, start, size);
+}
+
+/* Depending on the enable status of overlay1/2, the DMA should be
+ * updated from FDADRx (when disabled) or FBRx (when enabled).
+ */
+static void overlay1fb_enable(struct pxafb_layer *ofb)
+{
+       int enabled = lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN;
+       uint32_t fdadr1 = ofb->fbi->fdadr[DMA_OV1] | (enabled ? 0x1 : 0);
+
+       lcd_writel(ofb->fbi, enabled ? FBR1 : FDADR1, fdadr1);
+       lcd_writel(ofb->fbi, OVL1C2, ofb->control[1]);
+       lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] | OVLxC1_OEN);
+}
+
+static void overlay1fb_disable(struct pxafb_layer *ofb)
+{
+       uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
+
+       lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN);
+
+       lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(1));
+       lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(1));
+       lcd_writel(ofb->fbi, FBR1, ofb->fbi->fdadr[DMA_OV1] | 0x3);
+
+       if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) == 0)
+               pr_warning("%s: timeout disabling overlay1\n", __func__);
+
+       lcd_writel(ofb->fbi, LCCR5, lccr5);
+}
+
+static void overlay2fb_setup(struct pxafb_layer *ofb)
+{
+       int size, div = 1, pfor = NONSTD_TO_PFOR(ofb->fb.var.nonstd);
+       unsigned long start[3] = { ofb->video_mem_phys, 0, 0 };
+
+       if (pfor == OVERLAY_FORMAT_RGB || pfor == OVERLAY_FORMAT_YUV444_PACKED) {
+               size = ofb->fb.fix.line_length * ofb->fb.var.yres_virtual;
+               setup_frame_dma(ofb->fbi, DMA_OV2_Y, -1, start[0], size);
+       } else {
+               size = ofb->fb.var.xres_virtual * ofb->fb.var.yres_virtual;
+               switch (pfor) {
+               case OVERLAY_FORMAT_YUV444_PLANAR: div = 1; break;
+               case OVERLAY_FORMAT_YUV422_PLANAR: div = 2; break;
+               case OVERLAY_FORMAT_YUV420_PLANAR: div = 4; break;
+               }
+               start[1] = start[0] + size;
+               start[2] = start[1] + size / div;
+               setup_frame_dma(ofb->fbi, DMA_OV2_Y,  -1, start[0], size);
+               setup_frame_dma(ofb->fbi, DMA_OV2_Cb, -1, start[1], size / div);
+               setup_frame_dma(ofb->fbi, DMA_OV2_Cr, -1, start[2], size / div);
+       }
+}
+
+static void overlay2fb_enable(struct pxafb_layer *ofb)
+{
+       int pfor = NONSTD_TO_PFOR(ofb->fb.var.nonstd);
+       int enabled = lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN;
+       uint32_t fdadr2 = ofb->fbi->fdadr[DMA_OV2_Y]  | (enabled ? 0x1 : 0);
+       uint32_t fdadr3 = ofb->fbi->fdadr[DMA_OV2_Cb] | (enabled ? 0x1 : 0);
+       uint32_t fdadr4 = ofb->fbi->fdadr[DMA_OV2_Cr] | (enabled ? 0x1 : 0);
+
+       if (pfor == OVERLAY_FORMAT_RGB || pfor == OVERLAY_FORMAT_YUV444_PACKED)
+               lcd_writel(ofb->fbi, enabled ? FBR2 : FDADR2, fdadr2);
+       else {
+               lcd_writel(ofb->fbi, enabled ? FBR2 : FDADR2, fdadr2);
+               lcd_writel(ofb->fbi, enabled ? FBR3 : FDADR3, fdadr3);
+               lcd_writel(ofb->fbi, enabled ? FBR4 : FDADR4, fdadr4);
+       }
+       lcd_writel(ofb->fbi, OVL2C2, ofb->control[1]);
+       lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] | OVLxC1_OEN);
+}
+
+static void overlay2fb_disable(struct pxafb_layer *ofb)
+{
+       uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5);
+
+       lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN);
+
+       lcd_writel(ofb->fbi, LCSR1, LCSR1_BS(2));
+       lcd_writel(ofb->fbi, LCCR5, lccr5 & ~LCSR1_BS(2));
+       lcd_writel(ofb->fbi, FBR2, ofb->fbi->fdadr[DMA_OV2_Y]  | 0x3);
+       lcd_writel(ofb->fbi, FBR3, ofb->fbi->fdadr[DMA_OV2_Cb] | 0x3);
+       lcd_writel(ofb->fbi, FBR4, ofb->fbi->fdadr[DMA_OV2_Cr] | 0x3);
+
+       if (wait_for_completion_timeout(&ofb->branch_done, 1 * HZ) == 0)
+               pr_warning("%s: timeout disabling overlay2\n", __func__);
+}
+
+static struct pxafb_layer_ops ofb_ops[] = {
+       [0] = {
+               .enable         = overlay1fb_enable,
+               .disable        = overlay1fb_disable,
+               .setup          = overlay1fb_setup,
+       },
+       [1] = {
+               .enable         = overlay2fb_enable,
+               .disable        = overlay2fb_disable,
+               .setup          = overlay2fb_setup,
+       },
+};
+
+static int overlayfb_open(struct fb_info *info, int user)
+{
+       struct pxafb_layer *ofb = (struct pxafb_layer *)info;
+
+       /* no support for framebuffer console on overlay */
+       if (user == 0)
+               return -ENODEV;
+
+       /* allow only one user at a time */
+       if (atomic_inc_and_test(&ofb->usage))
+               return -EBUSY;
+
+       /* unblank the base framebuffer */
+       fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK);
+       return 0;
+}
+
+static int overlayfb_release(struct fb_info *info, int user)
+{
+       struct pxafb_layer *ofb = (struct pxafb_layer*) info;
+
+       atomic_dec(&ofb->usage);
+       ofb->ops->disable(ofb);
+
+       free_pages_exact(ofb->video_mem, ofb->video_mem_size);
+       ofb->video_mem = NULL;
+       ofb->video_mem_size = 0;
+       return 0;
+}
+
+static int overlayfb_check_var(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+       struct pxafb_layer *ofb = (struct pxafb_layer *)info;
+       struct fb_var_screeninfo *base_var = &ofb->fbi->fb.var;
+       int xpos, ypos, pfor, bpp;
+
+       xpos = NONSTD_TO_XPOS(var->nonstd);
+       ypos = NONSTD_TO_XPOS(var->nonstd);
+       pfor = NONSTD_TO_PFOR(var->nonstd);
+
+       bpp = pxafb_var_to_bpp(var);
+       if (bpp < 0)
+               return -EINVAL;
+
+       /* no support for YUV format on overlay1 */
+       if (ofb->id == OVERLAY1 && pfor != 0)
+               return -EINVAL;
+
+       /* for YUV packed formats, bpp = 'minimum bpp of YUV components' */
+       switch (pfor) {
+       case OVERLAY_FORMAT_RGB:
+               bpp = pxafb_var_to_bpp(var);
+               if (bpp < 0)
+                       return -EINVAL;
+
+               pxafb_set_pixfmt(var, var_to_depth(var));
+               break;
+       case OVERLAY_FORMAT_YUV444_PACKED: bpp = 24; break;
+       case OVERLAY_FORMAT_YUV444_PLANAR: bpp = 8; break;
+       case OVERLAY_FORMAT_YUV422_PLANAR: bpp = 4; break;
+       case OVERLAY_FORMAT_YUV420_PLANAR: bpp = 2; break;
+       default:
+               return -EINVAL;
+       }
+
+       /* each line must start at a 32-bit word boundary */
+       if ((xpos * bpp) % 32)
+               return -EINVAL;
+
+       /* xres must align on 32-bit word boundary */
+       var->xres = roundup(var->xres * bpp, 32) / bpp;
+
+       if ((xpos + var->xres > base_var->xres) ||
+           (ypos + var->yres > base_var->yres))
+               return -EINVAL;
+
+       var->xres_virtual = var->xres;
+       var->yres_virtual = max(var->yres, var->yres_virtual);
+       return 0;
+}
+
+static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
+{
+       struct fb_var_screeninfo *var = &ofb->fb.var;
+       int pfor = NONSTD_TO_PFOR(var->nonstd);
+       int size, bpp = 0;
+
+       switch (pfor) {
+       case OVERLAY_FORMAT_RGB: bpp = var->bits_per_pixel; break;
+       case OVERLAY_FORMAT_YUV444_PACKED: bpp = 24; break;
+       case OVERLAY_FORMAT_YUV444_PLANAR: bpp = 24; break;
+       case OVERLAY_FORMAT_YUV422_PLANAR: bpp = 16; break;
+       case OVERLAY_FORMAT_YUV420_PLANAR: bpp = 12; break;
+       }
+
+       ofb->fb.fix.line_length = var->xres_virtual * bpp / 8;
+
+       size = PAGE_ALIGN(ofb->fb.fix.line_length * var->yres_virtual);
+
+       /* don't re-allocate if the original video memory is enough */
+       if (ofb->video_mem) {
+               if (ofb->video_mem_size >= size)
+                       return 0;
+
+               free_pages_exact(ofb->video_mem, ofb->video_mem_size);
+       }
+
+       ofb->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+       if (ofb->video_mem == NULL)
+               return -ENOMEM;
+
+       ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
+       ofb->video_mem_size = size;
+
+       ofb->fb.fix.smem_start  = ofb->video_mem_phys;
+       ofb->fb.fix.smem_len    = ofb->fb.fix.line_length * var->yres_virtual;
+       ofb->fb.screen_base     = ofb->video_mem;
+       return 0;
+}
+
+static int overlayfb_set_par(struct fb_info *info)
+{
+       struct pxafb_layer *ofb = (struct pxafb_layer *)info;
+       struct fb_var_screeninfo *var = &info->var;
+       int xpos, ypos, pfor, bpp, ret;
+
+       ret = overlayfb_map_video_memory(ofb);
+       if (ret)
+               return ret;
+
+       bpp  = pxafb_var_to_bpp(var);
+       xpos = NONSTD_TO_XPOS(var->nonstd);
+       ypos = NONSTD_TO_XPOS(var->nonstd);
+       pfor = NONSTD_TO_PFOR(var->nonstd);
+
+       ofb->control[0] = OVLxC1_PPL(var->xres) | OVLxC1_LPO(var->yres) |
+                         OVLxC1_BPP(bpp);
+       ofb->control[1] = OVLxC2_XPOS(xpos) | OVLxC2_YPOS(ypos);
+
+       if (ofb->id == OVERLAY2)
+               ofb->control[1] |= OVL2C2_PFOR(pfor);
+
+       ofb->ops->setup(ofb);
+       ofb->ops->enable(ofb);
+       return 0;
+}
+
+static struct fb_ops overlay_fb_ops = {
+       .owner                  = THIS_MODULE,
+       .fb_open                = overlayfb_open,
+       .fb_release             = overlayfb_release,
+       .fb_check_var           = overlayfb_check_var,
+       .fb_set_par             = overlayfb_set_par,
+};
+
+static void __devinit init_pxafb_overlay(struct pxafb_info *fbi,
+                                        struct pxafb_layer *ofb, int id)
+{
+       sprintf(ofb->fb.fix.id, "overlay%d", id + 1);
+
+       ofb->fb.fix.type                = FB_TYPE_PACKED_PIXELS;
+       ofb->fb.fix.xpanstep            = 0;
+       ofb->fb.fix.ypanstep            = 1;
+
+       ofb->fb.var.activate            = FB_ACTIVATE_NOW;
+       ofb->fb.var.height              = -1;
+       ofb->fb.var.width               = -1;
+       ofb->fb.var.vmode               = FB_VMODE_NONINTERLACED;
+
+       ofb->fb.fbops                   = &overlay_fb_ops;
+       ofb->fb.flags                   = FBINFO_FLAG_DEFAULT;
+       ofb->fb.node                    = -1;
+       ofb->fb.pseudo_palette          = NULL;
+
+       ofb->id = id;
+       ofb->ops = &ofb_ops[id];
+       atomic_set(&ofb->usage, 0);
+       ofb->fbi = fbi;
+       init_completion(&ofb->branch_done);
+}
+
+static int __devinit pxafb_overlay_init(struct pxafb_info *fbi)
+{
+       int i, ret;
+
+       for (i = 0; i < 2; i++) {
+               init_pxafb_overlay(fbi, &fbi->overlay[i], i);
+               ret = register_framebuffer(&fbi->overlay[i].fb);
+               if (ret) {
+                       dev_err(fbi->dev, "failed to register overlay %d\n", i);
+                       return ret;
+               }
+       }
+
+       /* mask all IU/BS/EOF/SOF interrupts */
+       lcd_writel(fbi, LCCR5, ~0);
+
+       /* place overlay(s) on top of base */
+       fbi->lccr0 |= LCCR0_OUC;
+       pr_info("PXA Overlay driver loaded successfully!\n");
+       return 0;
+}
+
+static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi)
+{
+       int i;
+
+       for (i = 0; i < 2; i++)
+               unregister_framebuffer(&fbi->overlay[i].fb);
+}
+#else
+static inline void pxafb_overlay_init(struct pxafb_info *fbi) {}
+static inline void pxafb_overlay_exit(struct pxafb_info *fbi) {}
+#endif /* CONFIG_FB_PXA_OVERLAY */
+
 /*
  * Calculate the PCD value from the clock rate (in picoseconds).
  * We take account of the PPCR clock setting.
@@ -607,22 +996,22 @@ unsigned long pxafb_get_hsync_time(struct device *dev)
 EXPORT_SYMBOL(pxafb_get_hsync_time);
 
 static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
-               unsigned int offset, size_t size)
+                          unsigned long start, size_t size)
 {
        struct pxafb_dma_descriptor *dma_desc, *pal_desc;
        unsigned int dma_desc_off, pal_desc_off;
 
-       if (dma < 0 || dma >= DMA_MAX)
+       if (dma < 0 || dma >= DMA_MAX * 2)
                return -EINVAL;
 
        dma_desc = &fbi->dma_buff->dma_desc[dma];
        dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]);
 
-       dma_desc->fsadr = fbi->screen_dma + offset;
+       dma_desc->fsadr = start;
        dma_desc->fidr  = 0;
        dma_desc->ldcmd = size;
 
-       if (pal < 0 || pal >= PAL_MAX) {
+       if (pal < 0 || pal >= PAL_MAX * 2) {
                dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
                fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
        } else {
@@ -648,6 +1037,27 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
        return 0;
 }
 
+static void setup_base_frame(struct pxafb_info *fbi, int branch)
+{
+       struct fb_var_screeninfo *var = &fbi->fb.var;
+       struct fb_fix_screeninfo *fix = &fbi->fb.fix;
+       int nbytes, dma, pal, bpp = var->bits_per_pixel;
+       unsigned long offset;
+
+       dma = DMA_BASE + (branch ? DMA_MAX : 0);
+       pal = (bpp >= 16) ? PAL_NONE : PAL_BASE + (branch ? PAL_MAX : 0);
+
+       nbytes = fix->line_length * var->yres;
+       offset = fix->line_length * var->yoffset + fbi->video_mem_phys;
+
+       if (fbi->lccr0 & LCCR0_SDS) {
+               nbytes = nbytes / 2;
+               setup_frame_dma(fbi, dma + 1, PAL_NONE, offset + nbytes, nbytes);
+       }
+
+       setup_frame_dma(fbi, dma, pal, offset, nbytes);
+}
+
 #ifdef CONFIG_FB_PXA_SMARTPANEL
 static int setup_smart_dma(struct pxafb_info *fbi)
 {
@@ -701,6 +1111,7 @@ int pxafb_smart_flush(struct fb_info *info)
        lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
        lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
        lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+       lcd_writel(fbi, LCCR4, fbi->reg_lccr4);
        lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
        lcd_writel(fbi, FDADR6, fbi->fdadr[6]);
 
@@ -727,12 +1138,19 @@ int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
        int i;
        struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
 
-       /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */
-       for (i = 0; i < n_cmds; i++) {
+       for (i = 0; i < n_cmds; i++, cmds++) {
+               /* if it is a software delay, flush and delay */
+               if ((*cmds & 0xff00) == SMART_CMD_DELAY) {
+                       pxafb_smart_flush(info);
+                       mdelay(*cmds & 0xff);
+                       continue;
+               }
+
+               /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */
                if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8)
                        pxafb_smart_flush(info);
 
-               fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds++;
+               fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds;
        }
 
        return 0;
@@ -764,7 +1182,9 @@ static void setup_smart_timing(struct pxafb_info *fbi,
                LCCR1_HorSnchWdth(__smart_timing(t3, lclk));
 
        fbi->reg_lccr2 = LCCR2_DisHght(var->yres);
-       fbi->reg_lccr3 = LCCR3_PixClkDiv(__smart_timing(t4, lclk));
+       fbi->reg_lccr3 = fbi->lccr3 | LCCR3_PixClkDiv(__smart_timing(t4, lclk));
+       fbi->reg_lccr3 |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? LCCR3_HSP : 0;
+       fbi->reg_lccr3 |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? LCCR3_VSP : 0;
 
        /* FIXME: make this configurable */
        fbi->reg_cmdcr = 1;
@@ -789,11 +1209,15 @@ static int pxafb_smart_thread(void *arg)
                if (try_to_freeze())
                        continue;
 
+               mutex_lock(&fbi->ctrlr_lock);
+
                if (fbi->state == C_ENABLE) {
                        inf->smart_update(&fbi->fb);
                        complete(&fbi->refresh_done);
                }
 
+               mutex_unlock(&fbi->ctrlr_lock);
+
                set_current_state(TASK_INTERRUPTIBLE);
                schedule_timeout(30 * HZ / 1000);
        }
@@ -804,16 +1228,22 @@ static int pxafb_smart_thread(void *arg)
 
 static int pxafb_smart_init(struct pxafb_info *fbi)
 {
-       if (!(fbi->lccr0 | LCCR0_LCDT))
+       if (!(fbi->lccr0 & LCCR0_LCDT))
                return 0;
 
+       fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
+       fbi->n_smart_cmds = 0;
+
+       init_completion(&fbi->command_done);
+       init_completion(&fbi->refresh_done);
+
        fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi,
                                        "lcd_refresh");
        if (IS_ERR(fbi->smart_thread)) {
-               printk(KERN_ERR "%s: unable to create kernel thread\n",
-                               __func__);
+               pr_err("%s: unable to create kernel thread\n", __func__);
                return PTR_ERR(fbi->smart_thread);
        }
+
        return 0;
 }
 #else
@@ -826,7 +1256,9 @@ int pxafb_smart_flush(struct fb_info *info)
 {
        return 0;
 }
-#endif /* CONFIG_FB_SMART_PANEL */
+
+static inline int pxafb_smart_init(struct pxafb_info *fbi) { return 0; }
+#endif /* CONFIG_FB_PXA_SMARTPANEL */
 
 static void setup_parallel_timing(struct pxafb_info *fbi,
                                  struct fb_var_screeninfo *var)
@@ -874,51 +1306,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
                              struct pxafb_info *fbi)
 {
        u_long flags;
-       size_t nbytes;
-
-#if DEBUG_VAR
-       if (!(fbi->lccr0 & LCCR0_LCDT)) {
-               if (var->xres < 16 || var->xres > 1024)
-                       printk(KERN_ERR "%s: invalid xres %d\n",
-                               fbi->fb.fix.id, var->xres);
-               switch (var->bits_per_pixel) {
-               case 1:
-               case 2:
-               case 4:
-               case 8:
-               case 16:
-               case 24:
-               case 32:
-                       break;
-               default:
-                       printk(KERN_ERR "%s: invalid bit depth %d\n",
-                              fbi->fb.fix.id, var->bits_per_pixel);
-                       break;
-               }
 
-               if (var->hsync_len < 1 || var->hsync_len > 64)
-                       printk(KERN_ERR "%s: invalid hsync_len %d\n",
-                               fbi->fb.fix.id, var->hsync_len);
-               if (var->left_margin < 1 || var->left_margin > 255)
-                       printk(KERN_ERR "%s: invalid left_margin %d\n",
-                               fbi->fb.fix.id, var->left_margin);
-               if (var->right_margin < 1 || var->right_margin > 255)
-                       printk(KERN_ERR "%s: invalid right_margin %d\n",
-                               fbi->fb.fix.id, var->right_margin);
-               if (var->yres < 1 || var->yres > 1024)
-                       printk(KERN_ERR "%s: invalid yres %d\n",
-                               fbi->fb.fix.id, var->yres);
-               if (var->vsync_len < 1 || var->vsync_len > 64)
-                       printk(KERN_ERR "%s: invalid vsync_len %d\n",
-                               fbi->fb.fix.id, var->vsync_len);
-               if (var->upper_margin < 0 || var->upper_margin > 255)
-                       printk(KERN_ERR "%s: invalid upper_margin %d\n",
-                               fbi->fb.fix.id, var->upper_margin);
-               if (var->lower_margin < 0 || var->lower_margin > 255)
-                       printk(KERN_ERR "%s: invalid lower_margin %d\n",
-                               fbi->fb.fix.id, var->lower_margin);
-       }
-#endif
        /* Update shadow copy atomically */
        local_irq_save(flags);
 
@@ -929,23 +1317,13 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
 #endif
                setup_parallel_timing(fbi, var);
 
+       setup_base_frame(fbi, 0);
+
        fbi->reg_lccr0 = fbi->lccr0 |
                (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
                 LCCR0_QDM | LCCR0_BM  | LCCR0_OUM);
 
-       fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
-
-       nbytes = var->yres * fbi->fb.fix.line_length;
-
-       if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) {
-               nbytes = nbytes / 2;
-               setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes);
-       }
-
-       if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT))
-               setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes);
-       else
-               setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes);
+       fbi->reg_lccr3 |= pxafb_var_to_lccr3(var);
 
        fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK;
        fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
@@ -959,6 +1337,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
            (lcd_readl(fbi, LCCR1) != fbi->reg_lccr1) ||
            (lcd_readl(fbi, LCCR2) != fbi->reg_lccr2) ||
            (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
+           (lcd_readl(fbi, LCCR4) != fbi->reg_lccr4) ||
            (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
            (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
                pxafb_schedule_work(fbi, C_REENABLE);
@@ -976,67 +1355,16 @@ static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on)
 {
        pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff");
 
-       if (pxafb_backlight_power)
-               pxafb_backlight_power(on);
+       if (fbi->backlight_power)
+               fbi->backlight_power(on);
 }
 
 static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
 {
        pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff");
 
-       if (pxafb_lcd_power)
-               pxafb_lcd_power(on, &fbi->fb.var);
-}
-
-static void pxafb_setup_gpio(struct pxafb_info *fbi)
-{
-       int gpio, ldd_bits;
-       unsigned int lccr0 = fbi->lccr0;
-
-       /*
-        * setup is based on type of panel supported
-        */
-
-       /* 4 bit interface */
-       if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
-           (lccr0 & LCCR0_SDS) == LCCR0_Sngl &&
-           (lccr0 & LCCR0_DPD) == LCCR0_4PixMono)
-               ldd_bits = 4;
-
-       /* 8 bit interface */
-       else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
-                 ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
-                  (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
-                ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
-                 (lccr0 & LCCR0_PAS) == LCCR0_Pas &&
-                 (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
-               ldd_bits = 8;
-
-       /* 16 bit interface */
-       else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
-                ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
-                 (lccr0 & LCCR0_PAS) == LCCR0_Act))
-               ldd_bits = 16;
-
-       else {
-               printk(KERN_ERR "pxafb_setup_gpio: unable to determine "
-                              "bits per pixel\n");
-               return;
-       }
-
-       for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
-               pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
-       /* 18 bit interface */
-       if (fbi->fb.var.bits_per_pixel > 16) {
-               pxa_gpio_mode(86 | GPIO_ALT_FN_2_OUT);
-               pxa_gpio_mode(87 | GPIO_ALT_FN_2_OUT);
-       }
-       pxa_gpio_mode(GPIO74_LCD_FCLK_MD);
-       pxa_gpio_mode(GPIO75_LCD_LCLK_MD);
-       pxa_gpio_mode(GPIO76_LCD_PCLK_MD);
-
-       if ((lccr0 & LCCR0_PAS) == 0)
-               pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD);
+       if (fbi->lcd_power)
+               fbi->lcd_power(on, &fbi->fb.var);
 }
 
 static void pxafb_enable_controller(struct pxafb_info *fbi)
@@ -1056,6 +1384,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
                return;
 
        /* Sequence from 11.7.10 */
+       lcd_writel(fbi, LCCR4, fbi->reg_lccr4);
        lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
        lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
        lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
@@ -1097,8 +1426,9 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
 static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
 {
        struct pxafb_info *fbi = dev_id;
-       unsigned int lccr0, lcsr = lcd_readl(fbi, LCSR);
+       unsigned int lccr0, lcsr, lcsr1;
 
+       lcsr = lcd_readl(fbi, LCSR);
        if (lcsr & LCSR_LDD) {
                lccr0 = lcd_readl(fbi, LCCR0);
                lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM);
@@ -1109,8 +1439,18 @@ static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
        if (lcsr & LCSR_CMD_INT)
                complete(&fbi->command_done);
 #endif
-
        lcd_writel(fbi, LCSR, lcsr);
+
+#ifdef CONFIG_FB_PXA_OVERLAY
+       lcsr1 = lcd_readl(fbi, LCSR1);
+       if (lcsr1 & LCSR1_BS(1))
+               complete(&fbi->overlay[0].branch_done);
+
+       if (lcsr1 & LCSR1_BS(2))
+               complete(&fbi->overlay[1].branch_done);
+
+       lcd_writel(fbi, LCSR1, lcsr1);
+#endif
        return IRQ_HANDLED;
 }
 
@@ -1181,7 +1521,6 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
                if (old_state == C_ENABLE) {
                        __pxafb_lcd_power(fbi, 0);
                        pxafb_disable_controller(fbi);
-                       pxafb_setup_gpio(fbi);
                        pxafb_enable_controller(fbi);
                        __pxafb_lcd_power(fbi, 1);
                }
@@ -1204,7 +1543,6 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
                 */
                if (old_state != C_ENABLE) {
                        fbi->state = C_ENABLE;
-                       pxafb_setup_gpio(fbi);
                        pxafb_enable_controller(fbi);
                        __pxafb_lcd_power(fbi, 1);
                        __pxafb_backlight_power(fbi, 1);
@@ -1303,77 +1641,34 @@ static int pxafb_resume(struct platform_device *dev)
 #define pxafb_resume   NULL
 #endif
 
-/*
- * pxafb_map_video_memory():
- *      Allocates the DRAM memory for the frame buffer.  This buffer is
- *     remapped into a non-cached, non-buffered, memory region to
- *      allow palette and pixel writes to occur without flushing the
- *      cache.  Once this area is remapped, all virtual memory
- *      access to the video memory should occur at the new region.
- */
-static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
+static int __devinit pxafb_init_video_memory(struct pxafb_info *fbi)
 {
-       /*
-        * We reserve one page for the palette, plus the size
-        * of the framebuffer.
-        */
-       fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
-       fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
-       fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
-                                             &fbi->map_dma, GFP_KERNEL);
-
-       if (fbi->map_cpu) {
-               /* prevent initial garbage on screen */
-               memset(fbi->map_cpu, 0, fbi->map_size);
-               fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
-               fbi->screen_dma = fbi->map_dma + fbi->video_offset;
-
-               /*
-                * FIXME: this is actually the wrong thing to place in
-                * smem_start.  But fbdev suffers from the problem that
-                * it needs an API which doesn't exist (in this case,
-                * dma_writecombine_mmap)
-                */
-               fbi->fb.fix.smem_start = fbi->screen_dma;
-               fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
-
-               fbi->dma_buff = (void *) fbi->map_cpu;
-               fbi->dma_buff_phys = fbi->map_dma;
-               fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
+       int size = PAGE_ALIGN(fbi->video_mem_size);
 
-               pr_debug("pxafb: palette_mem_size = 0x%08x\n", fbi->palette_size*sizeof(u16));
+       fbi->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
+       if (fbi->video_mem == NULL)
+               return -ENOMEM;
 
-#ifdef CONFIG_FB_PXA_SMARTPANEL
-               fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
-               fbi->n_smart_cmds = 0;
-#endif
-       }
-
-       return fbi->map_cpu ? 0 : -ENOMEM;
-}
+       fbi->video_mem_phys = virt_to_phys(fbi->video_mem);
+       fbi->video_mem_size = size;
 
-static void pxafb_decode_mode_info(struct pxafb_info *fbi,
-                                  struct pxafb_mode_info *modes,
-                                  unsigned int num_modes)
-{
-       unsigned int i, smemlen;
-
-       pxafb_setmode(&fbi->fb.var, &modes[0]);
+       fbi->fb.fix.smem_start  = fbi->video_mem_phys;
+       fbi->fb.fix.smem_len    = fbi->video_mem_size;
+       fbi->fb.screen_base     = fbi->video_mem;
 
-       for (i = 0; i < num_modes; i++) {
-               smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8;
-               if (smemlen > fbi->fb.fix.smem_len)
-                       fbi->fb.fix.smem_len = smemlen;
-       }
+       return fbi->video_mem ? 0 : -ENOMEM;
 }
 
 static void pxafb_decode_mach_info(struct pxafb_info *fbi,
                                   struct pxafb_mach_info *inf)
 {
        unsigned int lcd_conn = inf->lcd_conn;
+       struct pxafb_mode_info *m;
+       int i;
 
        fbi->cmap_inverse       = inf->cmap_inverse;
        fbi->cmap_static        = inf->cmap_static;
+       fbi->lccr4              = inf->lccr4;
 
        switch (lcd_conn & LCD_TYPE_MASK) {
        case LCD_TYPE_MONO_STN:
@@ -1398,7 +1693,6 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi,
                /* fall back to backward compatibility way */
                fbi->lccr0 = inf->lccr0;
                fbi->lccr3 = inf->lccr3;
-               fbi->lccr4 = inf->lccr4;
                goto decode_mode;
        }
 
@@ -1412,7 +1706,22 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi,
        fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL)  ? LCCR3_PCP : 0;
 
 decode_mode:
-       pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
+       pxafb_setmode(&fbi->fb.var, &inf->modes[0]);
+
+       /* decide video memory size as follows:
+        * 1. default to mode of maximum resolution
+        * 2. allow platform to override
+        * 3. allow module parameter to override
+        */
+       for (i = 0, m = &inf->modes[0]; i < inf->num_modes; i++, m++)
+               fbi->video_mem_size = max_t(size_t, fbi->video_mem_size,
+                               m->xres * m->yres * m->bpp / 8);
+
+       if (inf->video_mem_size > fbi->video_mem_size)
+               fbi->video_mem_size = inf->video_mem_size;
+
+       if (video_mem_size > fbi->video_mem_size)
+               fbi->video_mem_size = video_mem_size;
 }
 
 static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
@@ -1429,7 +1738,7 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
        memset(fbi, 0, sizeof(struct pxafb_info));
        fbi->dev = dev;
 
-       fbi->clk = clk_get(dev, "LCDCLK");
+       fbi->clk = clk_get(dev, NULL);
        if (IS_ERR(fbi->clk)) {
                kfree(fbi);
                return NULL;
@@ -1440,7 +1749,7 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
        fbi->fb.fix.type        = FB_TYPE_PACKED_PIXELS;
        fbi->fb.fix.type_aux    = 0;
        fbi->fb.fix.xpanstep    = 0;
-       fbi->fb.fix.ypanstep    = 0;
+       fbi->fb.fix.ypanstep    = 1;
        fbi->fb.fix.ywrapstep   = 0;
        fbi->fb.fix.accel       = FB_ACCEL_NONE;
 
@@ -1448,7 +1757,7 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
        fbi->fb.var.activate    = FB_ACTIVATE_NOW;
        fbi->fb.var.height      = -1;
        fbi->fb.var.width       = -1;
-       fbi->fb.var.accel_flags = 0;
+       fbi->fb.var.accel_flags = FB_ACCELF_TEXT;
        fbi->fb.var.vmode       = FB_VMODE_NONINTERLACED;
 
        fbi->fb.fbops           = &pxafb_ops;
@@ -1468,10 +1777,6 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
        INIT_WORK(&fbi->task, pxafb_task);
        mutex_init(&fbi->ctrlr_lock);
        init_completion(&fbi->disable_done);
-#ifdef CONFIG_FB_PXA_SMARTPANEL
-       init_completion(&fbi->command_done);
-       init_completion(&fbi->refresh_done);
-#endif
 
        return fbi;
 }
@@ -1544,7 +1849,9 @@ static int __devinit parse_opt(struct device *dev, char *this_opt)
 
        s[0] = '\0';
 
-       if (!strncmp(this_opt, "mode:", 5)) {
+       if (!strncmp(this_opt, "vmem:", 5)) {
+               video_mem_size = memparse(this_opt + 5, NULL);
+       } else if (!strncmp(this_opt, "mode:", 5)) {
                return parse_opt_mode(dev, this_opt);
        } else if (!strncmp(this_opt, "pixclock:", 9)) {
                mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
@@ -1748,8 +2055,7 @@ static int __devinit pxafb_probe(struct platform_device *dev)
                ret = -EINVAL;
                goto failed;
        }
-       pxafb_backlight_power = inf->pxafb_backlight_power;
-       pxafb_lcd_power = inf->pxafb_lcd_power;
+
        fbi = pxafb_init_fbinfo(&dev->dev);
        if (!fbi) {
                /* only reason for pxafb_init_fbinfo to fail is kmalloc */
@@ -1758,6 +2064,9 @@ static int __devinit pxafb_probe(struct platform_device *dev)
                goto failed;
        }
 
+       fbi->backlight_power = inf->pxafb_backlight_power;
+       fbi->lcd_power = inf->pxafb_lcd_power;
+
        r = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&dev->dev, "no I/O memory resource defined\n");
@@ -1779,12 +2088,20 @@ static int __devinit pxafb_probe(struct platform_device *dev)
                goto failed_free_res;
        }
 
-       /* Initialize video memory */
-       ret = pxafb_map_video_memory(fbi);
+       fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
+       fbi->dma_buff = dma_alloc_coherent(fbi->dev, fbi->dma_buff_size,
+                               &fbi->dma_buff_phys, GFP_KERNEL);
+       if (fbi->dma_buff == NULL) {
+               dev_err(&dev->dev, "failed to allocate memory for DMA\n");
+               ret = -ENOMEM;
+               goto failed_free_io;
+       }
+
+       ret = pxafb_init_video_memory(fbi);
        if (ret) {
                dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
                ret = -ENOMEM;
-               goto failed_free_io;
+               goto failed_free_dma;
        }
 
        irq = platform_get_irq(dev, 0);
@@ -1801,13 +2118,12 @@ static int __devinit pxafb_probe(struct platform_device *dev)
                goto failed_free_mem;
        }
 
-#ifdef CONFIG_FB_PXA_SMARTPANEL
        ret = pxafb_smart_init(fbi);
        if (ret) {
                dev_err(&dev->dev, "failed to initialize smartpanel\n");
                goto failed_free_irq;
        }
-#endif
+
        /*
         * This makes sure that our colour bitfield
         * descriptors are correctly initialised.
@@ -1833,6 +2149,8 @@ static int __devinit pxafb_probe(struct platform_device *dev)
                goto failed_free_cmap;
        }
 
+       pxafb_overlay_init(fbi);
+
 #ifdef CONFIG_CPU_FREQ
        fbi->freq_transition.notifier_call = pxafb_freq_transition;
        fbi->freq_policy.notifier_call = pxafb_freq_policy;
@@ -1855,8 +2173,10 @@ failed_free_cmap:
 failed_free_irq:
        free_irq(irq, fbi);
 failed_free_mem:
-       dma_free_writecombine(&dev->dev, fbi->map_size,
-                       fbi->map_cpu, fbi->map_dma);
+       free_pages_exact(fbi->video_mem, fbi->video_mem_size);
+failed_free_dma:
+       dma_free_coherent(&dev->dev, fbi->dma_buff_size,
+                       fbi->dma_buff, fbi->dma_buff_phys);
 failed_free_io:
        iounmap(fbi->mmio_base);
 failed_free_res:
@@ -1881,6 +2201,7 @@ static int __devexit pxafb_remove(struct platform_device *dev)
 
        info = &fbi->fb;
 
+       pxafb_overlay_exit(fbi);
        unregister_framebuffer(info);
 
        pxafb_disable_controller(fbi);
@@ -1891,8 +2212,10 @@ static int __devexit pxafb_remove(struct platform_device *dev)
        irq = platform_get_irq(dev, 0);
        free_irq(irq, fbi);
 
-       dma_free_writecombine(&dev->dev, fbi->map_size,
-                                       fbi->map_cpu, fbi->map_dma);
+       free_pages_exact(fbi->video_mem, fbi->video_mem_size);
+
+       dma_free_writecombine(&dev->dev, fbi->dma_buff_size,
+                       fbi->dma_buff, fbi->dma_buff_phys);
 
        iounmap(fbi->mmio_base);
 
index 31541b86f13d2d0e509fb9649342fbcb7b666126..2353521c5c8ca188108892203b330dacdc79e40c 100644 (file)
@@ -54,11 +54,55 @@ enum {
 #define PALETTE_SIZE   (256 * 4)
 #define CMD_BUFF_SIZE  (1024 * 50)
 
+/* NOTE: the palette and frame dma descriptors are doubled to allow
+ * the 2nd set for branch settings (FBRx)
+ */
 struct pxafb_dma_buff {
        unsigned char palette[PAL_MAX * PALETTE_SIZE];
        uint16_t cmd_buff[CMD_BUFF_SIZE];
-       struct pxafb_dma_descriptor pal_desc[PAL_MAX];
-       struct pxafb_dma_descriptor dma_desc[DMA_MAX];
+       struct pxafb_dma_descriptor pal_desc[PAL_MAX * 2];
+       struct pxafb_dma_descriptor dma_desc[DMA_MAX * 2];
+};
+
+enum {
+       OVERLAY1,
+       OVERLAY2,
+};
+
+enum {
+       OVERLAY_FORMAT_RGB = 0,
+       OVERLAY_FORMAT_YUV444_PACKED,
+       OVERLAY_FORMAT_YUV444_PLANAR,
+       OVERLAY_FORMAT_YUV422_PLANAR,
+       OVERLAY_FORMAT_YUV420_PLANAR,
+};
+
+#define NONSTD_TO_XPOS(x)      (((x) >> 0)  & 0x3ff)
+#define NONSTD_TO_YPOS(x)      (((x) >> 10) & 0x3ff)
+#define NONSTD_TO_PFOR(x)      (((x) >> 20) & 0x7)
+
+struct pxafb_layer;
+
+struct pxafb_layer_ops {
+       void (*enable)(struct pxafb_layer *);
+       void (*disable)(struct pxafb_layer *);
+       void (*setup)(struct pxafb_layer *);
+};
+
+struct pxafb_layer {
+       struct fb_info          fb;
+       int                     id;
+       atomic_t                usage;
+       uint32_t                control[2];
+
+       struct pxafb_layer_ops  *ops;
+
+       void __iomem            *video_mem;
+       unsigned long           video_mem_phys;
+       size_t                  video_mem_size;
+       struct completion       branch_done;
+
+       struct pxafb_info       *fbi;
 };
 
 struct pxafb_info {
@@ -69,24 +113,15 @@ struct pxafb_info {
        void __iomem            *mmio_base;
 
        struct pxafb_dma_buff   *dma_buff;
+       size_t                  dma_buff_size;
        dma_addr_t              dma_buff_phys;
-       dma_addr_t              fdadr[DMA_MAX];
-
-       /*
-        * These are the addresses we mapped
-        * the framebuffer memory region to.
-        */
-       /* raw memory addresses */
-       dma_addr_t              map_dma;        /* physical */
-       u_char *                map_cpu;        /* virtual */
-       u_int                   map_size;
-
-       /* addresses of pieces placed in raw buffer */
-       u_char *                screen_cpu;     /* virtual address of frame buffer */
-       dma_addr_t              screen_dma;     /* physical address of frame buffer */
+       dma_addr_t              fdadr[DMA_MAX * 2];
+
+       void __iomem            *video_mem;     /* virtual address of frame buffer */
+       unsigned long           video_mem_phys; /* physical address of frame buffer */
+       size_t                  video_mem_size; /* size of the frame buffer */
        u16 *                   palette_cpu;    /* virtual address of palette memory */
        u_int                   palette_size;
-       ssize_t                 video_offset;
 
        u_int                   lccr0;
        u_int                   lccr3;
@@ -120,10 +155,17 @@ struct pxafb_info {
        struct task_struct      *smart_thread;
 #endif
 
+#ifdef CONFIG_FB_PXA_OVERLAY
+       struct pxafb_layer      overlay[2];
+#endif
+
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block   freq_transition;
        struct notifier_block   freq_policy;
 #endif
+
+       void (*lcd_power)(int, struct fb_var_screeninfo *);
+       void (*backlight_power)(int);
 };
 
 #define TO_INF(ptr,member) container_of(ptr,struct pxafb_info,member)
@@ -148,4 +190,10 @@ struct pxafb_info {
 #define MIN_XRES       64
 #define MIN_YRES       64
 
+/* maximum X and Y resolutions - note these are limits from the register
+ * bits length instead of the real ones
+ */
+#define MAX_XRES       1024
+#define MAX_YRES       1024
+
 #endif /* __PXAFB_H__ */
index c052bd4c0b0676c7d843ec5d465afed6fb56d1c8..076f946fa0f544dc611ff69d08be2ff3425e8ba2 100644 (file)
  *     - convert dma address types to dma_addr_t
  *     - remove unused 'montype' stuff
  *     - remove redundant zero inits of init_var after the initial
- *       memzero.
+ *       memset.
  *     - remove allow_modeset (acornfb idea does not belong here)
  *
  * 2001/05/28: <rmk@arm.linux.org.uk>
index 5b78fd0aff0a6d50306c75f80d99f52f97dbe99e..018c070a357f8138852a41fe4ec46d8cc4cf2f98 100644 (file)
@@ -176,7 +176,7 @@ int register_virtio_device(struct virtio_device *dev)
 
        /* Assign a unique device index and hence name. */
        dev->index = dev_index++;
-       sprintf(dev->dev.bus_id, "virtio%u", dev->index);
+       dev_set_name(&dev->dev, "virtio%u", dev->index);
 
        /* We always start by resetting the device, in case a previous
         * driver messed it up.  This also tests that code path a little. */
index 62eab43152d21314826838080caed9ad3ee3eb1e..59268266b79a5b7c6b439c6e9b210bb25c4236a3 100644 (file)
@@ -56,6 +56,15 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+static u32 page_to_balloon_pfn(struct page *page)
+{
+       unsigned long pfn = page_to_pfn(page);
+
+       BUILD_BUG_ON(PAGE_SHIFT < VIRTIO_BALLOON_PFN_SHIFT);
+       /* Convert pfn from Linux page size to balloon page size. */
+       return pfn >> (PAGE_SHIFT - VIRTIO_BALLOON_PFN_SHIFT);
+}
+
 static void balloon_ack(struct virtqueue *vq)
 {
        struct virtio_balloon *vb;
@@ -99,7 +108,7 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num)
                        msleep(200);
                        break;
                }
-               vb->pfns[vb->num_pfns] = page_to_pfn(page);
+               vb->pfns[vb->num_pfns] = page_to_balloon_pfn(page);
                totalram_pages--;
                vb->num_pages++;
                list_add(&page->lru, &vb->pages);
@@ -132,7 +141,7 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
        for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
                page = list_first_entry(&vb->pages, struct page, lru);
                list_del(&page->lru);
-               vb->pfns[vb->num_pfns] = page_to_pfn(page);
+               vb->pfns[vb->num_pfns] = page_to_balloon_pfn(page);
                vb->num_pages--;
        }
 
index c7dc37c7cce91592326fff43187097ae4049ed33..265fdf2d1276f41884366179eaea1fbceaa153a7 100644 (file)
@@ -75,7 +75,7 @@ MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
  * would make more sense for virtio to not insist on having it's own device. */
 static struct device virtio_pci_root = {
        .parent         = NULL,
-       .bus_id         = "virtio-pci",
+       .init_name      = "virtio-pci",
 };
 
 /* Convert a generic virtio device to our structure */
@@ -216,7 +216,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
        struct virtio_pci_device *vp_dev = to_vp_device(vdev);
        struct virtio_pci_vq_info *info;
        struct virtqueue *vq;
-       unsigned long flags;
+       unsigned long flags, size;
        u16 num;
        int err;
 
@@ -237,19 +237,20 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
        info->queue_index = index;
        info->num = num;
 
-       info->queue = kzalloc(PAGE_ALIGN(vring_size(num,PAGE_SIZE)), GFP_KERNEL);
+       size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
+       info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
        if (info->queue == NULL) {
                err = -ENOMEM;
                goto out_info;
        }
 
        /* activate the queue */
-       iowrite32(virt_to_phys(info->queue) >> PAGE_SHIFT,
+       iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,
                  vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 
        /* create the vring */
-       vq = vring_new_virtqueue(info->num, vdev, info->queue,
-                                vp_notify, callback);
+       vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN,
+                                vdev, info->queue, vp_notify, callback);
        if (!vq) {
                err = -ENOMEM;
                goto out_activate_queue;
@@ -266,7 +267,7 @@ static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
 
 out_activate_queue:
        iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
-       kfree(info->queue);
+       free_pages_exact(info->queue, size);
 out_info:
        kfree(info);
        return ERR_PTR(err);
@@ -277,7 +278,7 @@ static void vp_del_vq(struct virtqueue *vq)
 {
        struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
        struct virtio_pci_vq_info *info = vq->priv;
-       unsigned long flags;
+       unsigned long flags, size;
 
        spin_lock_irqsave(&vp_dev->lock, flags);
        list_del(&info->node);
@@ -289,7 +290,8 @@ static void vp_del_vq(struct virtqueue *vq)
        iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
        iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
 
-       kfree(info->queue);
+       size = PAGE_ALIGN(vring_size(info->num, VIRTIO_PCI_VRING_ALIGN));
+       free_pages_exact(info->queue, size);
        kfree(info);
 }
 
@@ -305,6 +307,20 @@ static struct virtio_config_ops virtio_pci_config_ops = {
        .finalize_features = vp_finalize_features,
 };
 
+static void virtio_pci_release_dev(struct device *_d)
+{
+       struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
+       struct virtio_pci_device *vp_dev = to_vp_device(dev);
+       struct pci_dev *pci_dev = vp_dev->pci_dev;
+
+       free_irq(pci_dev->irq, vp_dev);
+       pci_set_drvdata(pci_dev, NULL);
+       pci_iounmap(pci_dev, vp_dev->ioaddr);
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+       kfree(vp_dev);
+}
+
 /* the PCI probing function */
 static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
                                      const struct pci_device_id *id)
@@ -328,6 +344,7 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
                return -ENOMEM;
 
        vp_dev->vdev.dev.parent = &virtio_pci_root;
+       vp_dev->vdev.dev.release = virtio_pci_release_dev;
        vp_dev->vdev.config = &virtio_pci_config_ops;
        vp_dev->pci_dev = pci_dev;
        INIT_LIST_HEAD(&vp_dev->virtqueues);
@@ -357,7 +374,7 @@ static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
 
        /* register a handler for the queue with the PCI device's interrupt */
        err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
-                         vp_dev->vdev.dev.bus_id, vp_dev);
+                         dev_name(&vp_dev->vdev.dev), vp_dev);
        if (err)
                goto out_set_drvdata;
 
@@ -387,12 +404,6 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
        struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
 
        unregister_virtio_device(&vp_dev->vdev);
-       free_irq(pci_dev->irq, vp_dev);
-       pci_set_drvdata(pci_dev, NULL);
-       pci_iounmap(pci_dev, vp_dev->ioaddr);
-       pci_release_regions(pci_dev);
-       pci_disable_device(pci_dev);
-       kfree(vp_dev);
 }
 
 #ifdef CONFIG_PM
index 6eb5303fed11b20613083ed960aa27cb8e2d4bd9..5777196bf6c9cc873ef07dd6e79eb10f1775379b 100644 (file)
@@ -274,6 +274,7 @@ static struct virtqueue_ops vring_vq_ops = {
 };
 
 struct virtqueue *vring_new_virtqueue(unsigned int num,
+                                     unsigned int vring_align,
                                      struct virtio_device *vdev,
                                      void *pages,
                                      void (*notify)(struct virtqueue *),
@@ -292,7 +293,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
        if (!vq)
                return NULL;
 
-       vring_init(&vq->vring, num, pages, PAGE_SIZE);
+       vring_init(&vq->vring, num, pages, vring_align);
        vq->vq.callback = callback;
        vq->vq.vdev = vdev;
        vq->vq.vq_ops = &vring_vq_ops;
index f7f6ce82a5e251d8e088f7500af6394f778bbd91..e31925ee83462774ff573d4d4ae1d8d2ff538858 100644 (file)
@@ -42,7 +42,7 @@
 #undef S3C_VA_WATCHDOG
 #define S3C_VA_WATCHDOG (0)
 
-#include <asm/plat-s3c/regs-watchdog.h>
+#include <plat/regs-watchdog.h>
 
 #define PFX "s3c2410-wdt: "
 
index ed01e4c2beff7bfb70c9b848e91e027c15a7a901..e19b4579471762d5f055e0eebaa99d6589d1398a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/uaccess.h>
+#include <linux/timex.h>
 
 #ifdef CONFIG_ARCH_PXA
 #include <mach/pxa-regs.h>
@@ -35,8 +36,7 @@
 #include <mach/reset.h>
 #include <mach/hardware.h>
 
-#define OSCR_FREQ              CLOCK_TICK_RATE
-
+static unsigned long oscr_freq;
 static unsigned long sa1100wdt_users;
 static int pre_margin;
 static int boot_status;
@@ -123,12 +123,12 @@ static long sa1100dog_ioctl(struct file *file, unsigned int cmd,
                        break;
                }
 
-               pre_margin = OSCR_FREQ * time;
+               pre_margin = oscr_freq * time;
                OSMR3 = OSCR + pre_margin;
                /*fall through*/
 
        case WDIOC_GETTIMEOUT:
-               ret = put_user(pre_margin / OSCR_FREQ, p);
+               ret = put_user(pre_margin / oscr_freq, p);
                break;
        }
        return ret;
@@ -155,6 +155,8 @@ static int __init sa1100dog_init(void)
 {
        int ret;
 
+       oscr_freq = get_clock_tick_rate();
+
        /*
         * Read the reset status, and save it for later.  If
         * we suspend, RCSR will be cleared, and the watchdog
@@ -162,7 +164,7 @@ static int __init sa1100dog_init(void)
         */
        boot_status = (reset_status & RESET_STATUS_WATCHDOG) ?
                                WDIOF_CARDRESET : 0;
-       pre_margin = OSCR_FREQ * margin;
+       pre_margin = oscr_freq * margin;
 
        ret = misc_register(&sa1100dog_miscdev);
        if (ret == 0)
index 1e3b934a4cf707cbe06084f21efb39874d4802f4..46625cd38743c2506e1fc024c8e1c4d434a4fa26 100644 (file)
@@ -141,8 +141,12 @@ static void init_evtchn_cpu_bindings(void)
        int i;
 
        /* By default all event channels notify CPU#0. */
-       for_each_irq_desc(i, desc)
+       for_each_irq_desc(i, desc) {
+               if (!desc)
+                       continue;
+
                desc->affinity = cpumask_of_cpu(0);
+       }
 #endif
 
        memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
@@ -229,15 +233,20 @@ static void unmask_evtchn(int port)
 static int find_unbound_irq(void)
 {
        int irq;
+       struct irq_desc *desc;
 
        /* Only allocate from dynirq range */
-       for_each_irq_nr(irq)
+       for (irq = 0; irq < nr_irqs; irq++)
                if (irq_bindcount[irq] == 0)
                        break;
 
        if (irq == nr_irqs)
                panic("No available IRQ to bind to: increase nr_irqs!\n");
 
+       desc = irq_to_desc_alloc_cpu(irq, 0);
+       if (WARN_ON(desc == NULL))
+               return -1;
+
        return irq;
 }
 
@@ -792,7 +801,7 @@ void xen_irq_resume(void)
                mask_evtchn(evtchn);
 
        /* No IRQ <-> event-channel mappings. */
-       for_each_irq_nr(irq)
+       for (irq = 0; irq < nr_irqs; irq++)
                irq_info[irq].evtchn = 0; /* zap event-channel binding */
 
        for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
@@ -824,7 +833,7 @@ void __init xen_init_IRQ(void)
                mask_evtchn(i);
 
        /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-       for_each_irq_nr(i)
+       for (i = 0; i < nr_irqs; i++)
                irq_bindcount[i] = 0;
 
        irq_ctx_init(smp_processor_id());
index 4993a4b3d8ab5d68c2277f8eb580740deee85b50..6968388818be797e34f4c49c5ce879fd5a262698 100644 (file)
@@ -150,27 +150,15 @@ $(patsubst %,$(obj)/%.gen.o, $(fw-external-y)): $(obj)/%.gen.o: $(fwdir)/%
 $(obj)/%: $(obj)/%.ihex | $(objtree)/$(obj)/$$(dir %)
        $(call cmd,ihex)
 
-# Don't depend on ihex2fw if we're installing and it already exists.
-# Putting it after | in the dependencies doesn't seem sufficient when
-# we're installing after a cross-compile, because ihex2fw has dependencies
-# on stuff like /usr/lib/gcc/ppc64-redhat-linux/4.3.0/include/stddef.h and 
-# thus wants to be rebuilt. Which it can't be, if the prebuilt kernel tree
-# is exported read-only for someone to run 'make install'.
-ifeq ($(INSTALL):$(wildcard $(obj)/ihex2fw),install:$(obj)/ihex2fw)
-ihex2fw_dep :=
-else
-ihex2fw_dep := $(obj)/ihex2fw
-endif
-
 # .HEX is also Intel HEX, but where the offset and length in each record
 # is actually meaningful, because the firmware has to be loaded in a certain
 # order rather than as a single binary blob. Thus, we convert them into our
 # more compact binary representation of ihex records (<linux/ihex.h>)
-$(obj)/%.fw: $(obj)/%.HEX $(ihex2fw_dep) | $(objtree)/$(obj)/$$(dir %)
+$(obj)/%.fw: $(obj)/%.HEX $(obj)/ihex2fw | $(objtree)/$(obj)/$$(dir %)
        $(call cmd,ihex2fw)
 
 # .H16 is our own modified form of Intel HEX, with 16-bit length for records.
-$(obj)/%.fw: $(obj)/%.H16 $(ihex2fw_dep) | $(objtree)/$(obj)/$$(dir %)
+$(obj)/%.fw: $(obj)/%.H16 $(obj)/ihex2fw | $(objtree)/$(obj)/$$(dir %)
        $(call cmd,h16tofw)
 
 $(firmware-dirs):
index f658441d5666c9d108f8ec337b2e0909686723bb..d6f89d3c15e80f0ebd15699e62959712fad4b7bc 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -191,6 +191,20 @@ static int aio_setup_ring(struct kioctx *ctx)
        kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK), km); \
 } while(0)
 
+static void ctx_rcu_free(struct rcu_head *head)
+{
+       struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
+       unsigned nr_events = ctx->max_reqs;
+
+       kmem_cache_free(kioctx_cachep, ctx);
+
+       if (nr_events) {
+               spin_lock(&aio_nr_lock);
+               BUG_ON(aio_nr - nr_events > aio_nr);
+               aio_nr -= nr_events;
+               spin_unlock(&aio_nr_lock);
+       }
+}
 
 /* __put_ioctx
  *     Called when the last user of an aio context has gone away,
@@ -198,8 +212,6 @@ static int aio_setup_ring(struct kioctx *ctx)
  */
 static void __put_ioctx(struct kioctx *ctx)
 {
-       unsigned nr_events = ctx->max_reqs;
-
        BUG_ON(ctx->reqs_active);
 
        cancel_delayed_work(&ctx->wq);
@@ -208,14 +220,7 @@ static void __put_ioctx(struct kioctx *ctx)
        mmdrop(ctx->mm);
        ctx->mm = NULL;
        pr_debug("__put_ioctx: freeing %p\n", ctx);
-       kmem_cache_free(kioctx_cachep, ctx);
-
-       if (nr_events) {
-               spin_lock(&aio_nr_lock);
-               BUG_ON(aio_nr - nr_events > aio_nr);
-               aio_nr -= nr_events;
-               spin_unlock(&aio_nr_lock);
-       }
+       call_rcu(&ctx->rcu_head, ctx_rcu_free);
 }
 
 #define get_ioctx(kioctx) do {                                         \
@@ -235,6 +240,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
 {
        struct mm_struct *mm;
        struct kioctx *ctx;
+       int did_sync = 0;
 
        /* Prevent overflows */
        if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
@@ -267,21 +273,30 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
                goto out_freectx;
 
        /* limit the number of system wide aios */
-       spin_lock(&aio_nr_lock);
-       if (aio_nr + ctx->max_reqs > aio_max_nr ||
-           aio_nr + ctx->max_reqs < aio_nr)
-               ctx->max_reqs = 0;
-       else
-               aio_nr += ctx->max_reqs;
-       spin_unlock(&aio_nr_lock);
+       do {
+               spin_lock_bh(&aio_nr_lock);
+               if (aio_nr + nr_events > aio_max_nr ||
+                   aio_nr + nr_events < aio_nr)
+                       ctx->max_reqs = 0;
+               else
+                       aio_nr += ctx->max_reqs;
+               spin_unlock_bh(&aio_nr_lock);
+               if (ctx->max_reqs || did_sync)
+                       break;
+
+               /* wait for rcu callbacks to have completed before giving up */
+               synchronize_rcu();
+               did_sync = 1;
+               ctx->max_reqs = nr_events;
+       } while (1);
+
        if (ctx->max_reqs == 0)
                goto out_cleanup;
 
        /* now link into global list. */
-       write_lock(&mm->ioctx_list_lock);
-       ctx->next = mm->ioctx_list;
-       mm->ioctx_list = ctx;
-       write_unlock(&mm->ioctx_list_lock);
+       spin_lock(&mm->ioctx_lock);
+       hlist_add_head_rcu(&ctx->list, &mm->ioctx_list);
+       spin_unlock(&mm->ioctx_lock);
 
        dprintk("aio: allocated ioctx %p[%ld]: mm=%p mask=0x%x\n",
                ctx, ctx->user_id, current->mm, ctx->ring_info.nr);
@@ -375,11 +390,12 @@ ssize_t wait_on_sync_kiocb(struct kiocb *iocb)
  */
 void exit_aio(struct mm_struct *mm)
 {
-       struct kioctx *ctx = mm->ioctx_list;
-       mm->ioctx_list = NULL;
-       while (ctx) {
-               struct kioctx *next = ctx->next;
-               ctx->next = NULL;
+       struct kioctx *ctx;
+
+       while (!hlist_empty(&mm->ioctx_list)) {
+               ctx = hlist_entry(mm->ioctx_list.first, struct kioctx, list);
+               hlist_del_rcu(&ctx->list);
+
                aio_cancel_all(ctx);
 
                wait_for_all_aios(ctx);
@@ -394,7 +410,6 @@ void exit_aio(struct mm_struct *mm)
                                atomic_read(&ctx->users), ctx->dead,
                                ctx->reqs_active);
                put_ioctx(ctx);
-               ctx = next;
        }
 }
 
@@ -555,19 +570,21 @@ int aio_put_req(struct kiocb *req)
 
 static struct kioctx *lookup_ioctx(unsigned long ctx_id)
 {
-       struct kioctx *ioctx;
-       struct mm_struct *mm;
+       struct mm_struct *mm = current->mm;
+       struct kioctx *ctx = NULL;
+       struct hlist_node *n;
 
-       mm = current->mm;
-       read_lock(&mm->ioctx_list_lock);
-       for (ioctx = mm->ioctx_list; ioctx; ioctx = ioctx->next)
-               if (likely(ioctx->user_id == ctx_id && !ioctx->dead)) {
-                       get_ioctx(ioctx);
+       rcu_read_lock();
+
+       hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) {
+               if (ctx->user_id == ctx_id && !ctx->dead) {
+                       get_ioctx(ctx);
                        break;
                }
-       read_unlock(&mm->ioctx_list_lock);
+       }
 
-       return ioctx;
+       rcu_read_unlock();
+       return ctx;
 }
 
 /*
@@ -1215,19 +1232,14 @@ out:
 static void io_destroy(struct kioctx *ioctx)
 {
        struct mm_struct *mm = current->mm;
-       struct kioctx **tmp;
        int was_dead;
 
        /* delete the entry from the list is someone else hasn't already */
-       write_lock(&mm->ioctx_list_lock);
+       spin_lock(&mm->ioctx_lock);
        was_dead = ioctx->dead;
        ioctx->dead = 1;
-       for (tmp = &mm->ioctx_list; *tmp && *tmp != ioctx;
-            tmp = &(*tmp)->next)
-               ;
-       if (*tmp)
-               *tmp = ioctx->next;
-       write_unlock(&mm->ioctx_list_lock);
+       hlist_del_rcu(&ioctx->list);
+       spin_unlock(&mm->ioctx_lock);
 
        dprintk("aio_release(%p)\n", ioctx);
        if (likely(!was_dead))
index 19caf7c962ace6c58868ed4fd2196212faf755ef..77ebc3c263d6549b5934017b3adfacd7752dc802 100644 (file)
@@ -111,7 +111,7 @@ void bio_integrity_free(struct bio *bio, struct bio_set *bs)
            && bip->bip_buf != NULL)
                kfree(bip->bip_buf);
 
-       mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]);
+       bvec_free_bs(bs, bip->bip_vec, bip->bip_pool);
        mempool_free(bip, bs->bio_integrity_pool);
 
        bio->bi_integrity = NULL;
index df99c882b807549f25c30b13416a3ae8ca43d7e0..711cee10360273cd76c535ed346060a7a32f7c29 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
 
 DEFINE_TRACE(block_split);
 
-static struct kmem_cache *bio_slab __read_mostly;
+/*
+ * Test patch to inline a certain number of bi_io_vec's inside the bio
+ * itself, to shrink a bio data allocation from two mempool calls to one
+ */
+#define BIO_INLINE_VECS                4
 
 static mempool_t *bio_split_pool __read_mostly;
 
@@ -40,9 +44,8 @@ static mempool_t *bio_split_pool __read_mostly;
  * break badly! cannot be bigger than what you can fit into an
  * unsigned short
  */
-
 #define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
+struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
        BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
 };
 #undef BV
@@ -53,12 +56,121 @@ static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
  */
 struct bio_set *fs_bio_set;
 
+/*
+ * Our slab pool management
+ */
+struct bio_slab {
+       struct kmem_cache *slab;
+       unsigned int slab_ref;
+       unsigned int slab_size;
+       char name[8];
+};
+static DEFINE_MUTEX(bio_slab_lock);
+static struct bio_slab *bio_slabs;
+static unsigned int bio_slab_nr, bio_slab_max;
+
+static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
+{
+       unsigned int sz = sizeof(struct bio) + extra_size;
+       struct kmem_cache *slab = NULL;
+       struct bio_slab *bslab;
+       unsigned int i, entry = -1;
+
+       mutex_lock(&bio_slab_lock);
+
+       i = 0;
+       while (i < bio_slab_nr) {
+               struct bio_slab *bslab = &bio_slabs[i];
+
+               if (!bslab->slab && entry == -1)
+                       entry = i;
+               else if (bslab->slab_size == sz) {
+                       slab = bslab->slab;
+                       bslab->slab_ref++;
+                       break;
+               }
+               i++;
+       }
+
+       if (slab)
+               goto out_unlock;
+
+       if (bio_slab_nr == bio_slab_max && entry == -1) {
+               bio_slab_max <<= 1;
+               bio_slabs = krealloc(bio_slabs,
+                                    bio_slab_max * sizeof(struct bio_slab),
+                                    GFP_KERNEL);
+               if (!bio_slabs)
+                       goto out_unlock;
+       }
+       if (entry == -1)
+               entry = bio_slab_nr++;
+
+       bslab = &bio_slabs[entry];
+
+       snprintf(bslab->name, sizeof(bslab->name), "bio-%d", entry);
+       slab = kmem_cache_create(bslab->name, sz, 0, SLAB_HWCACHE_ALIGN, NULL);
+       if (!slab)
+               goto out_unlock;
+
+       printk("bio: create slab <%s> at %d\n", bslab->name, entry);
+       bslab->slab = slab;
+       bslab->slab_ref = 1;
+       bslab->slab_size = sz;
+out_unlock:
+       mutex_unlock(&bio_slab_lock);
+       return slab;
+}
+
+static void bio_put_slab(struct bio_set *bs)
+{
+       struct bio_slab *bslab = NULL;
+       unsigned int i;
+
+       mutex_lock(&bio_slab_lock);
+
+       for (i = 0; i < bio_slab_nr; i++) {
+               if (bs->bio_slab == bio_slabs[i].slab) {
+                       bslab = &bio_slabs[i];
+                       break;
+               }
+       }
+
+       if (WARN(!bslab, KERN_ERR "bio: unable to find slab!\n"))
+               goto out;
+
+       WARN_ON(!bslab->slab_ref);
+
+       if (--bslab->slab_ref)
+               goto out;
+
+       kmem_cache_destroy(bslab->slab);
+       bslab->slab = NULL;
+
+out:
+       mutex_unlock(&bio_slab_lock);
+}
+
 unsigned int bvec_nr_vecs(unsigned short idx)
 {
        return bvec_slabs[idx].nr_vecs;
 }
 
-struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
+void bvec_free_bs(struct bio_set *bs, struct bio_vec *bv, unsigned int idx)
+{
+       BIO_BUG_ON(idx >= BIOVEC_NR_POOLS);
+
+       if (idx == BIOVEC_MAX_IDX)
+               mempool_free(bv, bs->bvec_pool);
+       else {
+               struct biovec_slab *bvs = bvec_slabs + idx;
+
+               kmem_cache_free(bvs->slab, bv);
+       }
+}
+
+struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx,
+                             struct bio_set *bs)
 {
        struct bio_vec *bvl;
 
@@ -67,60 +179,85 @@ struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct
         * If not, this is a bio_kmalloc() allocation and just do a
         * kzalloc() for the exact number of vecs right away.
         */
-       if (bs) {
+       if (!bs)
+               bvl = kmalloc(nr * sizeof(struct bio_vec), gfp_mask);
+
+       /*
+        * see comment near bvec_array define!
+        */
+       switch (nr) {
+       case 1:
+               *idx = 0;
+               break;
+       case 2 ... 4:
+               *idx = 1;
+               break;
+       case 5 ... 16:
+               *idx = 2;
+               break;
+       case 17 ... 64:
+               *idx = 3;
+               break;
+       case 65 ... 128:
+               *idx = 4;
+               break;
+       case 129 ... BIO_MAX_PAGES:
+               *idx = 5;
+               break;
+       default:
+               return NULL;
+       }
+
+       /*
+        * idx now points to the pool we want to allocate from. only the
+        * 1-vec entry pool is mempool backed.
+        */
+       if (*idx == BIOVEC_MAX_IDX) {
+fallback:
+               bvl = mempool_alloc(bs->bvec_pool, gfp_mask);
+       } else {
+               struct biovec_slab *bvs = bvec_slabs + *idx;
+               gfp_t __gfp_mask = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+
                /*
-                * see comment near bvec_array define!
+                * Make this allocation restricted and don't dump info on
+                * allocation failures, since we'll fallback to the mempool
+                * in case of failure.
                 */
-               switch (nr) {
-               case 1:
-                       *idx = 0;
-                       break;
-               case 2 ... 4:
-                       *idx = 1;
-                       break;
-               case 5 ... 16:
-                       *idx = 2;
-                       break;
-               case 17 ... 64:
-                       *idx = 3;
-                       break;
-               case 65 ... 128:
-                       *idx = 4;
-                       break;
-               case 129 ... BIO_MAX_PAGES:
-                       *idx = 5;
-                       break;
-               default:
-                       return NULL;
-               }
+               __gfp_mask |= __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
 
                /*
-                * idx now points to the pool we want to allocate from
+                * Try a slab allocation. If this fails and __GFP_WAIT
+                * is set, retry with the 1-entry mempool
                 */
-               bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
-               if (bvl)
-                       memset(bvl, 0,
-                               bvec_nr_vecs(*idx) * sizeof(struct bio_vec));
-       } else
-               bvl = kzalloc(nr * sizeof(struct bio_vec), gfp_mask);
+               bvl = kmem_cache_alloc(bvs->slab, __gfp_mask);
+               if (unlikely(!bvl && (gfp_mask & __GFP_WAIT))) {
+                       *idx = BIOVEC_MAX_IDX;
+                       goto fallback;
+               }
+       }
 
        return bvl;
 }
 
-void bio_free(struct bio *bio, struct bio_set *bio_set)
+void bio_free(struct bio *bio, struct bio_set *bs)
 {
-       if (bio->bi_io_vec) {
-               const int pool_idx = BIO_POOL_IDX(bio);
+       void *p;
 
-               BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
-
-               mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
-       }
+       if (bio_has_allocated_vec(bio))
+               bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio));
 
        if (bio_integrity(bio))
-               bio_integrity_free(bio, bio_set);
+               bio_integrity_free(bio, bs);
+
+       /*
+        * If we have front padding, adjust the bio pointer before freeing
+        */
+       p = bio;
+       if (bs->front_pad)
+               p -= bs->front_pad;
 
-       mempool_free(bio, bio_set->bio_pool);
+       mempool_free(p, bs->bio_pool);
 }
 
 /*
@@ -133,7 +270,8 @@ static void bio_fs_destructor(struct bio *bio)
 
 static void bio_kmalloc_destructor(struct bio *bio)
 {
-       kfree(bio->bi_io_vec);
+       if (bio_has_allocated_vec(bio))
+               kfree(bio->bi_io_vec);
        kfree(bio);
 }
 
@@ -157,16 +295,20 @@ void bio_init(struct bio *bio)
  *   for a &struct bio to become free. If a %NULL @bs is passed in, we will
  *   fall back to just using @kmalloc to allocate the required memory.
  *
- *   allocate bio and iovecs from the memory pools specified by the
- *   bio_set structure, or @kmalloc if none given.
+ *   Note that the caller must set ->bi_destructor on succesful return
+ *   of a bio, to do the appropriate freeing of the bio once the reference
+ *   count drops to zero.
  **/
 struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
 {
-       struct bio *bio;
+       struct bio *bio = NULL;
+
+       if (bs) {
+               void *p = mempool_alloc(bs->bio_pool, gfp_mask);
 
-       if (bs)
-               bio = mempool_alloc(bs->bio_pool, gfp_mask);
-       else
+               if (p)
+                       bio = p + bs->front_pad;
+       else
                bio = kmalloc(sizeof(*bio), gfp_mask);
 
        if (likely(bio)) {
@@ -176,7 +318,15 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
                if (likely(nr_iovecs)) {
                        unsigned long uninitialized_var(idx);
 
-                       bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
+                       if (nr_iovecs <= BIO_INLINE_VECS) {
+                               idx = 0;
+                               bvl = bio->bi_inline_vecs;
+                               nr_iovecs = BIO_INLINE_VECS;
+                       } else {
+                               bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx,
+                                                       bs);
+                               nr_iovecs = bvec_nr_vecs(idx);
+                       }
                        if (unlikely(!bvl)) {
                                if (bs)
                                        mempool_free(bio, bs->bio_pool);
@@ -186,7 +336,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
                                goto out;
                        }
                        bio->bi_flags |= idx << BIO_POOL_OFFSET;
-                       bio->bi_max_vecs = bvec_nr_vecs(idx);
+                       bio->bi_max_vecs = nr_iovecs;
                }
                bio->bi_io_vec = bvl;
        }
@@ -1346,30 +1496,18 @@ EXPORT_SYMBOL(bio_sector_offset);
  */
 static int biovec_create_pools(struct bio_set *bs, int pool_entries)
 {
-       int i;
+       struct biovec_slab *bp = bvec_slabs + BIOVEC_MAX_IDX;
 
-       for (i = 0; i < BIOVEC_NR_POOLS; i++) {
-               struct biovec_slab *bp = bvec_slabs + i;
-               mempool_t **bvp = bs->bvec_pools + i;
+       bs->bvec_pool = mempool_create_slab_pool(pool_entries, bp->slab);
+       if (!bs->bvec_pool)
+               return -ENOMEM;
 
-               *bvp = mempool_create_slab_pool(pool_entries, bp->slab);
-               if (!*bvp)
-                       return -ENOMEM;
-       }
        return 0;
 }
 
 static void biovec_free_pools(struct bio_set *bs)
 {
-       int i;
-
-       for (i = 0; i < BIOVEC_NR_POOLS; i++) {
-               mempool_t *bvp = bs->bvec_pools[i];
-
-               if (bvp)
-                       mempool_destroy(bvp);
-       }
-
+       mempool_destroy(bs->bvec_pool);
 }
 
 void bioset_free(struct bio_set *bs)
@@ -1379,25 +1517,49 @@ void bioset_free(struct bio_set *bs)
 
        bioset_integrity_free(bs);
        biovec_free_pools(bs);
+       bio_put_slab(bs);
 
        kfree(bs);
 }
 
-struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
+/**
+ * bioset_create  - Create a bio_set
+ * @pool_size: Number of bio and bio_vecs to cache in the mempool
+ * @front_pad: Number of bytes to allocate in front of the returned bio
+ *
+ * Description:
+ *    Set up a bio_set to be used with @bio_alloc_bioset. Allows the caller
+ *    to ask for a number of bytes to be allocated in front of the bio.
+ *    Front pad allocation is useful for embedding the bio inside
+ *    another structure, to avoid allocating extra data to go with the bio.
+ *    Note that the bio must be embedded at the END of that structure always,
+ *    or things will break badly.
+ */
+struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad)
 {
-       struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
+       unsigned int back_pad = BIO_INLINE_VECS * sizeof(struct bio_vec);
+       struct bio_set *bs;
 
+       bs = kzalloc(sizeof(*bs), GFP_KERNEL);
        if (!bs)
                return NULL;
 
-       bs->bio_pool = mempool_create_slab_pool(bio_pool_size, bio_slab);
+       bs->front_pad = front_pad;
+
+       bs->bio_slab = bio_find_or_create_slab(front_pad + back_pad);
+       if (!bs->bio_slab) {
+               kfree(bs);
+               return NULL;
+       }
+
+       bs->bio_pool = mempool_create_slab_pool(pool_size, bs->bio_slab);
        if (!bs->bio_pool)
                goto bad;
 
-       if (bioset_integrity_create(bs, bio_pool_size))
+       if (bioset_integrity_create(bs, pool_size))
                goto bad;
 
-       if (!biovec_create_pools(bs, bvec_pool_size))
+       if (!biovec_create_pools(bs, pool_size))
                return bs;
 
 bad:
@@ -1421,12 +1583,16 @@ static void __init biovec_init_slabs(void)
 
 static int __init init_bio(void)
 {
-       bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+       bio_slab_max = 2;
+       bio_slab_nr = 0;
+       bio_slabs = kzalloc(bio_slab_max * sizeof(struct bio_slab), GFP_KERNEL);
+       if (!bio_slabs)
+               panic("bio: can't allocate bios\n");
 
        bio_integrity_init_slab();
        biovec_init_slabs();
 
-       fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
+       fs_bio_set = bioset_create(BIO_POOL_SIZE, 0);
        if (!fs_bio_set)
                panic("bio: can't allocate bios\n");
 
index 10179cfa11528683495886657bd643ebde590ce8..776ae091d3b0d58052aacb899e0954c3b191ae10 100644 (file)
@@ -99,10 +99,18 @@ __clear_page_buffers(struct page *page)
        page_cache_release(page);
 }
 
+
+static int quiet_error(struct buffer_head *bh)
+{
+       if (!test_bit(BH_Quiet, &bh->b_state) && printk_ratelimit())
+               return 0;
+       return 1;
+}
+
+
 static void buffer_io_error(struct buffer_head *bh)
 {
        char b[BDEVNAME_SIZE];
-
        printk(KERN_ERR "Buffer I/O error on device %s, logical block %Lu\n",
                        bdevname(bh->b_bdev, b),
                        (unsigned long long)bh->b_blocknr);
@@ -144,7 +152,7 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate)
        if (uptodate) {
                set_buffer_uptodate(bh);
        } else {
-               if (!buffer_eopnotsupp(bh) && printk_ratelimit()) {
+               if (!buffer_eopnotsupp(bh) && !quiet_error(bh)) {
                        buffer_io_error(bh);
                        printk(KERN_WARNING "lost page write due to "
                                        "I/O error on %s\n",
@@ -394,7 +402,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
                set_buffer_uptodate(bh);
        } else {
                clear_buffer_uptodate(bh);
-               if (printk_ratelimit())
+               if (!quiet_error(bh))
                        buffer_io_error(bh);
                SetPageError(page);
        }
@@ -455,7 +463,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
        if (uptodate) {
                set_buffer_uptodate(bh);
        } else {
-               if (printk_ratelimit()) {
+               if (!quiet_error(bh)) {
                        buffer_io_error(bh);
                        printk(KERN_WARNING "lost page write due to "
                                        "I/O error on %s\n",
@@ -2913,6 +2921,9 @@ static void end_bio_bh_io_sync(struct bio *bio, int err)
                set_bit(BH_Eopnotsupp, &bh->b_state);
        }
 
+       if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags)))
+               set_bit(BH_Quiet, &bh->b_state);
+
        bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
        bio_put(bio);
 }
index 1f59ea079cbb80f1910c98a828f0cb32f1d6292c..02d2e120542d76ca26ee233e638749e53bc227f0 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -773,7 +773,6 @@ static int de_thread(struct task_struct *tsk)
        struct signal_struct *sig = tsk->signal;
        struct sighand_struct *oldsighand = tsk->sighand;
        spinlock_t *lock = &oldsighand->siglock;
-       struct task_struct *leader = NULL;
        int count;
 
        if (thread_group_empty(tsk))
@@ -811,7 +810,7 @@ static int de_thread(struct task_struct *tsk)
         * and to assume its PID:
         */
        if (!thread_group_leader(tsk)) {
-               leader = tsk->group_leader;
+               struct task_struct *leader = tsk->group_leader;
 
                sig->notify_count = -1; /* for exit_notify() */
                for (;;) {
@@ -863,8 +862,9 @@ static int de_thread(struct task_struct *tsk)
 
                BUG_ON(leader->exit_state != EXIT_ZOMBIE);
                leader->exit_state = EXIT_DEAD;
-
                write_unlock_irq(&tasklist_lock);
+
+               release_task(leader);
        }
 
        sig->group_exit_task = NULL;
@@ -873,8 +873,6 @@ static int de_thread(struct task_struct *tsk)
 no_thread_group:
        exit_itimers(sig);
        flush_itimer_signals();
-       if (leader)
-               release_task(leader);
 
        if (atomic_read(&oldsighand->count) != 1) {
                struct sighand_struct *newsighand;
index e4a241c65dbeb79d189d84b08010430274c6755f..04158ad74dbbc7192587f8d140d4cb8305bd8e46 100644 (file)
@@ -1721,7 +1721,7 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files)
        /* small i_blocks in vfs inode? */
        if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
                /*
-                * CONFIG_LSF is not enabled implies the inode
+                * CONFIG_LBD is not enabled implies the inode
                 * i_block represent total blocks in 512 bytes
                 * 32 == size of vfs inode i_blocks * 8
                 */
@@ -1764,7 +1764,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files)
 
        if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
                /*
-                * !has_huge_files or CONFIG_LSF is not enabled
+                * !has_huge_files or CONFIG_LBD is not enabled
                 * implies the inode i_block represent total blocks in
                 * 512 bytes 32 == size of vfs inode i_blocks * 8
                 */
@@ -2021,13 +2021,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (has_huge_files) {
                /*
                 * Large file size enabled file system can only be
-                * mount if kernel is build with CONFIG_LSF
+                * mount if kernel is build with CONFIG_LBD
                 */
                if (sizeof(root->i_blocks) < sizeof(u64) &&
                                !(sb->s_flags & MS_RDONLY)) {
                        printk(KERN_ERR "EXT4-fs: %s: Filesystem with huge "
                                        "files cannot be mounted read-write "
-                                       "without CONFIG_LSF.\n", sb->s_id);
+                                       "without CONFIG_LBD.\n", sb->s_id);
                        goto failed_mount;
                }
        }
index 210339784b56f98a29ca2d75e2c2cf082dae904a..b00ee9f05a0695f0a84814ae15320aaac1a58aa8 100644 (file)
@@ -59,8 +59,14 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
                if (inode->i_size >= IDATASIZE) {
                        inode->i_op = &page_symlink_inode_operations;
                        inode->i_mapping->a_ops = &jfs_aops;
-               } else
+               } else {
                        inode->i_op = &jfs_symlink_inode_operations;
+                       /*
+                        * The inline data should be null-terminated, but
+                        * don't let on-disk corruption crash the kernel
+                        */
+                       JFS_IP(inode)->i_inline[inode->i_size] = '\0';
+               }
        } else {
                inode->i_op = &jfs_file_inode_operations;
                init_special_inode(inode, inode->i_mode, inode->i_rdev);
index 81904f07679d43635cbc6241162d9b45d9a9db62..3bb1cf1e742552ad2f97b6b6206474937ffb0f07 100644 (file)
@@ -44,10 +44,13 @@ static int show_stat(struct seq_file *p, void *v)
                softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
                steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
                guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
-
-               for_each_irq_nr(j)
+               for_each_irq_nr(j) {
+#ifdef CONFIG_SPARSE_IRQ
+                       if (!irq_to_desc(j))
+                               continue;
+#endif
                        sum += kstat_irqs_cpu(j, i);
-
+               }
                sum += arch_irq_stat_cpu(i);
        }
        sum += arch_irq_stat();
@@ -92,7 +95,12 @@ static int show_stat(struct seq_file *p, void *v)
        /* sum again ? it could be updated? */
        for_each_irq_nr(j) {
                per_irq_sum = 0;
-
+#ifdef CONFIG_SPARSE_IRQ
+               if (!irq_to_desc(j)) {
+                       seq_printf(p, " %u", per_irq_sum);
+                       continue;
+               }
+#endif
                for_each_possible_cpu(i)
                        per_irq_sum += kstat_irqs_cpu(j, i);
 
index 4c794d73fb8484e47fb0708beb7a470724707046..8af276361bf26c662bd268fcec2c1431254ce03d 100644 (file)
@@ -41,15 +41,14 @@ struct bug_entry {
 
 #ifndef __WARN
 #ifndef __ASSEMBLY__
-extern void warn_on_slowpath(const char *file, const int line);
 extern void warn_slowpath(const char *file, const int line,
                const char *fmt, ...) __attribute__((format(printf, 3, 4)));
 #define WANT_WARN_ON_SLOWPATH
 #endif
-#define __WARN() warn_on_slowpath(__FILE__, __LINE__)
-#define __WARN_printf(arg...) warn_slowpath(__FILE__, __LINE__, arg)
+#define __WARN()               warn_slowpath(__FILE__, __LINE__, NULL)
+#define __WARN_printf(arg...)  warn_slowpath(__FILE__, __LINE__, arg)
 #else
-#define __WARN_printf(arg...) do { printk(arg); __WARN(); } while (0)
+#define __WARN_printf(arg...)  do { printk(arg); __WARN(); } while (0)
 #endif
 
 #ifndef WARN_ON
index 82b6983b7fbbe8e3bf32092e7a7f899ba85b72f8..b940fdfa3b25284fb0a244b18781709cda90789b 100644 (file)
@@ -1,4 +1,4 @@
-unifdef-y += drm.h drm_sarea.h
+unifdef-y += drm.h drm_sarea.h drm_mode.h
 unifdef-y += i810_drm.h
 unifdef-y += i830_drm.h
 unifdef-y += i915_drm.h
index f46ba4b57da4aedda3e3c4ac170056474bf8c102..32e5096554e9004f78c0d173f45d7036f419cab3 100644 (file)
@@ -173,6 +173,7 @@ enum drm_map_type {
        _DRM_AGP = 3,             /**< AGP/GART */
        _DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
        _DRM_CONSISTENT = 5,      /**< Consistent memory for PCI DMA */
+       _DRM_GEM = 6,             /**< GEM object */
 };
 
 /**
@@ -598,6 +599,8 @@ struct drm_gem_open {
        uint64_t size;
 };
 
+#include "drm_mode.h"
+
 #define DRM_IOCTL_BASE                 'd'
 #define DRM_IO(nr)                     _IO(DRM_IOCTL_BASE,nr)
 #define DRM_IOR(nr,type)               _IOR(DRM_IOCTL_BASE,nr,type)
@@ -634,6 +637,9 @@ struct drm_gem_open {
 #define DRM_IOCTL_SET_SAREA_CTX                DRM_IOW( 0x1c, struct drm_ctx_priv_map)
 #define DRM_IOCTL_GET_SAREA_CTX        DRM_IOWR(0x1d, struct drm_ctx_priv_map)
 
+#define DRM_IOCTL_SET_MASTER            DRM_IO(0x1e)
+#define DRM_IOCTL_DROP_MASTER           DRM_IO(0x1f)
+
 #define DRM_IOCTL_ADD_CTX              DRM_IOWR(0x20, struct drm_ctx)
 #define DRM_IOCTL_RM_CTX               DRM_IOWR(0x21, struct drm_ctx)
 #define DRM_IOCTL_MOD_CTX              DRM_IOW( 0x22, struct drm_ctx)
@@ -664,6 +670,24 @@ struct drm_gem_open {
 
 #define DRM_IOCTL_UPDATE_DRAW          DRM_IOW(0x3f, struct drm_update_draw)
 
+#define DRM_IOCTL_MODE_GETRESOURCES    DRM_IOWR(0xA0, struct drm_mode_card_res)
+#define DRM_IOCTL_MODE_GETCRTC         DRM_IOWR(0xA1, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_SETCRTC         DRM_IOWR(0xA2, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_CURSOR          DRM_IOWR(0xA3, struct drm_mode_cursor)
+#define DRM_IOCTL_MODE_GETGAMMA                DRM_IOWR(0xA4, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_SETGAMMA                DRM_IOWR(0xA5, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_GETENCODER      DRM_IOWR(0xA6, struct drm_mode_get_encoder)
+#define DRM_IOCTL_MODE_GETCONNECTOR    DRM_IOWR(0xA7, struct drm_mode_get_connector)
+#define DRM_IOCTL_MODE_ATTACHMODE      DRM_IOWR(0xA8, struct drm_mode_mode_cmd)
+#define DRM_IOCTL_MODE_DETACHMODE      DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
+
+#define DRM_IOCTL_MODE_GETPROPERTY     DRM_IOWR(0xAA, struct drm_mode_get_property)
+#define DRM_IOCTL_MODE_SETPROPERTY     DRM_IOWR(0xAB, struct drm_mode_connector_set_property)
+#define DRM_IOCTL_MODE_GETPROPBLOB     DRM_IOWR(0xAC, struct drm_mode_get_blob)
+#define DRM_IOCTL_MODE_GETFB           DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_ADDFB           DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_RMFB            DRM_IOWR(0xAF, unsigned int)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x99.
index d5e8e5c8954825baaf69564e07716dd041ed0593..afb7858c068d1f31ef1a77bbe6abc3ea7c00bfb9 100644 (file)
@@ -105,6 +105,7 @@ struct drm_device;
 #define DRIVER_FB_DMA      0x400
 #define DRIVER_IRQ_VBL2    0x800
 #define DRIVER_GEM         0x1000
+#define DRIVER_MODESET     0x2000
 
 /***********************************************************************/
 /** \name Begin the DRM... */
@@ -238,11 +239,11 @@ struct drm_device;
  */
 #define LOCK_TEST_WITH_RETURN( dev, file_priv )                                \
 do {                                                                   \
-       if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||           \
-            dev->lock.file_priv != file_priv ) {                       \
+       if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock) ||                \
+           file_priv->master->lock.file_priv != file_priv)     {                       \
                DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
-                          __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
-                          dev->lock.file_priv, file_priv );            \
+                          __func__, _DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock),\
+                          file_priv->master->lock.file_priv, file_priv);               \
                return -EINVAL;                                         \
        }                                                               \
 } while (0)
@@ -276,6 +277,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
 #define DRM_AUTH       0x1
 #define        DRM_MASTER      0x2
 #define DRM_ROOT_ONLY  0x4
+#define DRM_CONTROL_ALLOW 0x8
 
 struct drm_ioctl_desc {
        unsigned int cmd;
@@ -379,21 +381,26 @@ struct drm_buf_entry {
 /** File private data */
 struct drm_file {
        int authenticated;
-       int master;
        pid_t pid;
        uid_t uid;
        drm_magic_t magic;
        unsigned long ioctl_count;
        struct list_head lhead;
        struct drm_minor *minor;
-       int remove_auth_on_close;
        unsigned long lock_count;
+
        /** Mapping of mm object handles to object pointers. */
        struct idr object_idr;
        /** Lock for synchronization of access to object_idr. */
        spinlock_t table_lock;
+
        struct file *filp;
        void *driver_priv;
+
+       int is_master; /* this file private is a master for a minor */
+       struct drm_master *master; /* master this node is currently associated with
+                                     N.B. not always minor->master */
+       struct list_head fbs;
 };
 
 /** Wait queue */
@@ -523,6 +530,8 @@ struct drm_map_list {
        struct drm_hash_item hash;
        struct drm_map *map;                    /**< mapping */
        uint64_t user_token;
+       struct drm_master *master;
+       struct drm_mm_node *file_offset_node;   /**< fake offset */
 };
 
 typedef struct drm_map drm_local_map_t;
@@ -562,6 +571,14 @@ struct drm_ati_pcigart_info {
        int table_size;
 };
 
+/**
+ * GEM specific mm private for tracking GEM objects
+ */
+struct drm_gem_mm {
+       struct drm_mm offset_manager;   /**< Offset mgmt for buffer objects */
+       struct drm_open_hash offset_hash; /**< User token hash table for maps */
+};
+
 /**
  * This structure defines the drm_mm memory object, which will be used by the
  * DRM for its buffer objects.
@@ -579,6 +596,9 @@ struct drm_gem_object {
        /** File representing the shmem storage */
        struct file *filp;
 
+       /* Mapping info for this object */
+       struct drm_map_list map_list;
+
        /**
         * Size of the object, in bytes.  Immutable over the object's
         * lifetime.
@@ -612,6 +632,33 @@ struct drm_gem_object {
        void *driver_private;
 };
 
+#include "drm_crtc.h"
+
+/* per-master structure */
+struct drm_master {
+
+       struct kref refcount; /* refcount for this master */
+
+       struct list_head head; /**< each minor contains a list of masters */
+       struct drm_minor *minor; /**< link back to minor we are a master for */
+
+       char *unique;                   /**< Unique identifier: e.g., busid */
+       int unique_len;                 /**< Length of unique field */
+       int unique_size;                /**< amount allocated */
+
+       int blocked;                    /**< Blocked due to VC switch? */
+
+       /** \name Authentication */
+       /*@{ */
+       struct drm_open_hash magiclist;
+       struct list_head magicfree;
+       /*@} */
+
+       struct drm_lock_data lock;      /**< Information on hardware lock */
+
+       void *driver_priv; /**< Private structure for driver to use */
+};
+
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -712,6 +759,10 @@ struct drm_driver {
        void (*set_version) (struct drm_device *dev,
                             struct drm_set_version *sv);
 
+       /* Master routines */
+       int (*master_create)(struct drm_device *dev, struct drm_master *master);
+       void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
+
        int (*proc_init)(struct drm_minor *minor);
        void (*proc_cleanup)(struct drm_minor *minor);
 
@@ -724,6 +775,9 @@ struct drm_driver {
        int (*gem_init_object) (struct drm_gem_object *obj);
        void (*gem_free_object) (struct drm_gem_object *obj);
 
+       /* Driver private ops for this object */
+       struct vm_operations_struct *gem_vm_ops;
+
        int major;
        int minor;
        int patchlevel;
@@ -737,10 +791,14 @@ struct drm_driver {
        int num_ioctls;
        struct file_operations fops;
        struct pci_driver pci_driver;
+       /* List of devices hanging off this driver */
+       struct list_head device_list;
 };
 
 #define DRM_MINOR_UNASSIGNED 0
 #define DRM_MINOR_LEGACY 1
+#define DRM_MINOR_CONTROL 2
+#define DRM_MINOR_RENDER 3
 
 /**
  * DRM minor structure. This structure represents a drm minor number.
@@ -752,6 +810,9 @@ struct drm_minor {
        struct device kdev;             /**< Linux device */
        struct drm_device *dev;
        struct proc_dir_entry *dev_root;  /**< proc directory entry */
+       struct drm_master *master; /* currently active master for this node */
+       struct list_head master_list;
+       struct drm_mode_group mode_group;
 };
 
 /**
@@ -759,13 +820,10 @@ struct drm_minor {
  * may contain multiple heads.
  */
 struct drm_device {
-       char *unique;                   /**< Unique identifier: e.g., busid */
-       int unique_len;                 /**< Length of unique field */
+       struct list_head driver_item;   /**< list of devices per driver */
        char *devname;                  /**< For /proc/interrupts */
        int if_version;                 /**< Highest interface version set */
 
-       int blocked;                    /**< Blocked due to VC switch? */
-
        /** \name Locks */
        /*@{ */
        spinlock_t count_lock;          /**< For inuse, drm_device::open_count, drm_device::buf_use */
@@ -788,12 +846,7 @@ struct drm_device {
        atomic_t counts[15];
        /*@} */
 
-       /** \name Authentication */
-       /*@{ */
        struct list_head filelist;
-       struct drm_open_hash magiclist; /**< magic hash table */
-       struct list_head magicfree;
-       /*@} */
 
        /** \name Memory management */
        /*@{ */
@@ -810,7 +863,7 @@ struct drm_device {
        struct idr ctx_idr;
 
        struct list_head vmalist;       /**< List of vmas (for debugging) */
-       struct drm_lock_data lock;      /**< Information on hardware lock */
+
        /*@} */
 
        /** \name DMA queues (contexts) */
@@ -858,6 +911,7 @@ struct drm_device {
        int *vblank_enabled;            /* so we don't call enable more than
                                           once per disable */
        int *vblank_inmodeset;          /* Display driver is setting mode */
+       u32 *last_vblank_wait;          /* Last vblank seqno waited per CRTC */
        struct timer_list vblank_disable_timer;
 
        u32 max_vblank_count;           /**< size of vblank counter register */
@@ -881,12 +935,15 @@ struct drm_device {
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
        int num_crtcs;                  /**< Number of CRTCs on this device */
        void *dev_private;              /**< device private data */
+       void *mm_private;
+       struct address_space *dev_mapping;
        struct drm_sigdata sigdata;        /**< For block_all_signals */
        sigset_t sigmask;
 
        struct drm_driver *driver;
        drm_local_map_t *agp_buffer_map;
        unsigned int agp_buffer_token;
+       struct drm_minor *control;              /**< Control node for card */
        struct drm_minor *primary;              /**< render type primary screen head */
 
        /** \name Drawable information */
@@ -895,6 +952,8 @@ struct drm_device {
        struct idr drw_idr;
        /*@} */
 
+        struct drm_mode_config mode_config;    /**< Current mode config */
+
        /** \name GEM information */
        /*@{ */
        spinlock_t object_name_lock;
@@ -997,6 +1056,8 @@ extern int drm_release(struct inode *inode, struct file *filp);
 
                                /* Mapping support (drm_vm.h) */
 extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
+extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
+extern void drm_vm_open_locked(struct vm_area_struct *vma);
 extern unsigned long drm_core_get_map_ofs(struct drm_map * map);
 extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
 extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
@@ -1153,6 +1214,8 @@ extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
 /* Modesetting support */
+extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
+extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
 extern int drm_modeset_ctl(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);
 
@@ -1189,6 +1252,13 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
 extern void drm_agp_chipset_flush(struct drm_device *dev);
 
                                /* Stub support (drm_stub.h) */
+extern int drm_setmaster_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file_priv);
+extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
+struct drm_master *drm_master_create(struct drm_minor *minor);
+extern struct drm_master *drm_master_get(struct drm_master *master);
+extern void drm_master_put(struct drm_master **master);
 extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                       struct drm_driver *driver);
 extern int drm_put_dev(struct drm_device *dev);
@@ -1231,7 +1301,11 @@ struct drm_sysfs_class;
 extern struct class *drm_sysfs_create(struct module *owner, char *name);
 extern void drm_sysfs_destroy(void);
 extern int drm_sysfs_device_add(struct drm_minor *minor);
+extern void drm_sysfs_hotplug_event(struct drm_device *dev);
 extern void drm_sysfs_device_remove(struct drm_minor *minor);
+extern char *drm_get_connector_status_name(enum drm_connector_status status);
+extern int drm_sysfs_connector_add(struct drm_connector *connector);
+extern void drm_sysfs_connector_remove(struct drm_connector *connector);
 
 /*
  * Basic memory manager support (drm_mm.c)
@@ -1251,10 +1325,12 @@ extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
 
 /* Graphics Execution Manager library functions (drm_gem.c) */
 int drm_gem_init(struct drm_device *dev);
+void drm_gem_destroy(struct drm_device *dev);
 void drm_gem_object_free(struct kref *kref);
 struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
                                            size_t size);
 void drm_gem_object_handle_free(struct kref *kref);
+int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
 
 static inline void
 drm_gem_object_reference(struct drm_gem_object *obj)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
new file mode 100644 (file)
index 0000000..0acb07f
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+ * Copyright Â© 2006 Keith Packard
+ * Copyright Â© 2007-2008 Dave Airlie
+ * Copyright Â© 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __DRM_CRTC_H__
+#define __DRM_CRTC_H__
+
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+
+#include <linux/fb.h>
+
+struct drm_device;
+struct drm_mode_set;
+struct drm_framebuffer;
+
+
+#define DRM_MODE_OBJECT_CRTC 0xcccccccc
+#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
+#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0
+#define DRM_MODE_OBJECT_MODE 0xdededede
+#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0
+#define DRM_MODE_OBJECT_FB 0xfbfbfbfb
+#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
+
+struct drm_mode_object {
+       uint32_t id;
+       uint32_t type;
+};
+
+/*
+ * Note on terminology:  here, for brevity and convenience, we refer to connector
+ * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
+ * DVI, etc.  And 'screen' refers to the whole of the visible display, which
+ * may span multiple monitors (and therefore multiple CRTC and connector
+ * structures).
+ */
+
+enum drm_mode_status {
+    MODE_OK    = 0,    /* Mode OK */
+    MODE_HSYNC,                /* hsync out of range */
+    MODE_VSYNC,                /* vsync out of range */
+    MODE_H_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_V_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_BAD_WIDTH,    /* requires an unsupported linepitch */
+    MODE_NOMODE,       /* no mode with a maching name */
+    MODE_NO_INTERLACE, /* interlaced mode not supported */
+    MODE_NO_DBLESCAN,  /* doublescan mode not supported */
+    MODE_NO_VSCAN,     /* multiscan mode not supported */
+    MODE_MEM,          /* insufficient video memory */
+    MODE_VIRTUAL_X,    /* mode width too large for specified virtual size */
+    MODE_VIRTUAL_Y,    /* mode height too large for specified virtual size */
+    MODE_MEM_VIRT,     /* insufficient video memory given virtual size */
+    MODE_NOCLOCK,      /* no fixed clock available */
+    MODE_CLOCK_HIGH,   /* clock required is too high */
+    MODE_CLOCK_LOW,    /* clock required is too low */
+    MODE_CLOCK_RANGE,  /* clock/mode isn't in a ClockRange */
+    MODE_BAD_HVALUE,   /* horizontal timing was out of range */
+    MODE_BAD_VVALUE,   /* vertical timing was out of range */
+    MODE_BAD_VSCAN,    /* VScan value out of range */
+    MODE_HSYNC_NARROW, /* horizontal sync too narrow */
+    MODE_HSYNC_WIDE,   /* horizontal sync too wide */
+    MODE_HBLANK_NARROW,        /* horizontal blanking too narrow */
+    MODE_HBLANK_WIDE,  /* horizontal blanking too wide */
+    MODE_VSYNC_NARROW, /* vertical sync too narrow */
+    MODE_VSYNC_WIDE,   /* vertical sync too wide */
+    MODE_VBLANK_NARROW,        /* vertical blanking too narrow */
+    MODE_VBLANK_WIDE,  /* vertical blanking too wide */
+    MODE_PANEL,         /* exceeds panel dimensions */
+    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
+    MODE_ONE_WIDTH,     /* only one width is supported */
+    MODE_ONE_HEIGHT,    /* only one height is supported */
+    MODE_ONE_SIZE,      /* only one resolution is supported */
+    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
+    MODE_UNVERIFIED = -3, /* mode needs to reverified */
+    MODE_BAD = -2,     /* unspecified reason */
+    MODE_ERROR = -1    /* error condition */
+};
+
+#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
+                                   DRM_MODE_TYPE_CRTC_C)
+
+#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
+       .name = nm, .status = 0, .type = (t), .clock = (c), \
+       .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
+       .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
+       .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
+       .vscan = (vs), .flags = (f), .vrefresh = 0
+
+#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */
+
+struct drm_display_mode {
+       /* Header */
+       struct list_head head;
+       struct drm_mode_object base;
+
+       char name[DRM_DISPLAY_MODE_LEN];
+
+       int connector_count;
+       enum drm_mode_status status;
+       int type;
+
+       /* Proposed mode values */
+       int clock;
+       int hdisplay;
+       int hsync_start;
+       int hsync_end;
+       int htotal;
+       int hskew;
+       int vdisplay;
+       int vsync_start;
+       int vsync_end;
+       int vtotal;
+       int vscan;
+       unsigned int flags;
+
+       /* Addressable image size (may be 0 for projectors, etc.) */
+       int width_mm;
+       int height_mm;
+
+       /* Actual mode we give to hw */
+       int clock_index;
+       int synth_clock;
+       int crtc_hdisplay;
+       int crtc_hblank_start;
+       int crtc_hblank_end;
+       int crtc_hsync_start;
+       int crtc_hsync_end;
+       int crtc_htotal;
+       int crtc_hskew;
+       int crtc_vdisplay;
+       int crtc_vblank_start;
+       int crtc_vblank_end;
+       int crtc_vsync_start;
+       int crtc_vsync_end;
+       int crtc_vtotal;
+       int crtc_hadjusted;
+       int crtc_vadjusted;
+
+       /* Driver private mode info */
+       int private_size;
+       int *private;
+       int private_flags;
+
+       int vrefresh;
+       float hsync;
+};
+
+enum drm_connector_status {
+       connector_status_connected = 1,
+       connector_status_disconnected = 2,
+       connector_status_unknown = 3,
+};
+
+enum subpixel_order {
+       SubPixelUnknown = 0,
+       SubPixelHorizontalRGB,
+       SubPixelHorizontalBGR,
+       SubPixelVerticalRGB,
+       SubPixelVerticalBGR,
+       SubPixelNone,
+};
+
+
+/*
+ * Describes a given display (e.g. CRT or flat panel) and its limitations.
+ */
+struct drm_display_info {
+       char name[DRM_DISPLAY_INFO_LEN];
+       /* Input info */
+       bool serration_vsync;
+       bool sync_on_green;
+       bool composite_sync;
+       bool separate_syncs;
+       bool blank_to_black;
+       unsigned char video_level;
+       bool digital;
+       /* Physical size */
+        unsigned int width_mm;
+       unsigned int height_mm;
+
+       /* Display parameters */
+       unsigned char gamma; /* FIXME: storage format */
+       bool gtf_supported;
+       bool standard_color;
+       enum {
+               monochrome = 0,
+               rgb,
+               other,
+               unknown,
+       } display_type;
+       bool active_off_supported;
+       bool suspend_supported;
+       bool standby_supported;
+
+       /* Color info FIXME: storage format */
+       unsigned short redx, redy;
+       unsigned short greenx, greeny;
+       unsigned short bluex, bluey;
+       unsigned short whitex, whitey;
+
+       /* Clock limits FIXME: storage format */
+       unsigned int min_vfreq, max_vfreq;
+       unsigned int min_hfreq, max_hfreq;
+       unsigned int pixel_clock;
+
+       /* White point indices FIXME: storage format */
+       unsigned int wpx1, wpy1;
+       unsigned int wpgamma1;
+       unsigned int wpx2, wpy2;
+       unsigned int wpgamma2;
+
+       enum subpixel_order subpixel_order;
+
+       char *raw_edid; /* if any */
+};
+
+struct drm_framebuffer_funcs {
+       void (*destroy)(struct drm_framebuffer *framebuffer);
+       int (*create_handle)(struct drm_framebuffer *fb,
+                            struct drm_file *file_priv,
+                            unsigned int *handle);
+};
+
+struct drm_framebuffer {
+       struct drm_device *dev;
+       struct list_head head;
+       struct drm_mode_object base;
+       const struct drm_framebuffer_funcs *funcs;
+       unsigned int pitch;
+       unsigned int width;
+       unsigned int height;
+       /* depth can be 15 or 16 */
+       unsigned int depth;
+       int bits_per_pixel;
+       int flags;
+       void *fbdev;
+       u32 pseudo_palette[17];
+       struct list_head filp_head;
+};
+
+struct drm_property_blob {
+       struct drm_mode_object base;
+       struct list_head head;
+       unsigned int length;
+       void *data;
+};
+
+struct drm_property_enum {
+       uint64_t value;
+       struct list_head head;
+       char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_property {
+       struct list_head head;
+       struct drm_mode_object base;
+       uint32_t flags;
+       char name[DRM_PROP_NAME_LEN];
+       uint32_t num_values;
+       uint64_t *values;
+
+       struct list_head enum_blob_list;
+};
+
+struct drm_crtc;
+struct drm_connector;
+struct drm_encoder;
+
+/**
+ * drm_crtc_funcs - control CRTCs for a given device
+ * @dpms: control display power levels
+ * @save: save CRTC state
+ * @resore: restore CRTC state
+ * @lock: lock the CRTC
+ * @unlock: unlock the CRTC
+ * @shadow_allocate: allocate shadow pixmap
+ * @shadow_create: create shadow pixmap for rotation support
+ * @shadow_destroy: free shadow pixmap
+ * @mode_fixup: fixup proposed mode
+ * @mode_set: set the desired mode on the CRTC
+ * @gamma_set: specify color ramp for CRTC
+ * @destroy: deinit and free object.
+ *
+ * The drm_crtc_funcs structure is the central CRTC management structure
+ * in the DRM.  Each CRTC controls one or more connectors (note that the name
+ * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc.
+ * connectors, not just CRTs).
+ *
+ * Each driver is responsible for filling out this structure at startup time,
+ * in addition to providing other modesetting features, like i2c and DDC
+ * bus accessors.
+ */
+struct drm_crtc_funcs {
+       /* Save CRTC state */
+       void (*save)(struct drm_crtc *crtc); /* suspend? */
+       /* Restore CRTC state */
+       void (*restore)(struct drm_crtc *crtc); /* resume? */
+
+       /* cursor controls */
+       int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,
+                         uint32_t handle, uint32_t width, uint32_t height);
+       int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
+
+       /* Set gamma on the CRTC */
+       void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
+                         uint32_t size);
+       /* Object destroy routine */
+       void (*destroy)(struct drm_crtc *crtc);
+
+       int (*set_config)(struct drm_mode_set *set);
+};
+
+/**
+ * drm_crtc - central CRTC control structure
+ * @enabled: is this CRTC enabled?
+ * @x: x position on screen
+ * @y: y position on screen
+ * @desired_mode: new desired mode
+ * @desired_x: desired x for desired_mode
+ * @desired_y: desired y for desired_mode
+ * @funcs: CRTC control functions
+ *
+ * Each CRTC may have one or more connectors associated with it.  This structure
+ * allows the CRTC to be controlled.
+ */
+struct drm_crtc {
+       struct drm_device *dev;
+       struct list_head head;
+
+       struct drm_mode_object base;
+
+       /* framebuffer the connector is currently bound to */
+       struct drm_framebuffer *fb;
+
+       bool enabled;
+
+       struct drm_display_mode mode;
+
+       int x, y;
+       struct drm_display_mode *desired_mode;
+       int desired_x, desired_y;
+       const struct drm_crtc_funcs *funcs;
+
+       /* CRTC gamma size for reporting to userspace */
+       uint32_t gamma_size;
+       uint16_t *gamma_store;
+
+       /* if you are using the helper */
+       void *helper_private;
+};
+
+
+/**
+ * drm_connector_funcs - control connectors on a given device
+ * @dpms: set power state (see drm_crtc_funcs above)
+ * @save: save connector state
+ * @restore: restore connector state
+ * @mode_valid: is this mode valid on the given connector?
+ * @mode_fixup: try to fixup proposed mode for this connector
+ * @mode_set: set this mode
+ * @detect: is this connector active?
+ * @get_modes: get mode list for this connector
+ * @set_property: property for this connector may need update
+ * @destroy: make object go away
+ *
+ * Each CRTC may have one or more connectors attached to it.  The functions
+ * below allow the core DRM code to control connectors, enumerate available modes,
+ * etc.
+ */
+struct drm_connector_funcs {
+       void (*dpms)(struct drm_connector *connector, int mode);
+       void (*save)(struct drm_connector *connector);
+       void (*restore)(struct drm_connector *connector);
+       enum drm_connector_status (*detect)(struct drm_connector *connector);
+       void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
+       int (*set_property)(struct drm_connector *connector, struct drm_property *property,
+                            uint64_t val);
+       void (*destroy)(struct drm_connector *connector);
+};
+
+struct drm_encoder_funcs {
+       void (*destroy)(struct drm_encoder *encoder);
+};
+
+#define DRM_CONNECTOR_MAX_UMODES 16
+#define DRM_CONNECTOR_MAX_PROPERTY 16
+#define DRM_CONNECTOR_LEN 32
+#define DRM_CONNECTOR_MAX_ENCODER 2
+
+/**
+ * drm_encoder - central DRM encoder structure
+ */
+struct drm_encoder {
+       struct drm_device *dev;
+       struct list_head head;
+
+       struct drm_mode_object base;
+       int encoder_type;
+       uint32_t possible_crtcs;
+       uint32_t possible_clones;
+
+       struct drm_crtc *crtc;
+       const struct drm_encoder_funcs *funcs;
+       void *helper_private;
+};
+
+/**
+ * drm_connector - central DRM connector control structure
+ * @crtc: CRTC this connector is currently connected to, NULL if none
+ * @interlace_allowed: can this connector handle interlaced modes?
+ * @doublescan_allowed: can this connector handle doublescan?
+ * @available_modes: modes available on this connector (from get_modes() + user)
+ * @initial_x: initial x position for this connector
+ * @initial_y: initial y position for this connector
+ * @status: connector connected?
+ * @funcs: connector control functions
+ *
+ * Each connector may be connected to one or more CRTCs, or may be clonable by
+ * another connector if they can share a CRTC.  Each connector also has a specific
+ * position in the broader display (referred to as a 'screen' though it could
+ * span multiple monitors).
+ */
+struct drm_connector {
+       struct drm_device *dev;
+       struct device kdev;
+       struct device_attribute *attr;
+       struct list_head head;
+
+       struct drm_mode_object base;
+
+       int connector_type;
+       int connector_type_id;
+       bool interlace_allowed;
+       bool doublescan_allowed;
+       struct list_head modes; /* list of modes on this connector */
+
+       int initial_x, initial_y;
+       enum drm_connector_status status;
+
+       /* these are modes added by probing with DDC or the BIOS */
+       struct list_head probed_modes;
+
+       struct drm_display_info display_info;
+       const struct drm_connector_funcs *funcs;
+
+       struct list_head user_modes;
+       struct drm_property_blob *edid_blob_ptr;
+       u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
+       uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
+
+       void *helper_private;
+
+       uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
+       uint32_t force_encoder_id;
+       struct drm_encoder *encoder; /* currently active encoder */
+};
+
+/**
+ * struct drm_mode_set
+ *
+ * Represents a single crtc the connectors that it drives with what mode
+ * and from which framebuffer it scans out from.
+ *
+ * This is used to set modes.
+ */
+struct drm_mode_set {
+       struct list_head head;
+
+       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;
+       struct drm_display_mode *mode;
+
+       uint32_t x;
+       uint32_t y;
+
+       struct drm_connector **connectors;
+       size_t num_connectors;
+};
+
+/**
+ * struct drm_mode_config_funcs - configure CRTCs for a given screen layout
+ * @resize: adjust CRTCs as necessary for the proposed layout
+ *
+ * Currently only a resize hook is available.  DRM will call back into the
+ * driver with a new screen width and height.  If the driver can't support
+ * the proposed size, it can return false.  Otherwise it should adjust
+ * the CRTC<->connector mappings as needed and update its view of the screen.
+ */
+struct drm_mode_config_funcs {
+       struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd);
+       int (*fb_changed)(struct drm_device *dev);
+};
+
+struct drm_mode_group {
+       uint32_t num_crtcs;
+       uint32_t num_encoders;
+       uint32_t num_connectors;
+
+       /* list of object IDs for this group */
+       uint32_t *id_list;
+};
+
+/**
+ * drm_mode_config - Mode configuration control structure
+ *
+ */
+struct drm_mode_config {
+       struct mutex mutex; /* protects configuration and IDR */
+       struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
+       /* this is limited to one for now */
+       int num_fb;
+       struct list_head fb_list;
+       int num_connector;
+       struct list_head connector_list;
+       int num_encoder;
+       struct list_head encoder_list;
+
+       int num_crtc;
+       struct list_head crtc_list;
+
+       struct list_head property_list;
+
+       /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */
+       struct list_head fb_kernel_list;
+
+       int min_width, min_height;
+       int max_width, max_height;
+       struct drm_mode_config_funcs *funcs;
+       unsigned long fb_base;
+
+       /* pointers to standard properties */
+       struct list_head property_blob_list;
+       struct drm_property *edid_property;
+       struct drm_property *dpms_property;
+
+       /* DVI-I properties */
+       struct drm_property *dvi_i_subconnector_property;
+       struct drm_property *dvi_i_select_subconnector_property;
+
+       /* TV properties */
+       struct drm_property *tv_subconnector_property;
+       struct drm_property *tv_select_subconnector_property;
+       struct drm_property *tv_mode_property;
+       struct drm_property *tv_left_margin_property;
+       struct drm_property *tv_right_margin_property;
+       struct drm_property *tv_top_margin_property;
+       struct drm_property *tv_bottom_margin_property;
+
+       /* Optional properties */
+       struct drm_property *scaling_mode_property;
+       struct drm_property *dithering_mode_property;
+};
+
+#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
+#define obj_to_connector(x) container_of(x, struct drm_connector, base)
+#define obj_to_encoder(x) container_of(x, struct drm_encoder, base)
+#define obj_to_mode(x) container_of(x, struct drm_display_mode, base)
+#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base)
+#define obj_to_property(x) container_of(x, struct drm_property, base)
+#define obj_to_blob(x) container_of(x, struct drm_property_blob, base)
+
+
+extern void drm_crtc_init(struct drm_device *dev,
+                         struct drm_crtc *crtc,
+                         const struct drm_crtc_funcs *funcs);
+extern void drm_crtc_cleanup(struct drm_crtc *crtc);
+
+extern void drm_connector_init(struct drm_device *dev,
+                           struct drm_connector *connector,
+                           const struct drm_connector_funcs *funcs,
+                           int connector_type);
+
+extern void drm_connector_cleanup(struct drm_connector *connector);
+
+extern void drm_encoder_init(struct drm_device *dev,
+                            struct drm_encoder *encoder,
+                            const struct drm_encoder_funcs *funcs,
+                            int encoder_type);
+
+extern void drm_encoder_cleanup(struct drm_encoder *encoder);
+
+extern char *drm_get_connector_name(struct drm_connector *connector);
+extern char *drm_get_dpms_name(int val);
+extern char *drm_get_dvi_i_subconnector_name(int val);
+extern char *drm_get_dvi_i_select_name(int val);
+extern char *drm_get_tv_subconnector_name(int val);
+extern char *drm_get_tv_select_name(int val);
+extern void drm_fb_release(struct file *filp);
+extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
+extern struct edid *drm_get_edid(struct drm_connector *connector,
+                                struct i2c_adapter *adapter);
+extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter);
+extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
+extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
+extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode);
+extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+                                                  struct drm_display_mode *mode);
+extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode);
+extern void drm_mode_config_init(struct drm_device *dev);
+extern void drm_mode_config_cleanup(struct drm_device *dev);
+extern void drm_mode_set_name(struct drm_display_mode *mode);
+extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
+extern int drm_mode_width(struct drm_display_mode *mode);
+extern int drm_mode_height(struct drm_display_mode *mode);
+
+/* for us by fb module */
+extern int drm_mode_attachmode_crtc(struct drm_device *dev,
+                                   struct drm_crtc *crtc,
+                                   struct drm_display_mode *mode);
+extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
+
+extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
+extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
+extern void drm_mode_list_concat(struct list_head *head,
+                                struct list_head *new);
+extern void drm_mode_validate_size(struct drm_device *dev,
+                                  struct list_head *mode_list,
+                                  int maxX, int maxY, int maxPitch);
+extern void drm_mode_prune_invalid(struct drm_device *dev,
+                                  struct list_head *mode_list, bool verbose);
+extern void drm_mode_sort(struct list_head *mode_list);
+extern int drm_mode_vrefresh(struct drm_display_mode *mode);
+extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
+                                 int adjust_flags);
+extern void drm_mode_connector_list_update(struct drm_connector *connector);
+extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
+                                               struct edid *edid);
+extern int drm_connector_property_set_value(struct drm_connector *connector,
+                                        struct drm_property *property,
+                                        uint64_t value);
+extern int drm_connector_property_get_value(struct drm_connector *connector,
+                                        struct drm_property *property,
+                                        uint64_t *value);
+extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
+extern void drm_framebuffer_set_object(struct drm_device *dev,
+                                      unsigned long handle);
+extern int drm_framebuffer_init(struct drm_device *dev,
+                               struct drm_framebuffer *fb,
+                               const struct drm_framebuffer_funcs *funcs);
+extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
+extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
+extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
+extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
+extern bool drm_crtc_in_use(struct drm_crtc *crtc);
+
+extern int drm_connector_attach_property(struct drm_connector *connector,
+                                     struct drm_property *property, uint64_t init_val);
+extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                               const char *name, int num_values);
+extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
+extern int drm_property_add_enum(struct drm_property *property, int index,
+                                uint64_t value, const char *name);
+extern int drm_mode_create_dvi_i_properties(struct drm_device *dev);
+extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats,
+                                    char *formats[]);
+extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
+extern int drm_mode_create_dithering_property(struct drm_device *dev);
+extern char *drm_get_encoder_name(struct drm_encoder *encoder);
+
+extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
+                                            struct drm_encoder *encoder);
+extern void drm_mode_connector_detach_encoder(struct drm_connector *connector,
+                                          struct drm_encoder *encoder);
+extern bool drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
+                                        int gamma_size);
+extern void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type);
+/* IOCTLs */
+extern int drm_mode_getresources(struct drm_device *dev,
+                                void *data, struct drm_file *file_priv);
+
+extern int drm_mode_getcrtc(struct drm_device *dev,
+                           void *data, struct drm_file *file_priv);
+extern int drm_mode_getconnector(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv);
+extern int drm_mode_setcrtc(struct drm_device *dev,
+                           void *data, struct drm_file *file_priv);
+extern int drm_mode_cursor_ioctl(struct drm_device *dev,
+                               void *data, struct drm_file *file_priv);
+extern int drm_mode_addfb(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
+extern int drm_mode_rmfb(struct drm_device *dev,
+                        void *data, struct drm_file *file_priv);
+extern int drm_mode_getfb(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
+extern int drm_mode_addmode_ioctl(struct drm_device *dev,
+                                 void *data, struct drm_file *file_priv);
+extern int drm_mode_rmmode_ioctl(struct drm_device *dev,
+                                void *data, struct drm_file *file_priv);
+extern int drm_mode_attachmode_ioctl(struct drm_device *dev,
+                                    void *data, struct drm_file *file_priv);
+extern int drm_mode_detachmode_ioctl(struct drm_device *dev,
+                                    void *data, struct drm_file *file_priv);
+
+extern int drm_mode_getproperty_ioctl(struct drm_device *dev,
+                                     void *data, struct drm_file *file_priv);
+extern int drm_mode_getblob_ioctl(struct drm_device *dev,
+                                 void *data, struct drm_file *file_priv);
+extern int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
+                                             void *data, struct drm_file *file_priv);
+extern int drm_mode_hotplug_ioctl(struct drm_device *dev,
+                                 void *data, struct drm_file *file_priv);
+extern int drm_mode_replacefb(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv);
+extern int drm_mode_getencoder(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv);
+extern int drm_mode_gamma_get_ioctl(struct drm_device *dev,
+                                   void *data, struct drm_file *file_priv);
+extern int drm_mode_gamma_set_ioctl(struct drm_device *dev,
+                                   void *data, struct drm_file *file_priv);
+#endif /* __DRM_CRTC_H__ */
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
new file mode 100644 (file)
index 0000000..4bc04cf
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright Â© 2006 Keith Packard
+ * Copyright Â© 2007-2008 Dave Airlie
+ * Copyright Â© 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The DRM mode setting helper functions are common code for drivers to use if
+ * they wish.  Drivers are not forced to use this code in their
+ * implementations but it would be useful if they code they do use at least
+ * provides a consistent interface and operation to userspace
+ */
+
+#ifndef __DRM_CRTC_HELPER_H__
+#define __DRM_CRTC_HELPER_H__
+
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+
+#include <linux/fb.h>
+
+struct drm_crtc_helper_funcs {
+       /*
+        * Control power levels on the CRTC.  If the mode passed in is
+        * unsupported, the provider must use the next lowest power level.
+        */
+       void (*dpms)(struct drm_crtc *crtc, int mode);
+       void (*prepare)(struct drm_crtc *crtc);
+       void (*commit)(struct drm_crtc *crtc);
+
+       /* Provider can fixup or change mode timings before modeset occurs */
+       bool (*mode_fixup)(struct drm_crtc *crtc,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+       /* Actually set the mode */
+       void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode, int x, int y,
+                        struct drm_framebuffer *old_fb);
+
+       /* Move the crtc on the current fb to the given position *optional* */
+       void (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
+                             struct drm_framebuffer *old_fb);
+};
+
+struct drm_encoder_helper_funcs {
+       void (*dpms)(struct drm_encoder *encoder, int mode);
+       void (*save)(struct drm_encoder *encoder);
+       void (*restore)(struct drm_encoder *encoder);
+
+       bool (*mode_fixup)(struct drm_encoder *encoder,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+       void (*prepare)(struct drm_encoder *encoder);
+       void (*commit)(struct drm_encoder *encoder);
+       void (*mode_set)(struct drm_encoder *encoder,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode);
+       /* detect for DAC style encoders */
+       enum drm_connector_status (*detect)(struct drm_encoder *encoder,
+                                           struct drm_connector *connector);
+};
+
+struct drm_connector_helper_funcs {
+       int (*get_modes)(struct drm_connector *connector);
+       int (*mode_valid)(struct drm_connector *connector,
+                         struct drm_display_mode *mode);
+       struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
+};
+
+extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
+extern void drm_helper_disable_unused_functions(struct drm_device *dev);
+extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
+extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
+extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
+extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
+                                    struct drm_display_mode *mode,
+                                    int x, int y,
+                                    struct drm_framebuffer *old_fb);
+extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc);
+
+extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
+                                         struct drm_mode_fb_cmd *mode_cmd);
+
+static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
+                                      const struct drm_crtc_helper_funcs *funcs)
+{
+       crtc->helper_private = (void *)funcs;
+}
+
+static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
+                                         const struct drm_encoder_helper_funcs *funcs)
+{
+       encoder->helper_private = (void *)funcs;
+}
+
+static inline void drm_connector_helper_add(struct drm_connector *connector,
+                                           const struct drm_connector_helper_funcs *funcs)
+{
+       connector->helper_private = (void *)funcs;
+}
+
+extern int drm_helper_resume_force_mode(struct drm_device *dev);
+#endif
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
new file mode 100644 (file)
index 0000000..c707c15
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright Â© 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __DRM_EDID_H__
+#define __DRM_EDID_H__
+
+#include <linux/types.h>
+
+#define EDID_LENGTH 128
+#define DDC_ADDR 0x50
+
+#ifdef BIG_ENDIAN
+#error "EDID structure is little endian, need big endian versions"
+#else
+
+struct est_timings {
+       u8 t1;
+       u8 t2;
+       u8 mfg_rsvd;
+} __attribute__((packed));
+
+struct std_timing {
+       u8 hsize; /* need to multiply by 8 then add 248 */
+       u8 vfreq:6; /* need to add 60 */
+       u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
+} __attribute__((packed));
+
+/* If detailed data is pixel timing */
+struct detailed_pixel_timing {
+       u8 hactive_lo;
+       u8 hblank_lo;
+       u8 hblank_hi:4;
+       u8 hactive_hi:4;
+       u8 vactive_lo;
+       u8 vblank_lo;
+       u8 vblank_hi:4;
+       u8 vactive_hi:4;
+       u8 hsync_offset_lo;
+       u8 hsync_pulse_width_lo;
+       u8 vsync_pulse_width_lo:4;
+       u8 vsync_offset_lo:4;
+       u8 hsync_pulse_width_hi:2;
+       u8 hsync_offset_hi:2;
+       u8 vsync_pulse_width_hi:2;
+       u8 vsync_offset_hi:2;
+       u8 width_mm_lo;
+       u8 height_mm_lo;
+       u8 height_mm_hi:4;
+       u8 width_mm_hi:4;
+       u8 hborder;
+       u8 vborder;
+       u8 unknown0:1;
+       u8 vsync_positive:1;
+       u8 hsync_positive:1;
+       u8 separate_sync:2;
+       u8 stereo:1;
+       u8 unknown6:1;
+       u8 interlaced:1;
+} __attribute__((packed));
+
+/* If it's not pixel timing, it'll be one of the below */
+struct detailed_data_string {
+       u8 str[13];
+} __attribute__((packed));
+
+struct detailed_data_monitor_range {
+       u8 min_vfreq;
+       u8 max_vfreq;
+       u8 min_hfreq_khz;
+       u8 max_hfreq_khz;
+       u8 pixel_clock_mhz; /* need to multiply by 10 */
+       u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */
+       u8 hfreq_start_khz; /* need to multiply by 2 */
+       u8 c; /* need to divide by 2 */
+       u16 m; /* FIXME: byte order */
+       u8 k;
+       u8 j; /* need to divide by 2 */
+} __attribute__((packed));
+
+struct detailed_data_wpindex {
+       u8 white_y_lo:2;
+       u8 white_x_lo:2;
+       u8 pad:4;
+       u8 white_x_hi;
+       u8 white_y_hi;
+       u8 gamma; /* need to divide by 100 then add 1 */
+} __attribute__((packed));
+
+struct detailed_data_color_point {
+       u8 windex1;
+       u8 wpindex1[3];
+       u8 windex2;
+       u8 wpindex2[3];
+} __attribute__((packed));
+
+struct detailed_non_pixel {
+       u8 pad1;
+       u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
+                   fb=color point data, fa=standard timing data,
+                   f9=undefined, f8=mfg. reserved */
+       u8 pad2;
+       union {
+               struct detailed_data_string str;
+               struct detailed_data_monitor_range range;
+               struct detailed_data_wpindex color;
+               struct std_timing timings[5];
+       } data;
+} __attribute__((packed));
+
+#define EDID_DETAIL_STD_MODES 0xfa
+#define EDID_DETAIL_MONITOR_CPDATA 0xfb
+#define EDID_DETAIL_MONITOR_NAME 0xfc
+#define EDID_DETAIL_MONITOR_RANGE 0xfd
+#define EDID_DETAIL_MONITOR_STRING 0xfe
+#define EDID_DETAIL_MONITOR_SERIAL 0xff
+
+struct detailed_timing {
+       u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */
+       union {
+               struct detailed_pixel_timing pixel_data;
+               struct detailed_non_pixel other_data;
+       } data;
+} __attribute__((packed));
+
+struct edid {
+       u8 header[8];
+       /* Vendor & product info */
+       u8 mfg_id[2];
+       u8 prod_code[2];
+       u32 serial; /* FIXME: byte order */
+       u8 mfg_week;
+       u8 mfg_year;
+       /* EDID version */
+       u8 version;
+       u8 revision;
+       /* Display info: */
+       /*   input definition */
+       u8 serration_vsync:1;
+       u8 sync_on_green:1;
+       u8 composite_sync:1;
+       u8 separate_syncs:1;
+       u8 blank_to_black:1;
+       u8 video_level:2;
+       u8 digital:1; /* bits below must be zero if set */
+       u8 width_cm;
+       u8 height_cm;
+       u8 gamma;
+       /*   feature support */
+       u8 default_gtf:1;
+       u8 preferred_timing:1;
+       u8 standard_color:1;
+       u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+       u8 pm_active_off:1;
+       u8 pm_suspend:1;
+       u8 pm_standby:1;
+       /* Color characteristics */
+       u8 red_green_lo;
+       u8 black_white_lo;
+       u8 red_x;
+       u8 red_y;
+       u8 green_x;
+       u8 green_y;
+       u8 blue_x;
+       u8 blue_y;
+       u8 white_x;
+       u8 white_y;
+       /* Est. timings and mfg rsvd timings*/
+       struct est_timings established_timings;
+       /* Standard timings 1-8*/
+       struct std_timing standard_timings[8];
+       /* Detailing timings 1-4 */
+       struct detailed_timing detailed_timings[4];
+       /* Number of 128 byte ext. blocks */
+       u8 extensions;
+       /* Checksum */
+       u8 checksum;
+} __attribute__((packed));
+
+#endif /* little endian structs */
+
+#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
+
+#endif /* __DRM_EDID_H__ */
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
new file mode 100644 (file)
index 0000000..601d2bd
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2007 Jakob Bornecrantz <wallbraker@gmail.com>
+ * Copyright (c) 2008 Red Hat Inc.
+ * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
+ * Copyright (c) 2007-2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _DRM_MODE_H
+#define _DRM_MODE_H
+
+#if !defined(__KERNEL__) && !defined(_KERNEL)
+#include <stdint.h>
+#else
+#include <linux/kernel.h>
+#endif
+
+#define DRM_DISPLAY_INFO_LEN   32
+#define DRM_CONNECTOR_NAME_LEN 32
+#define DRM_DISPLAY_MODE_LEN   32
+#define DRM_PROP_NAME_LEN      32
+
+#define DRM_MODE_TYPE_BUILTIN  (1<<0)
+#define DRM_MODE_TYPE_CLOCK_C  ((1<<1) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_CRTC_C   ((1<<2) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_PREFERRED        (1<<3)
+#define DRM_MODE_TYPE_DEFAULT  (1<<4)
+#define DRM_MODE_TYPE_USERDEF  (1<<5)
+#define DRM_MODE_TYPE_DRIVER   (1<<6)
+
+/* Video mode flags */
+/* bit compatible with the xorg definitions. */
+#define DRM_MODE_FLAG_PHSYNC   (1<<0)
+#define DRM_MODE_FLAG_NHSYNC   (1<<1)
+#define DRM_MODE_FLAG_PVSYNC   (1<<2)
+#define DRM_MODE_FLAG_NVSYNC   (1<<3)
+#define DRM_MODE_FLAG_INTERLACE        (1<<4)
+#define DRM_MODE_FLAG_DBLSCAN  (1<<5)
+#define DRM_MODE_FLAG_CSYNC    (1<<6)
+#define DRM_MODE_FLAG_PCSYNC   (1<<7)
+#define DRM_MODE_FLAG_NCSYNC   (1<<8)
+#define DRM_MODE_FLAG_HSKEW    (1<<9) /* hskew provided */
+#define DRM_MODE_FLAG_BCAST    (1<<10)
+#define DRM_MODE_FLAG_PIXMUX   (1<<11)
+#define DRM_MODE_FLAG_DBLCLK   (1<<12)
+#define DRM_MODE_FLAG_CLKDIV2  (1<<13)
+
+/* DPMS flags */
+/* bit compatible with the xorg definitions. */
+#define DRM_MODE_DPMS_ON       0
+#define DRM_MODE_DPMS_STANDBY  1
+#define DRM_MODE_DPMS_SUSPEND  2
+#define DRM_MODE_DPMS_OFF      3
+
+/* Scaling mode options */
+#define DRM_MODE_SCALE_NON_GPU         0
+#define DRM_MODE_SCALE_FULLSCREEN      1
+#define DRM_MODE_SCALE_NO_SCALE                2
+#define DRM_MODE_SCALE_ASPECT          3
+
+/* Dithering mode options */
+#define DRM_MODE_DITHERING_OFF 0
+#define DRM_MODE_DITHERING_ON  1
+
+struct drm_mode_modeinfo {
+       uint32_t clock;
+       uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
+       uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
+
+       uint32_t vrefresh; /* vertical refresh * 1000 */
+
+       uint32_t flags;
+       uint32_t type;
+       char name[DRM_DISPLAY_MODE_LEN];
+};
+
+struct drm_mode_card_res {
+       uint64_t fb_id_ptr;
+       uint64_t crtc_id_ptr;
+       uint64_t connector_id_ptr;
+       uint64_t encoder_id_ptr;
+       uint32_t count_fbs;
+       uint32_t count_crtcs;
+       uint32_t count_connectors;
+       uint32_t count_encoders;
+       uint32_t min_width, max_width;
+       uint32_t min_height, max_height;
+};
+
+struct drm_mode_crtc {
+       uint64_t set_connectors_ptr;
+       uint32_t count_connectors;
+
+       uint32_t crtc_id; /**< Id */
+       uint32_t fb_id; /**< Id of framebuffer */
+
+       uint32_t x, y; /**< Position on the frameuffer */
+
+       uint32_t gamma_size;
+       uint32_t mode_valid;
+       struct drm_mode_modeinfo mode;
+};
+
+#define DRM_MODE_ENCODER_NONE  0
+#define DRM_MODE_ENCODER_DAC   1
+#define DRM_MODE_ENCODER_TMDS  2
+#define DRM_MODE_ENCODER_LVDS  3
+#define DRM_MODE_ENCODER_TVDAC 4
+
+struct drm_mode_get_encoder {
+       uint32_t encoder_id;
+       uint32_t encoder_type;
+
+       uint32_t crtc_id; /**< Id of crtc */
+
+       uint32_t possible_crtcs;
+       uint32_t possible_clones;
+};
+
+/* This is for connectors with multiple signal types. */
+/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
+#define DRM_MODE_SUBCONNECTOR_Automatic        0
+#define DRM_MODE_SUBCONNECTOR_Unknown  0
+#define DRM_MODE_SUBCONNECTOR_DVID     3
+#define DRM_MODE_SUBCONNECTOR_DVIA     4
+#define DRM_MODE_SUBCONNECTOR_Composite        5
+#define DRM_MODE_SUBCONNECTOR_SVIDEO   6
+#define DRM_MODE_SUBCONNECTOR_Component        8
+
+#define DRM_MODE_CONNECTOR_Unknown     0
+#define DRM_MODE_CONNECTOR_VGA         1
+#define DRM_MODE_CONNECTOR_DVII                2
+#define DRM_MODE_CONNECTOR_DVID                3
+#define DRM_MODE_CONNECTOR_DVIA                4
+#define DRM_MODE_CONNECTOR_Composite   5
+#define DRM_MODE_CONNECTOR_SVIDEO      6
+#define DRM_MODE_CONNECTOR_LVDS                7
+#define DRM_MODE_CONNECTOR_Component   8
+#define DRM_MODE_CONNECTOR_9PinDIN     9
+#define DRM_MODE_CONNECTOR_DisplayPort 10
+#define DRM_MODE_CONNECTOR_HDMIA       11
+#define DRM_MODE_CONNECTOR_HDMIB       12
+
+struct drm_mode_get_connector {
+
+       uint64_t encoders_ptr;
+       uint64_t modes_ptr;
+       uint64_t props_ptr;
+       uint64_t prop_values_ptr;
+
+       uint32_t count_modes;
+       uint32_t count_props;
+       uint32_t count_encoders;
+
+       uint32_t encoder_id; /**< Current Encoder */
+       uint32_t connector_id; /**< Id */
+       uint32_t connector_type;
+       uint32_t connector_type_id;
+
+       uint32_t connection;
+       uint32_t mm_width, mm_height; /**< HxW in millimeters */
+       uint32_t subpixel;
+};
+
+#define DRM_MODE_PROP_PENDING  (1<<0)
+#define DRM_MODE_PROP_RANGE    (1<<1)
+#define DRM_MODE_PROP_IMMUTABLE        (1<<2)
+#define DRM_MODE_PROP_ENUM     (1<<3) /* enumerated type with text strings */
+#define DRM_MODE_PROP_BLOB     (1<<4)
+
+struct drm_mode_property_enum {
+       uint64_t value;
+       char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_mode_get_property {
+       uint64_t values_ptr; /* values and blob lengths */
+       uint64_t enum_blob_ptr; /* enum and blob id ptrs */
+
+       uint32_t prop_id;
+       uint32_t flags;
+       char name[DRM_PROP_NAME_LEN];
+
+       uint32_t count_values;
+       uint32_t count_enum_blobs;
+};
+
+struct drm_mode_connector_set_property {
+       uint64_t value;
+       uint32_t prop_id;
+       uint32_t connector_id;
+};
+
+struct drm_mode_get_blob {
+       uint32_t blob_id;
+       uint32_t length;
+       uint64_t data;
+};
+
+struct drm_mode_fb_cmd {
+       uint32_t fb_id;
+       uint32_t width, height;
+       uint32_t pitch;
+       uint32_t bpp;
+       uint32_t depth;
+       /* driver specific handle */
+       uint32_t handle;
+};
+
+struct drm_mode_mode_cmd {
+       uint32_t connector_id;
+       struct drm_mode_modeinfo mode;
+};
+
+#define DRM_MODE_CURSOR_BO     (1<<0)
+#define DRM_MODE_CURSOR_MOVE   (1<<1)
+
+/*
+ * depending on the value in flags diffrent members are used.
+ *
+ * CURSOR_BO uses
+ *    crtc
+ *    width
+ *    height
+ *    handle - if 0 turns the cursor of
+ *
+ * CURSOR_MOVE uses
+ *    crtc
+ *    x
+ *    y
+ */
+struct drm_mode_cursor {
+       uint32_t flags;
+       uint32_t crtc_id;
+       int32_t x;
+       int32_t y;
+       uint32_t width;
+       uint32_t height;
+       /* driver specific handle */
+       uint32_t handle;
+};
+
+struct drm_mode_crtc_lut {
+       uint32_t crtc_id;
+       uint32_t gamma_size;
+
+       /* pointers to arrays */
+       uint64_t red;
+       uint64_t green;
+       uint64_t blue;
+};
+
+#endif
index 480037331e4e39968c0609c0d91a27a6fd4c922c..ee5389d22c64745d72cc985d6024a5eec55176d4 100644 (file)
 
 /* SAREA area needs to be at least a page */
 #if defined(__alpha__)
-#define SAREA_MAX                       0x2000
+#define SAREA_MAX                       0x2000U
 #elif defined(__ia64__)
-#define SAREA_MAX                       0x10000        /* 64kB */
+#define SAREA_MAX                       0x10000U       /* 64kB */
 #else
 /* Intel 830M driver needs at least 8k SAREA */
-#define SAREA_MAX                       0x2000
+#define SAREA_MAX                       0x2000U
 #endif
 
 /** Maximum number of drawables in the SAREA */
index 152b34da927c1d8117c42d06d90a3adc0d214109..b3bcf72dc65623f412c3902a425ffdcd98b9b563 100644 (file)
@@ -113,8 +113,31 @@ typedef struct _drm_i915_sarea {
        int pipeB_y;
        int pipeB_w;
        int pipeB_h;
+
+       /* fill out some space for old userspace triple buffer */
+       drm_handle_t unused_handle;
+       uint32_t unused1, unused2, unused3;
+
+       /* buffer object handles for static buffers. May change
+        * over the lifetime of the client.
+        */
+       uint32_t front_bo_handle;
+       uint32_t back_bo_handle;
+       uint32_t unused_bo_handle;
+       uint32_t depth_bo_handle;
+
 } drm_i915_sarea_t;
 
+/* due to userspace building against these headers we need some compat here */
+#define planeA_x pipeA_x
+#define planeA_y pipeA_y
+#define planeA_w pipeA_w
+#define planeA_h pipeA_h
+#define planeB_x pipeB_x
+#define planeB_y pipeB_y
+#define planeB_w pipeB_w
+#define planeB_h pipeB_h
+
 /* Flags for perf_boxes
  */
 #define I915_BOX_RING_EMPTY    0x1
@@ -160,6 +183,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_SET_TILING        0x21
 #define DRM_I915_GEM_GET_TILING        0x22
 #define DRM_I915_GEM_GET_APERTURE 0x23
+#define DRM_I915_GEM_MMAP_GTT  0x24
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -177,6 +201,8 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
 #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
 #define DRM_IOCTL_I915_VBLANK_SWAP     DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t)
+#define DRM_IOCTL_I915_GEM_INIT                DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init)
+#define DRM_IOCTL_I915_GEM_EXECBUFFER  DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
 #define DRM_IOCTL_I915_GEM_PIN         DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin)
 #define DRM_IOCTL_I915_GEM_UNPIN       DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin)
 #define DRM_IOCTL_I915_GEM_BUSY                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
@@ -187,6 +213,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_PREAD       DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread)
 #define DRM_IOCTL_I915_GEM_PWRITE      DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite)
 #define DRM_IOCTL_I915_GEM_MMAP                DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap)
+#define DRM_IOCTL_I915_GEM_MMAP_GTT    DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt)
 #define DRM_IOCTL_I915_GEM_SET_DOMAIN  DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain)
 #define DRM_IOCTL_I915_GEM_SW_FINISH   DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish)
 #define DRM_IOCTL_I915_GEM_SET_TILING  DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling)
@@ -196,7 +223,7 @@ typedef struct _drm_i915_sarea {
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
  */
-typedef struct _drm_i915_batchbuffer {
+typedef struct drm_i915_batchbuffer {
        int start;              /* agp offset */
        int used;               /* nr bytes in use */
        int DR1;                /* hw flags for GFX_OP_DRAWRECT_INFO */
@@ -382,6 +409,18 @@ struct drm_i915_gem_mmap {
        uint64_t addr_ptr;
 };
 
+struct drm_i915_gem_mmap_gtt {
+       /** Handle for the object being mapped. */
+       uint32_t handle;
+       uint32_t pad;
+       /**
+        * Fake offset to use for subsequent mmap call
+        *
+        * This is a fixed-size type for 32/64 compatibility.
+        */
+       uint64_t offset;
+};
+
 struct drm_i915_gem_set_domain {
        /** Handle for the object */
        uint32_t handle;
index e531783e5d78db542fb4e86c602698bf5824d72b..95ac82340c3bc0914ad08e02bc337a17b0416e39 100644 (file)
@@ -313,6 +313,7 @@ unifdef-y += ptrace.h
 unifdef-y += qnx4_fs.h
 unifdef-y += quota.h
 unifdef-y += random.h
+unifdef-y += irqnr.h
 unifdef-y += reboot.h
 unifdef-y += reiserfs_fs.h
 unifdef-y += reiserfs_xattr.h
index f6b8cf99b596a30820215766fb7e680dedf7e6e1..b16a957030f87e16341efe5b41b476a04e742fc2 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/workqueue.h>
 #include <linux/aio_abi.h>
 #include <linux/uio.h>
+#include <linux/rcupdate.h>
 
 #include <asm/atomic.h>
 
@@ -183,7 +184,7 @@ struct kioctx {
 
        /* This needs improving */
        unsigned long           user_id;
-       struct kioctx           *next;
+       struct hlist_node       list;
 
        wait_queue_head_t       wait;
 
@@ -199,6 +200,8 @@ struct kioctx {
        struct aio_ring_info    ring_info;
 
        struct delayed_work     wq;
+
+       struct rcu_head         rcu_head;
 };
 
 /* prototypes */
index 6a642098e5c3524ad69fd15993268f35ef02cad9..18462c5b8fff91e0b4d5341dac07e4e263907690 100644 (file)
@@ -90,10 +90,11 @@ struct bio {
 
        unsigned int            bi_comp_cpu;    /* completion CPU */
 
+       atomic_t                bi_cnt;         /* pin count */
+
        struct bio_vec          *bi_io_vec;     /* the actual vec list */
 
        bio_end_io_t            *bi_end_io;
-       atomic_t                bi_cnt;         /* pin count */
 
        void                    *bi_private;
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
@@ -101,6 +102,13 @@ struct bio {
 #endif
 
        bio_destructor_t        *bi_destructor; /* destructor */
+
+       /*
+        * We can inline a number of vecs at the end of the bio, to avoid
+        * double allocations for a small number of bio_vecs. This member
+        * MUST obviously be kept at the very end of the bio.
+        */
+       struct bio_vec          bi_inline_vecs[0];
 };
 
 /*
@@ -117,6 +125,7 @@ struct bio {
 #define BIO_CPU_AFFINE 8       /* complete bio on same CPU as submitted */
 #define BIO_NULL_MAPPED 9      /* contains invalid user pages */
 #define BIO_FS_INTEGRITY 10    /* fs owns integrity data, not block layer */
+#define BIO_QUIET      11      /* Make BIO Quiet */
 #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
 
 /*
@@ -211,6 +220,11 @@ static inline void *bio_data(struct bio *bio)
        return NULL;
 }
 
+static inline int bio_has_allocated_vec(struct bio *bio)
+{
+       return bio->bi_io_vec && bio->bi_io_vec != bio->bi_inline_vecs;
+}
+
 /*
  * will die
  */
@@ -332,7 +346,7 @@ struct bio_pair {
 extern struct bio_pair *bio_split(struct bio *bi, int first_sectors);
 extern void bio_pair_release(struct bio_pair *dbio);
 
-extern struct bio_set *bioset_create(int, int);
+extern struct bio_set *bioset_create(unsigned int, unsigned int);
 extern void bioset_free(struct bio_set *);
 
 extern struct bio *bio_alloc(gfp_t, int);
@@ -377,6 +391,7 @@ extern struct bio *bio_copy_user_iov(struct request_queue *,
 extern int bio_uncopy_user(struct bio *);
 void zero_fill_bio(struct bio *bio);
 extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *);
+extern void bvec_free_bs(struct bio_set *, struct bio_vec *, unsigned int);
 extern unsigned int bvec_nr_vecs(unsigned short idx);
 
 /*
@@ -395,13 +410,17 @@ static inline void bio_set_completion_cpu(struct bio *bio, unsigned int cpu)
  */
 #define BIO_POOL_SIZE 2
 #define BIOVEC_NR_POOLS 6
+#define BIOVEC_MAX_IDX (BIOVEC_NR_POOLS - 1)
 
 struct bio_set {
+       struct kmem_cache *bio_slab;
+       unsigned int front_pad;
+
        mempool_t *bio_pool;
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
        mempool_t *bio_integrity_pool;
 #endif
-       mempool_t *bvec_pools[BIOVEC_NR_POOLS];
+       mempool_t *bvec_pool;
 };
 
 struct biovec_slab {
@@ -411,6 +430,7 @@ struct biovec_slab {
 };
 
 extern struct bio_set *fs_bio_set;
+extern struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly;
 
 /*
  * a small number of entries is fine, not going to be performance critical.
index 031a315c0509e5aa9eaa73c080b7e76a44dc95a0..7035cec583b6cd2854d14415139040032089b0ac 100644 (file)
@@ -26,7 +26,6 @@ struct scsi_ioctl_command;
 
 struct request_queue;
 struct elevator_queue;
-typedef struct elevator_queue elevator_t;
 struct request_pm_state;
 struct blk_trace;
 struct request;
@@ -313,7 +312,7 @@ struct request_queue
         */
        struct list_head        queue_head;
        struct request          *last_merge;
-       elevator_t              *elevator;
+       struct elevator_queue   *elevator;
 
        /*
         * the queue request freelist, one for reads and one for writes
@@ -449,6 +448,7 @@ struct request_queue
 #define QUEUE_FLAG_FAIL_IO     12      /* fake timeout */
 #define QUEUE_FLAG_STACKABLE   13      /* supports request stacking */
 #define QUEUE_FLAG_NONROT      14      /* non-rotational device (SSD) */
+#define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
 
 static inline int queue_is_locked(struct request_queue *q)
 {
@@ -522,22 +522,32 @@ enum {
         * TAG_FLUSH    : ordering by tag w/ pre and post flushes
         * TAG_FUA      : ordering by tag w/ pre flush and FUA write
         */
-       QUEUE_ORDERED_NONE      = 0x00,
-       QUEUE_ORDERED_DRAIN     = 0x01,
-       QUEUE_ORDERED_TAG       = 0x02,
-
-       QUEUE_ORDERED_PREFLUSH  = 0x10,
-       QUEUE_ORDERED_POSTFLUSH = 0x20,
-       QUEUE_ORDERED_FUA       = 0x40,
-
-       QUEUE_ORDERED_DRAIN_FLUSH = QUEUE_ORDERED_DRAIN |
-                       QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH,
-       QUEUE_ORDERED_DRAIN_FUA = QUEUE_ORDERED_DRAIN |
-                       QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_FUA,
-       QUEUE_ORDERED_TAG_FLUSH = QUEUE_ORDERED_TAG |
-                       QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH,
-       QUEUE_ORDERED_TAG_FUA   = QUEUE_ORDERED_TAG |
-                       QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_FUA,
+       QUEUE_ORDERED_BY_DRAIN          = 0x01,
+       QUEUE_ORDERED_BY_TAG            = 0x02,
+       QUEUE_ORDERED_DO_PREFLUSH       = 0x10,
+       QUEUE_ORDERED_DO_BAR            = 0x20,
+       QUEUE_ORDERED_DO_POSTFLUSH      = 0x40,
+       QUEUE_ORDERED_DO_FUA            = 0x80,
+
+       QUEUE_ORDERED_NONE              = 0x00,
+
+       QUEUE_ORDERED_DRAIN             = QUEUE_ORDERED_BY_DRAIN |
+                                         QUEUE_ORDERED_DO_BAR,
+       QUEUE_ORDERED_DRAIN_FLUSH       = QUEUE_ORDERED_DRAIN |
+                                         QUEUE_ORDERED_DO_PREFLUSH |
+                                         QUEUE_ORDERED_DO_POSTFLUSH,
+       QUEUE_ORDERED_DRAIN_FUA         = QUEUE_ORDERED_DRAIN |
+                                         QUEUE_ORDERED_DO_PREFLUSH |
+                                         QUEUE_ORDERED_DO_FUA,
+
+       QUEUE_ORDERED_TAG               = QUEUE_ORDERED_BY_TAG |
+                                         QUEUE_ORDERED_DO_BAR,
+       QUEUE_ORDERED_TAG_FLUSH         = QUEUE_ORDERED_TAG |
+                                         QUEUE_ORDERED_DO_PREFLUSH |
+                                         QUEUE_ORDERED_DO_POSTFLUSH,
+       QUEUE_ORDERED_TAG_FUA           = QUEUE_ORDERED_TAG |
+                                         QUEUE_ORDERED_DO_PREFLUSH |
+                                         QUEUE_ORDERED_DO_FUA,
 
        /*
         * Ordered operation sequence
@@ -585,7 +595,6 @@ enum {
 #define blk_fua_rq(rq)         ((rq)->cmd_flags & REQ_FUA)
 #define blk_discard_rq(rq)     ((rq)->cmd_flags & REQ_DISCARD)
 #define blk_bidi_rq(rq)                ((rq)->next_rq != NULL)
-#define blk_empty_barrier(rq)  (blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors)
 /* rq->queuelist of dequeued request must be list_empty() */
 #define blk_queued_rq(rq)      (!list_empty(&(rq)->queuelist))
 
@@ -855,10 +864,10 @@ extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
-extern int blk_do_ordered(struct request_queue *, struct request **);
+extern bool blk_do_ordered(struct request_queue *, struct request **);
 extern unsigned blk_ordered_cur_seq(struct request_queue *);
 extern unsigned blk_ordered_req_seq(struct request *);
-extern void blk_ordered_complete_seq(struct request_queue *, unsigned, int);
+extern bool blk_ordered_complete_seq(struct request_queue *, unsigned, int);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
@@ -977,7 +986,6 @@ static inline void put_dev_sector(Sector p)
 
 struct work_struct;
 int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
-void kblockd_flush_work(struct work_struct *work);
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
        MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
index 777dbf695d449e4b0d03346a8b5c39877ee34d97..27b1bcffe40853e8e1f6c1f629525c94ec2a343e 100644 (file)
@@ -2,7 +2,6 @@
 #define _LINUX_BH_H
 
 extern void local_bh_disable(void);
-extern void __local_bh_enable(void);
 extern void _local_bh_enable(void);
 extern void local_bh_enable(void);
 extern void local_bh_enable_ip(unsigned long ip);
index 3ce64b90118c20346a704d1c727ec9450d7ccb95..8605f8a74df9ba031fb654095bd47b62095aac0f 100644 (file)
@@ -35,6 +35,7 @@ enum bh_state_bits {
        BH_Ordered,     /* ordered write */
        BH_Eopnotsupp,  /* operation not supported (barrier) */
        BH_Unwritten,   /* Buffer is allocated on disk but not written */
+       BH_Quiet,       /* Buffer Error Prinks to be quiet */
 
        BH_PrivateStart,/* not a state bit, but the first bit available
                         * for private allocation by other entities
index 248e6e3b9b734d515e0c74f95aabd1de2dd57b6d..a67a90cf826882bb6ad47c119de04abac49cd91d 100644 (file)
@@ -153,4 +153,8 @@ void vcs_remove_sysfs(struct tty_struct *tty);
 #define VESA_HSYNC_SUSPEND      2
 #define VESA_POWERDOWN          3
 
+#ifdef CONFIG_VGA_CONSOLE
+extern bool vgacon_text_force(void);
+#endif
+
 #endif /* _LINUX_CONSOLE_H */
index 4aaa4afb1cb99f849bb345a8189153e65e94cbcd..096476f1fb356a2c17ab5d267be9a2295f55295a 100644 (file)
@@ -17,7 +17,7 @@ extern int debug_locks_off(void);
 ({                                                                     \
        int __ret = 0;                                                  \
                                                                        \
-       if (unlikely(c)) {                                              \
+       if (!oops_in_progress && unlikely(c)) {                         \
                if (debug_locks_off() && !debug_locks_silent)           \
                        WARN_ON(1);                                     \
                __ret = 1;                                              \
index 2bfda178f274ef5dfbe782fb117d5ea0d80391d4..34161907b2f8c2c397867468395541cf7b78d10b 100644 (file)
@@ -47,6 +47,7 @@ extern int dmi_name_in_vendors(const char *str);
 extern int dmi_name_in_serial(const char *str);
 extern int dmi_available;
 extern int dmi_walk(void (*decode)(const struct dmi_header *));
+extern bool dmi_match(enum dmi_field f, const char *str);
 
 #else
 
@@ -61,6 +62,8 @@ static inline int dmi_name_in_serial(const char *s) { return 0; }
 #define dmi_available 0
 static inline int dmi_walk(void (*decode)(const struct dmi_header *))
        { return -1; }
+static inline bool dmi_match(enum dmi_field f, const char *str)
+       { return false; }
 
 #endif
 
index 92f6f634e3e62ce77c38d46e6ecb88bf396ceea2..7a204256b1550f889f96a666808e805fe749c186 100644 (file)
@@ -28,7 +28,7 @@ typedef void (elevator_activate_req_fn) (struct request_queue *, struct request
 typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct request *);
 
 typedef void *(elevator_init_fn) (struct request_queue *);
-typedef void (elevator_exit_fn) (elevator_t *);
+typedef void (elevator_exit_fn) (struct elevator_queue *);
 
 struct elevator_ops
 {
@@ -62,8 +62,8 @@ struct elevator_ops
 
 struct elv_fs_entry {
        struct attribute attr;
-       ssize_t (*show)(elevator_t *, char *);
-       ssize_t (*store)(elevator_t *, const char *, size_t);
+       ssize_t (*show)(struct elevator_queue *, char *);
+       ssize_t (*store)(struct elevator_queue *, const char *, size_t);
 };
 
 /*
@@ -130,7 +130,7 @@ extern ssize_t elv_iosched_show(struct request_queue *, char *);
 extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t);
 
 extern int elevator_init(struct request_queue *, char *);
-extern void elevator_exit(elevator_t *);
+extern void elevator_exit(struct elevator_queue *);
 extern int elv_rq_merge_ok(struct request *, struct bio *);
 
 /*
index 32368c4f032644bd9b501cc60db32c14843fb2bb..06ca9b21dad23b0d6753d0a92d6cbc2acba81f40 100644 (file)
@@ -81,4 +81,13 @@ static inline void cleanup_fault_attr_dentries(struct fault_attr *attr)
 
 #endif /* CONFIG_FAULT_INJECTION */
 
+#ifdef CONFIG_FAILSLAB
+extern bool should_failslab(size_t size, gfp_t gfpflags);
+#else
+static inline bool should_failslab(size_t size, gfp_t gfpflags)
+{
+       return false;
+}
+#endif /* CONFIG_FAILSLAB */
+
 #endif /* _LINUX_FAULT_INJECT_H */
index 586ab56a3ec3500e601e786e0e858f1980fbc8e5..3bf5bb5a34f9fba43b9248caf434eb6059e6329e 100644 (file)
@@ -25,7 +25,8 @@ union ktime;
 #define FUTEX_WAKE_BITSET      10
 
 #define FUTEX_PRIVATE_FLAG     128
-#define FUTEX_CMD_MASK         ~FUTEX_PRIVATE_FLAG
+#define FUTEX_CLOCK_REALTIME   256
+#define FUTEX_CMD_MASK         ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
 
 #define FUTEX_WAIT_PRIVATE     (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
 #define FUTEX_WAKE_PRIVATE     (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
@@ -164,6 +165,8 @@ union futex_key {
        } both;
 };
 
+#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } }
+
 #ifdef CONFIG_FUTEX
 extern void exit_robust_list(struct task_struct *curr);
 extern void exit_pi_state_list(struct task_struct *curr);
index 3df7742ce2469e4bdc3673ec904b77e9e4eab6f7..16948eaecae3c3d4969cbbeb23d8106b0aeeb5da 100644 (file)
@@ -126,6 +126,7 @@ struct blk_scsi_cmd_filter {
 struct disk_part_tbl {
        struct rcu_head rcu_head;
        int len;
+       struct hd_struct *last_lookup;
        struct hd_struct *part[];
 };
 
index 89a56d79e4c6c4987531a10ad8fed17f3d597bf7..f83288347dda3455e2deaa057112707accacaa93 100644 (file)
@@ -119,13 +119,17 @@ static inline void account_system_vtime(struct task_struct *tsk)
 }
 #endif
 
-#if defined(CONFIG_PREEMPT_RCU) && defined(CONFIG_NO_HZ)
+#if defined(CONFIG_NO_HZ) && !defined(CONFIG_CLASSIC_RCU)
 extern void rcu_irq_enter(void);
 extern void rcu_irq_exit(void);
+extern void rcu_nmi_enter(void);
+extern void rcu_nmi_exit(void);
 #else
 # define rcu_irq_enter() do { } while (0)
 # define rcu_irq_exit() do { } while (0)
-#endif /* CONFIG_PREEMPT_RCU */
+# define rcu_nmi_enter() do { } while (0)
+# define rcu_nmi_exit() do { } while (0)
+#endif /* #if defined(CONFIG_NO_HZ) && !defined(CONFIG_CLASSIC_RCU) */
 
 /*
  * It is safe to do non-atomic ops on ->hardirq_context,
@@ -135,7 +139,6 @@ extern void rcu_irq_exit(void);
  */
 #define __irq_enter()                                  \
        do {                                            \
-               rcu_irq_enter();                        \
                account_system_vtime(current);          \
                add_preempt_count(HARDIRQ_OFFSET);      \
                trace_hardirq_enter();                  \
@@ -154,7 +157,6 @@ extern void irq_enter(void);
                trace_hardirq_exit();                   \
                account_system_vtime(current);          \
                sub_preempt_count(HARDIRQ_OFFSET);      \
-               rcu_irq_exit();                         \
        } while (0)
 
 /*
@@ -166,11 +168,14 @@ extern void irq_exit(void);
        do {                                    \
                ftrace_nmi_enter();             \
                lockdep_off();                  \
+               rcu_nmi_enter();                \
                __irq_enter();                  \
        } while (0)
+
 #define nmi_exit()                             \
        do {                                    \
                __irq_exit();                   \
+               rcu_nmi_exit();                 \
                lockdep_on();                   \
                ftrace_nmi_exit();              \
        } while (0)
index 3eba43878dcb2da2e6d4ad6a8b029ed13e3f8e6a..bd37078c2d7d7ceb9f9f7b9bd2340724ae29c73d 100644 (file)
@@ -42,26 +42,6 @@ enum hrtimer_restart {
        HRTIMER_RESTART,        /* Timer must be restarted */
 };
 
-/*
- * hrtimer callback modes:
- *
- *     HRTIMER_CB_SOFTIRQ:             Callback must run in softirq context
- *     HRTIMER_CB_IRQSAFE_PERCPU:      Callback must run in hardirq context
- *                                     Special mode for tick emulation and
- *                                     scheduler timer. Such timers are per
- *                                     cpu and not allowed to be migrated on
- *                                     cpu unplug.
- *     HRTIMER_CB_IRQSAFE_UNLOCKED:    Callback should run in hardirq context
- *                                     with timer->base lock unlocked
- *                                     used for timers which call wakeup to
- *                                     avoid lock order problems with rq->lock
- */
-enum hrtimer_cb_mode {
-       HRTIMER_CB_SOFTIRQ,
-       HRTIMER_CB_IRQSAFE_PERCPU,
-       HRTIMER_CB_IRQSAFE_UNLOCKED,
-};
-
 /*
  * Values to track state of the timer
  *
@@ -70,7 +50,6 @@ enum hrtimer_cb_mode {
  * 0x00                inactive
  * 0x01                enqueued into rbtree
  * 0x02                callback function running
- * 0x04                callback pending (high resolution mode)
  *
  * Special cases:
  * 0x03                callback function running and enqueued
@@ -92,8 +71,7 @@ enum hrtimer_cb_mode {
 #define HRTIMER_STATE_INACTIVE 0x00
 #define HRTIMER_STATE_ENQUEUED 0x01
 #define HRTIMER_STATE_CALLBACK 0x02
-#define HRTIMER_STATE_PENDING  0x04
-#define HRTIMER_STATE_MIGRATE  0x08
+#define HRTIMER_STATE_MIGRATE  0x04
 
 /**
  * struct hrtimer - the basic hrtimer structure
@@ -109,8 +87,6 @@ enum hrtimer_cb_mode {
  * @function:  timer expiry callback function
  * @base:      pointer to the timer base (per cpu and per clock)
  * @state:     state information (See bit values above)
- * @cb_mode:   high resolution timer feature to select the callback execution
- *              mode
  * @cb_entry:  list head to enqueue an expired timer into the callback list
  * @start_site:        timer statistics field to store the site where the timer
  *             was started
@@ -129,7 +105,6 @@ struct hrtimer {
        struct hrtimer_clock_base       *base;
        unsigned long                   state;
        struct list_head                cb_entry;
-       enum hrtimer_cb_mode            cb_mode;
 #ifdef CONFIG_TIMER_STATS
        int                             start_pid;
        void                            *start_site;
@@ -188,15 +163,11 @@ struct hrtimer_clock_base {
  * @check_clocks:      Indictator, when set evaluate time source and clock
  *                     event devices whether high resolution mode can be
  *                     activated.
- * @cb_pending:                Expired timers are moved from the rbtree to this
- *                     list in the timer interrupt. The list is processed
- *                     in the softirq.
  * @nr_events:         Total number of timer interrupt events
  */
 struct hrtimer_cpu_base {
        spinlock_t                      lock;
        struct hrtimer_clock_base       clock_base[HRTIMER_MAX_CLOCK_BASES];
-       struct list_head                cb_pending;
 #ifdef CONFIG_HIGH_RES_TIMERS
        ktime_t                         expires_next;
        int                             hres_active;
@@ -404,8 +375,7 @@ static inline int hrtimer_active(const struct hrtimer *timer)
  */
 static inline int hrtimer_is_queued(struct hrtimer *timer)
 {
-       return timer->state &
-               (HRTIMER_STATE_ENQUEUED | HRTIMER_STATE_PENDING);
+       return timer->state & HRTIMER_STATE_ENQUEUED;
 }
 
 /*
index 010fb26a15796452b4382ad167e58cc4210e0c38..e99c56de7f56e23a71e0a4b7daca0537c75b3012 100644 (file)
@@ -122,8 +122,6 @@ struct ide_io_ports {
 #define MAX_DRIVES     2       /* per interface; 2 assumed by lots of code */
 #define SECTOR_SIZE    512
 
-#define IDE_LARGE_SEEK(b1,b2,t)        (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
-
 /*
  * Timeouts for various operations:
  */
@@ -172,9 +170,7 @@ typedef int (ide_ack_intr_t)(struct hwif_s *);
 enum {         ide_unknown,    ide_generic,    ide_pci,
                ide_cmd640,     ide_dtc2278,    ide_ali14xx,
                ide_qd65xx,     ide_umc8672,    ide_ht6560b,
-               ide_rz1000,     ide_trm290,
-               ide_cmd646,     ide_cy82c693,   ide_4drives,
-               ide_pmac,       ide_acorn,
+               ide_4drives,    ide_pmac,       ide_acorn,
                ide_au1xxx,     ide_palm3710
 };
 
@@ -496,8 +492,6 @@ enum {
         * when more than one interrupt is needed.
         */
        IDE_AFLAG_LIMIT_NFRAMES         = (1 << 7),
-       /* Seeking in progress. */
-       IDE_AFLAG_SEEKING               = (1 << 8),
        /* Saved TOC information is current. */
        IDE_AFLAG_TOC_VALID             = (1 << 9),
        /* We think that the drive door is locked. */
@@ -845,8 +839,6 @@ typedef struct hwif_s {
        unsigned        extra_ports;    /* number of extra dma ports */
 
        unsigned        present    : 1; /* this interface exists */
-       unsigned        serialized : 1; /* serialized all channel operation */
-       unsigned        sharing_irq: 1; /* 1 = sharing irq with another hwif */
        unsigned        sg_mapped  : 1; /* sg_table and sg_nents are ready */
 
        struct device           gendev;
@@ -909,6 +901,8 @@ typedef struct hwgroup_s {
 
        int req_gen;
        int req_gen_timer;
+
+       spinlock_t lock;
 } ide_hwgroup_t;
 
 typedef struct ide_driver_s ide_driver_t;
@@ -1122,6 +1116,14 @@ enum {
        IDE_PM_COMPLETED,
 };
 
+int generic_ide_suspend(struct device *, pm_message_t);
+int generic_ide_resume(struct device *);
+
+void ide_complete_power_step(ide_drive_t *, struct request *);
+ide_startstop_t ide_start_power_step(ide_drive_t *, struct request *);
+void ide_complete_pm_request(ide_drive_t *, struct request *);
+void ide_check_pm_state(ide_drive_t *, struct request *);
+
 /*
  * Subdrivers support.
  *
@@ -1376,8 +1378,8 @@ enum {
        IDE_HFLAG_LEGACY_IRQS           = (1 << 21),
        /* force use of legacy IRQs */
        IDE_HFLAG_FORCE_LEGACY_IRQS     = (1 << 22),
-       /* limit LBA48 requests to 256 sectors */
-       IDE_HFLAG_RQSIZE_256            = (1 << 23),
+       /* host is TRM290 */
+       IDE_HFLAG_TRM290                = (1 << 23),
        /* use 32-bit I/O ops */
        IDE_HFLAG_IO_32BIT              = (1 << 24),
        /* unmask IRQs */
@@ -1415,6 +1417,9 @@ struct ide_port_info {
 
        ide_pci_enablebit_t     enablebits[2];
        hwif_chipset_t          chipset;
+
+       u16                     max_sectors;    /* if < than the default one */
+
        u32                     host_flags;
        u8                      pio_mask;
        u8                      swdma_mask;
@@ -1610,13 +1615,13 @@ extern struct mutex ide_cfg_mtx;
 /*
  * Structure locking:
  *
- * ide_cfg_mtx and ide_lock together protect changes to
- * ide_hwif_t->{next,hwgroup}
+ * ide_cfg_mtx and hwgroup->lock together protect changes to
+ * ide_hwif_t->next
  * ide_drive_t->next
  *
- * ide_hwgroup_t->busy: ide_lock
- * ide_hwgroup_t->hwif: ide_lock
- * ide_hwif_t->mate: constant, no locking
+ * ide_hwgroup_t->busy: hwgroup->lock
+ * ide_hwgroup_t->hwif: hwgroup->lock
+ * ide_hwif_t->{hwgroup,mate}: constant, no locking
  * ide_drive_t->hwif: constant, no locking
  */
 
index f58a0cf8929a81fb14025ab8683ab32bf8ab539c..be3c484b5242555082763718f4818eacdb37f020 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/irqflags.h>
 #include <linux/smp.h>
 #include <linux/percpu.h>
+#include <linux/irqnr.h>
+
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -251,9 +253,6 @@ enum
        BLOCK_SOFTIRQ,
        TASKLET_SOFTIRQ,
        SCHED_SOFTIRQ,
-#ifdef CONFIG_HIGH_RES_TIMERS
-       HRTIMER_SOFTIRQ,
-#endif
        RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */
 
        NR_SOFTIRQS
index 3dddfa703ebd95ab1253c56397104c2607f98e90..98564dc6447627f0d6c25033e3ba601db819daf1 100644 (file)
@@ -129,9 +129,14 @@ struct irq_chip {
        const char      *typename;
 };
 
+struct timer_rand_state;
+struct irq_2_iommu;
 /**
  * struct irq_desc - interrupt descriptor
  * @irq:               interrupt number for this descriptor
+ * @timer_rand_state:  pointer to timer rand state struct
+ * @kstat_irqs:                irq stats per cpu
+ * @irq_2_iommu:       iommu with this irq
  * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
  * @chip:              low level interrupt hardware access
  * @msi_desc:          MSI descriptor
@@ -143,8 +148,8 @@ struct irq_chip {
  * @depth:             disable-depth, for nested irq_disable() calls
  * @wake_depth:                enable depth, for multiple set_irq_wake() callers
  * @irq_count:         stats field to detect stalled irqs
- * @irqs_unhandled:    stats field for spurious unhandled interrupts
  * @last_unhandled:    aging timer for unhandled count
+ * @irqs_unhandled:    stats field for spurious unhandled interrupts
  * @lock:              locking for SMP
  * @affinity:          IRQ affinity on SMP
  * @cpu:               cpu index useful for balancing
@@ -154,6 +159,13 @@ struct irq_chip {
  */
 struct irq_desc {
        unsigned int            irq;
+#ifdef CONFIG_SPARSE_IRQ
+       struct timer_rand_state *timer_rand_state;
+       unsigned int            *kstat_irqs;
+# ifdef CONFIG_INTR_REMAP
+       struct irq_2_iommu      *irq_2_iommu;
+# endif
+#endif
        irq_flow_handler_t      handle_irq;
        struct irq_chip         *chip;
        struct msi_desc         *msi_desc;
@@ -165,8 +177,8 @@ struct irq_desc {
        unsigned int            depth;          /* nested irq disables */
        unsigned int            wake_depth;     /* nested wake enables */
        unsigned int            irq_count;      /* For detecting broken IRQs */
-       unsigned int            irqs_unhandled;
        unsigned long           last_unhandled; /* Aging timer for unhandled count */
+       unsigned int            irqs_unhandled;
        spinlock_t              lock;
 #ifdef CONFIG_SMP
        cpumask_t               affinity;
@@ -181,12 +193,51 @@ struct irq_desc {
        const char              *name;
 } ____cacheline_internodealigned_in_smp;
 
+extern void early_irq_init(void);
+extern void arch_early_irq_init(void);
+extern void arch_init_chip_data(struct irq_desc *desc, int cpu);
+extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
+                                       struct irq_desc *desc, int cpu);
+extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
 
+#ifndef CONFIG_SPARSE_IRQ
 extern struct irq_desc irq_desc[NR_IRQS];
 
 static inline struct irq_desc *irq_to_desc(unsigned int irq)
 {
-       return (irq < nr_irqs) ? irq_desc + irq : NULL;
+       return (irq < NR_IRQS) ? irq_desc + irq : NULL;
+}
+static inline struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+{
+       return irq_to_desc(irq);
+}
+
+#else
+
+extern struct irq_desc *irq_to_desc(unsigned int irq);
+extern struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu);
+extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu);
+
+# define for_each_irq_desc(irq, desc)          \
+       for (irq = 0, desc = irq_to_desc(irq); irq < nr_irqs; irq++, desc = irq_to_desc(irq))
+# define for_each_irq_desc_reverse(irq, desc)                          \
+       for (irq = nr_irqs - 1, desc = irq_to_desc(irq); irq >= 0; irq--, desc = irq_to_desc(irq))
+
+#define kstat_irqs_this_cpu(DESC) \
+       ((DESC)->kstat_irqs[smp_processor_id()])
+#define kstat_incr_irqs_this_cpu(irqno, DESC) \
+       ((DESC)->kstat_irqs[smp_processor_id()]++)
+
+#endif
+
+static inline struct irq_desc *
+irq_remap_to_desc(unsigned int irq, struct irq_desc *desc)
+{
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+       return irq_to_desc(irq);
+#else
+       return desc;
+#endif
 }
 
 /*
@@ -380,6 +431,11 @@ extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
 #define get_irq_data(irq)      (irq_to_desc(irq)->handler_data)
 #define get_irq_msi(irq)       (irq_to_desc(irq)->msi_desc)
 
+#define get_irq_desc_chip(desc)                ((desc)->chip)
+#define get_irq_desc_chip_data(desc)   ((desc)->chip_data)
+#define get_irq_desc_data(desc)                ((desc)->handler_data)
+#define get_irq_desc_msi(desc)         ((desc)->msi_desc)
+
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
 #endif /* !CONFIG_S390 */
index 452c280c8115525c2c294bebb3104bd6e06645a9..95d2b74641f5dbe2ecb90bb68d430ab600d61b74 100644 (file)
@@ -1,24 +1,38 @@
 #ifndef _LINUX_IRQNR_H
 #define _LINUX_IRQNR_H
 
+/*
+ * Generic irq_desc iterators:
+ */
+#ifdef __KERNEL__
+
 #ifndef CONFIG_GENERIC_HARDIRQS
 #include <asm/irq.h>
 # define nr_irqs               NR_IRQS
 
 # define for_each_irq_desc(irq, desc)          \
        for (irq = 0; irq < nr_irqs; irq++)
+
+# define for_each_irq_desc_reverse(irq, desc)                          \
+       for (irq = nr_irqs - 1; irq >= 0; irq--)
 #else
+
 extern int nr_irqs;
 
+#ifndef CONFIG_SPARSE_IRQ
+
+struct irq_desc;
 # define for_each_irq_desc(irq, desc)          \
        for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
-
-# define for_each_irq_desc_reverse(irq, desc)                          \
-       for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);        \
-            irq >= 0; irq--, desc--)
+# define for_each_irq_desc_reverse(irq, desc)                          \
+       for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1);        \
+           irq >= 0; irq--, desc--)
+#endif
 #endif
 
-#define for_each_irq_nr(irq)                   \
-       for (irq = 0; irq < nr_irqs; irq++)
+#define for_each_irq_nr(irq)                   \
+       for (irq = 0; irq < nr_irqs; irq++)
+
+#endif /* __KERNEL__ */
 
 #endif
index 6002ae76785c9aeba493c0960aa5de508b139b49..ca9ff6411dfa778fed80eae8360b6136529f8f11 100644 (file)
@@ -141,6 +141,15 @@ extern int _cond_resched(void);
                (__x < 0) ? -__x : __x;         \
        })
 
+#ifdef CONFIG_PROVE_LOCKING
+void might_fault(void);
+#else
+static inline void might_fault(void)
+{
+       might_sleep();
+}
+#endif
+
 extern struct atomic_notifier_head panic_notifier_list;
 extern long (*panic_blink)(long time);
 NORET_TYPE void panic(const char * fmt, ...)
@@ -188,6 +197,8 @@ extern unsigned long long memparse(const char *ptr, char **retptr);
 extern int core_kernel_text(unsigned long addr);
 extern int __kernel_text_address(unsigned long addr);
 extern int kernel_text_address(unsigned long addr);
+extern int func_ptr_is_kernel_text(void *ptr);
+
 struct pid;
 extern struct pid *session_of_pgrp(struct pid *pgrp);
 
index 4a145caeee075d3209fa4e0d324dfed7f9a15fe7..4ee4b3d2316ffc78495e7bfa0dd3017f220c05c9 100644 (file)
@@ -28,7 +28,9 @@ struct cpu_usage_stat {
 
 struct kernel_stat {
        struct cpu_usage_stat   cpustat;
-       unsigned int irqs[NR_IRQS];
+#ifndef CONFIG_SPARSE_IRQ
+       unsigned int irqs[NR_IRQS];
+#endif
 };
 
 DECLARE_PER_CPU(struct kernel_stat, kstat);
@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstat);
 
 extern unsigned long long nr_context_switches(void);
 
+#ifndef CONFIG_SPARSE_IRQ
+#define kstat_irqs_this_cpu(irq) \
+       (kstat_this_cpu.irqs[irq])
+
 struct irq_desc;
 
 static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
 {
        kstat_this_cpu.irqs[irq]++;
 }
+#endif
+
 
+#ifndef CONFIG_SPARSE_IRQ
 static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
 {
        return kstat_cpu(cpu).irqs[irq];
 }
+#else
+extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
+#endif
 
 /*
  * Number of interrupts per specific IRQ source, since bootup
index e7217dc58f398fb7e6d11897faf2e7ac3d0dbfae..a53407a4165c838ee457ee368e03758e3cea5560 100644 (file)
@@ -54,9 +54,13 @@ struct lguest_vqconfig {
 /* Write command first word is a request. */
 enum lguest_req
 {
-       LHREQ_INITIALIZE, /* + base, pfnlimit, pgdir, start */
+       LHREQ_INITIALIZE, /* + base, pfnlimit, start */
        LHREQ_GETDMA, /* No longer used */
        LHREQ_IRQ, /* + irq */
        LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
 };
+
+/* The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize for historical reasons. */
+#define LGUEST_VRING_ALIGN     4096
 #endif /* _LINUX_LGUEST_LAUNCHER */
index ed3f26eb5df1421287ea41d17feed10be87cafeb..3449de597eff8810a1538672da316f33a6ad6cd6 100644 (file)
@@ -213,10 +213,11 @@ enum {
        ATA_PFLAG_FROZEN        = (1 << 2), /* port is frozen */
        ATA_PFLAG_RECOVERED     = (1 << 3), /* recovery action performed */
        ATA_PFLAG_LOADING       = (1 << 4), /* boot/loading probe */
-       ATA_PFLAG_UNLOADING     = (1 << 5), /* module is unloading */
        ATA_PFLAG_SCSI_HOTPLUG  = (1 << 6), /* SCSI hotplug scheduled */
        ATA_PFLAG_INITIALIZING  = (1 << 7), /* being initialized, don't touch */
        ATA_PFLAG_RESETTING     = (1 << 8), /* reset in progress */
+       ATA_PFLAG_UNLOADING     = (1 << 9), /* driver is being unloaded */
+       ATA_PFLAG_UNLOADED      = (1 << 10), /* driver is unloaded */
 
        ATA_PFLAG_SUSPENDED     = (1 << 17), /* port is suspended (power) */
        ATA_PFLAG_PM_PENDING    = (1 << 18), /* PM operation pending */
@@ -1285,26 +1286,62 @@ static inline int ata_link_active(struct ata_link *link)
        return ata_tag_valid(link->active_tag) || link->sactive;
 }
 
-extern struct ata_link *__ata_port_next_link(struct ata_port *ap,
-                                            struct ata_link *link,
-                                            bool dev_only);
+/*
+ * Iterators
+ *
+ * ATA_LITER_* constants are used to select link iteration mode and
+ * ATA_DITER_* device iteration mode.
+ *
+ * For a custom iteration directly using ata_{link|dev}_next(), if
+ * @link or @dev, respectively, is NULL, the first element is
+ * returned.  @dev and @link can be any valid device or link and the
+ * next element according to the iteration mode will be returned.
+ * After the last element, NULL is returned.
+ */
+enum ata_link_iter_mode {
+       ATA_LITER_EDGE,         /* if present, PMP links only; otherwise,
+                                * host link.  no slave link */
+       ATA_LITER_HOST_FIRST,   /* host link followed by PMP or slave links */
+       ATA_LITER_PMP_FIRST,    /* PMP links followed by host link,
+                                * slave link still comes after host link */
+};
 
-#define __ata_port_for_each_link(link, ap) \
-       for ((link) = __ata_port_next_link((ap), NULL, false); (link); \
-            (link) = __ata_port_next_link((ap), (link), false))
+enum ata_dev_iter_mode {
+       ATA_DITER_ENABLED,
+       ATA_DITER_ENABLED_REVERSE,
+       ATA_DITER_ALL,
+       ATA_DITER_ALL_REVERSE,
+};
 
-#define ata_port_for_each_link(link, ap) \
-       for ((link) = __ata_port_next_link((ap), NULL, true); (link); \
-            (link) = __ata_port_next_link((ap), (link), true))
+extern struct ata_link *ata_link_next(struct ata_link *link,
+                                     struct ata_port *ap,
+                                     enum ata_link_iter_mode mode);
 
-#define ata_link_for_each_dev(dev, link) \
-       for ((dev) = (link)->device; \
-            (dev) < (link)->device + ata_link_max_devices(link) || ((dev) = NULL); \
-            (dev)++)
+extern struct ata_device *ata_dev_next(struct ata_device *dev,
+                                      struct ata_link *link,
+                                      enum ata_dev_iter_mode mode);
+
+/*
+ * Shortcut notation for iterations
+ *
+ * ata_for_each_link() iterates over each link of @ap according to
+ * @mode.  @link points to the current link in the loop.  @link is
+ * NULL after loop termination.  ata_for_each_dev() works the same way
+ * except that it iterates over each device of @link.
+ *
+ * Note that the mode prefixes ATA_{L|D}ITER_ shouldn't need to be
+ * specified when using the following shorthand notations.  Only the
+ * mode itself (EDGE, HOST_FIRST, ENABLED, etc...) should be
+ * specified.  This not only increases brevity but also makes it
+ * impossible to use ATA_LITER_* for device iteration or vice-versa.
+ */
+#define ata_for_each_link(link, ap, mode) \
+       for ((link) = ata_link_next(NULL, (ap), ATA_LITER_##mode); (link); \
+            (link) = ata_link_next((link), (ap), ATA_LITER_##mode))
 
-#define ata_link_for_each_dev_reverse(dev, link) \
-       for ((dev) = (link)->device + ata_link_max_devices(link) - 1; \
-            (dev) >= (link)->device || ((dev) = NULL); (dev)--)
+#define ata_for_each_dev(dev, link, mode) \
+       for ((dev) = ata_dev_next(NULL, (link), ATA_DITER_##mode); (dev); \
+            (dev) = ata_dev_next((dev), (link), ATA_DITER_##mode))
 
 /**
  *     ata_ncq_enabled - Test whether NCQ is enabled
index 29aec6e100203da5e8b0f40ab726360ca08b8e72..23bf02fb124ffae0dfb282453582385ea34d1919 100644 (file)
@@ -73,6 +73,8 @@ struct lock_class_key {
        struct lockdep_subclass_key     subkeys[MAX_LOCKDEP_SUBCLASSES];
 };
 
+#define LOCKSTAT_POINTS                4
+
 /*
  * The lock-class itself:
  */
@@ -119,7 +121,8 @@ struct lock_class {
        int                             name_version;
 
 #ifdef CONFIG_LOCK_STAT
-       unsigned long                   contention_point[4];
+       unsigned long                   contention_point[LOCKSTAT_POINTS];
+       unsigned long                   contending_point[LOCKSTAT_POINTS];
 #endif
 };
 
@@ -144,6 +147,7 @@ enum bounce_type {
 
 struct lock_class_stats {
        unsigned long                   contention_point[4];
+       unsigned long                   contending_point[4];
        struct lock_time                read_waittime;
        struct lock_time                write_waittime;
        struct lock_time                read_holdtime;
@@ -165,6 +169,7 @@ struct lockdep_map {
        const char                      *name;
 #ifdef CONFIG_LOCK_STAT
        int                             cpu;
+       unsigned long                   ip;
 #endif
 };
 
@@ -309,8 +314,15 @@ extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 extern void lock_release(struct lockdep_map *lock, int nested,
                         unsigned long ip);
 
-extern void lock_set_subclass(struct lockdep_map *lock, unsigned int subclass,
-                             unsigned long ip);
+extern void lock_set_class(struct lockdep_map *lock, const char *name,
+                          struct lock_class_key *key, unsigned int subclass,
+                          unsigned long ip);
+
+static inline void lock_set_subclass(struct lockdep_map *lock,
+               unsigned int subclass, unsigned long ip)
+{
+       lock_set_class(lock, lock->name, lock->key, subclass, ip);
+}
 
 # define INIT_LOCKDEP                          .lockdep_recursion = 0,
 
@@ -328,6 +340,7 @@ static inline void lockdep_on(void)
 
 # define lock_acquire(l, s, t, r, c, n, i)     do { } while (0)
 # define lock_release(l, n, i)                 do { } while (0)
+# define lock_set_class(l, n, k, s, i)         do { } while (0)
 # define lock_set_subclass(l, s, i)            do { } while (0)
 # define lockdep_init()                                do { } while (0)
 # define lockdep_info()                                do { } while (0)
@@ -356,7 +369,7 @@ struct lock_class_key { };
 #ifdef CONFIG_LOCK_STAT
 
 extern void lock_contended(struct lockdep_map *lock, unsigned long ip);
-extern void lock_acquired(struct lockdep_map *lock);
+extern void lock_acquired(struct lockdep_map *lock, unsigned long ip);
 
 #define LOCK_CONTENDED(_lock, try, lock)                       \
 do {                                                           \
@@ -364,20 +377,20 @@ do {                                                              \
                lock_contended(&(_lock)->dep_map, _RET_IP_);    \
                lock(_lock);                                    \
        }                                                       \
-       lock_acquired(&(_lock)->dep_map);                       \
+       lock_acquired(&(_lock)->dep_map, _RET_IP_);                     \
 } while (0)
 
 #else /* CONFIG_LOCK_STAT */
 
 #define lock_contended(lockdep_map, ip) do {} while (0)
-#define lock_acquired(lockdep_map) do {} while (0)
+#define lock_acquired(lockdep_map, ip) do {} while (0)
 
 #define LOCK_CONTENDED(_lock, try, lock) \
        lock(_lock)
 
 #endif /* CONFIG_LOCK_STAT */
 
-#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS)
+#ifdef CONFIG_GENERIC_HARDIRQS
 extern void early_init_irq_lock_class(void);
 #else
 static inline void early_init_irq_lock_class(void)
@@ -481,4 +494,22 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 # define lock_map_release(l)                   do { } while (0)
 #endif
 
+#ifdef CONFIG_PROVE_LOCKING
+# define might_lock(lock)                                              \
+do {                                                                   \
+       typecheck(struct lockdep_map *, &(lock)->dep_map);              \
+       lock_acquire(&(lock)->dep_map, 0, 0, 0, 2, NULL, _THIS_IP_);    \
+       lock_release(&(lock)->dep_map, 0, _THIS_IP_);                   \
+} while (0)
+# define might_lock_read(lock)                                                 \
+do {                                                                   \
+       typecheck(struct lockdep_map *, &(lock)->dep_map);              \
+       lock_acquire(&(lock)->dep_map, 0, 0, 1, 2, NULL, _THIS_IP_);    \
+       lock_release(&(lock)->dep_map, 0, _THIS_IP_);                   \
+} while (0)
+#else
+# define might_lock(lock) do { } while (0)
+# define might_lock_read(lock) do { } while (0)
+#endif
+
 #endif /* __LINUX_LOCKDEP_H */
index fe825471d5aaf9d59440a7f322989004736ea71f..9cfc9b627fdd745d4702a903e29db36f2676aa34 100644 (file)
@@ -232,8 +232,9 @@ struct mm_struct {
        struct core_state *core_state; /* coredumping support */
 
        /* aio bits */
-       rwlock_t                ioctx_list_lock;        /* aio lock */
-       struct kioctx           *ioctx_list;
+       spinlock_t              ioctx_lock;
+       struct hlist_head       ioctx_list;
+
 #ifdef CONFIG_MM_OWNER
        /*
         * "owner" points to a task that is regarded as the canonical
index 8f293922720735ee164cf4b5183f064d09e9f5a6..d2b8a1e8ca11000cf622717ab3302bf9a64888c3 100644 (file)
@@ -10,8 +10,11 @@ struct msi_msg {
 };
 
 /* Helper functions */
+struct irq_desc;
 extern void mask_msi_irq(unsigned int irq);
 extern void unmask_msi_irq(unsigned int irq);
+extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
+extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
index bc6da10ceee002ef14850e8025839e67d0d87c48..7a0e5c4f8072c53f4b0d6a7dfa681355324e065f 100644 (file)
@@ -144,6 +144,8 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
 /*
  * NOTE: mutex_trylock() follows the spin_trylock() convention,
  *       not the down_trylock() convention!
+ *
+ * Returns 1 if the mutex has been acquired successfully, and 0 on contention.
  */
 extern int mutex_trylock(struct mutex *lock);
 extern void mutex_unlock(struct mutex *lock);
index a8efcfeea7323365b65ac3b6098e053af3f14de7..3d327b67d7e2b5927cab4739a061dbf35a10f91e 100644 (file)
@@ -26,8 +26,7 @@ extern struct bus_type of_platform_bus_type;
 
 /*
  * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type) (or ISA, EBUS and SBUS
- * busses on sparc).
+ * the "platform bus" (of_platform_bus_type).
  */
 struct of_platform_driver
 {
index 5231861f357de5e3b2015ac4d8ca1d0badfefa70..1ce9fe572e514ef60a985d1ea050c36f48edb21b 100644 (file)
@@ -86,8 +86,7 @@ int oprofile_arch_init(struct oprofile_operations * ops);
 void oprofile_arch_exit(void);
 
 /**
- * Add a sample. This may be called from any context. Pass
- * smp_processor_id() as cpu.
+ * Add a sample. This may be called from any context.
  */
 void oprofile_add_sample(struct pt_regs * const regs, unsigned long event);
 
index a7c7213555492520e649a4920d9fc671e88460cd..4f71bf4e628c0796a398fa8ad0bd84b95efe1ee8 100644 (file)
@@ -45,7 +45,11 @@ struct k_itimer {
        int it_requeue_pending;         /* waiting to requeue this timer */
 #define REQUEUE_PENDING 1
        int it_sigev_notify;            /* notify word of sigevent struct */
-       struct task_struct *it_process; /* process to send signal to */
+       struct signal_struct *it_signal;
+       union {
+               struct pid *it_pid;     /* pid of process to send signal to */
+               struct task_struct *it_process; /* for clock_nanosleep */
+       };
        struct sigqueue *sigq;          /* signal queue entry. */
        union {
                struct {
index 36f125c0c6037f0270941e96e63790151a66fe34..adbf3bd3c6b3c8edea3e313a4abce0a736d02ebf 100644 (file)
@@ -8,6 +8,7 @@
 #define _LINUX_RANDOM_H
 
 #include <linux/ioctl.h>
+#include <linux/irqnr.h>
 
 /* ioctl()'s for the random number generator */
 
@@ -44,6 +45,56 @@ struct rand_pool_info {
 
 extern void rand_initialize_irq(int irq);
 
+struct timer_rand_state;
+#ifndef CONFIG_SPARSE_IRQ
+
+extern struct timer_rand_state *irq_timer_state[];
+
+static inline struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+       if (irq >= nr_irqs)
+               return NULL;
+
+       return irq_timer_state[irq];
+}
+
+static inline void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+       if (irq >= nr_irqs)
+               return;
+
+       irq_timer_state[irq] = state;
+}
+
+#else
+
+#include <linux/irq.h>
+static inline struct timer_rand_state *get_timer_rand_state(unsigned int irq)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+
+       if (!desc)
+               return NULL;
+
+       return desc->timer_rand_state;
+}
+
+static inline void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+
+       if (!desc)
+               return;
+
+       desc->timer_rand_state = state;
+}
+#endif
+
+
 extern void add_input_randomness(unsigned int type, unsigned int code,
                                 unsigned int value);
 extern void add_interrupt_randomness(int irq);
index 5f89b62e6983192befd7cc827df50fb53cd0a173..301dda829e37499f5cdaa0950e3a11f0c4ed3b74 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/seqlock.h>
 
 #ifdef CONFIG_RCU_CPU_STALL_DETECTOR
-#define RCU_SECONDS_TILL_STALL_CHECK   ( 3 * HZ) /* for rcp->jiffies_stall */
+#define RCU_SECONDS_TILL_STALL_CHECK   (10 * HZ) /* for rcp->jiffies_stall */
 #define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ) /* for rcp->jiffies_stall */
 #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
index 895dc9c1088c767ce4706814b806c20248423241..1168fbcea8d4bc6a42d4abccf5b05e47266aa418 100644 (file)
@@ -52,11 +52,15 @@ struct rcu_head {
        void (*func)(struct rcu_head *head);
 };
 
-#ifdef CONFIG_CLASSIC_RCU
+#if defined(CONFIG_CLASSIC_RCU)
 #include <linux/rcuclassic.h>
-#else /* #ifdef CONFIG_CLASSIC_RCU */
+#elif defined(CONFIG_TREE_RCU)
+#include <linux/rcutree.h>
+#elif defined(CONFIG_PREEMPT_RCU)
 #include <linux/rcupreempt.h>
-#endif /* #else #ifdef CONFIG_CLASSIC_RCU */
+#else
+#error "Unknown RCU implementation specified to kernel configuration"
+#endif /* #else #if defined(CONFIG_CLASSIC_RCU) */
 
 #define RCU_HEAD_INIT  { .next = NULL, .func = NULL }
 #define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
new file mode 100644 (file)
index 0000000..d4368b7
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion (tree-based version)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ *
+ * Copyright IBM Corporation, 2008
+ *
+ * Author: Dipankar Sarma <dipankar@in.ibm.com>
+ *        Paul E. McKenney <paulmck@linux.vnet.ibm.com> Hierarchical algorithm
+ *
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *     Documentation/RCU
+ */
+
+#ifndef __LINUX_RCUTREE_H
+#define __LINUX_RCUTREE_H
+
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/percpu.h>
+#include <linux/cpumask.h>
+#include <linux/seqlock.h>
+
+/*
+ * Define shape of hierarchy based on NR_CPUS and CONFIG_RCU_FANOUT.
+ * In theory, it should be possible to add more levels straightforwardly.
+ * In practice, this has not been tested, so there is probably some
+ * bug somewhere.
+ */
+#define MAX_RCU_LVLS 3
+#define RCU_FANOUT           (CONFIG_RCU_FANOUT)
+#define RCU_FANOUT_SQ        (RCU_FANOUT * RCU_FANOUT)
+#define RCU_FANOUT_CUBE              (RCU_FANOUT_SQ * RCU_FANOUT)
+
+#if NR_CPUS <= RCU_FANOUT
+#  define NUM_RCU_LVLS       1
+#  define NUM_RCU_LVL_0              1
+#  define NUM_RCU_LVL_1              (NR_CPUS)
+#  define NUM_RCU_LVL_2              0
+#  define NUM_RCU_LVL_3              0
+#elif NR_CPUS <= RCU_FANOUT_SQ
+#  define NUM_RCU_LVLS       2
+#  define NUM_RCU_LVL_0              1
+#  define NUM_RCU_LVL_1              (((NR_CPUS) + RCU_FANOUT - 1) / RCU_FANOUT)
+#  define NUM_RCU_LVL_2              (NR_CPUS)
+#  define NUM_RCU_LVL_3              0
+#elif NR_CPUS <= RCU_FANOUT_CUBE
+#  define NUM_RCU_LVLS       3
+#  define NUM_RCU_LVL_0              1
+#  define NUM_RCU_LVL_1              (((NR_CPUS) + RCU_FANOUT_SQ - 1) / RCU_FANOUT_SQ)
+#  define NUM_RCU_LVL_2              (((NR_CPUS) + (RCU_FANOUT) - 1) / (RCU_FANOUT))
+#  define NUM_RCU_LVL_3              NR_CPUS
+#else
+# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
+#endif /* #if (NR_CPUS) <= RCU_FANOUT */
+
+#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3)
+#define NUM_RCU_NODES (RCU_SUM - NR_CPUS)
+
+/*
+ * Dynticks per-CPU state.
+ */
+struct rcu_dynticks {
+       int dynticks_nesting;   /* Track nesting level, sort of. */
+       int dynticks;           /* Even value for dynticks-idle, else odd. */
+       int dynticks_nmi;       /* Even value for either dynticks-idle or */
+                               /*  not in nmi handler, else odd.  So this */
+                               /*  remains even for nmi from irq handler. */
+};
+
+/*
+ * Definition for node within the RCU grace-period-detection hierarchy.
+ */
+struct rcu_node {
+       spinlock_t lock;
+       unsigned long qsmask;   /* CPUs or groups that need to switch in */
+                               /*  order for current grace period to proceed.*/
+       unsigned long qsmaskinit;
+                               /* Per-GP initialization for qsmask. */
+       unsigned long grpmask;  /* Mask to apply to parent qsmask. */
+       int     grplo;          /* lowest-numbered CPU or group here. */
+       int     grphi;          /* highest-numbered CPU or group here. */
+       u8      grpnum;         /* CPU/group number for next level up. */
+       u8      level;          /* root is at level 0. */
+       struct rcu_node *parent;
+} ____cacheline_internodealigned_in_smp;
+
+/* Index values for nxttail array in struct rcu_data. */
+#define RCU_DONE_TAIL          0       /* Also RCU_WAIT head. */
+#define RCU_WAIT_TAIL          1       /* Also RCU_NEXT_READY head. */
+#define RCU_NEXT_READY_TAIL    2       /* Also RCU_NEXT head. */
+#define RCU_NEXT_TAIL          3
+#define RCU_NEXT_SIZE          4
+
+/* Per-CPU data for read-copy update. */
+struct rcu_data {
+       /* 1) quiescent-state and grace-period handling : */
+       long            completed;      /* Track rsp->completed gp number */
+                                       /*  in order to detect GP end. */
+       long            gpnum;          /* Highest gp number that this CPU */
+                                       /*  is aware of having started. */
+       long            passed_quiesc_completed;
+                                       /* Value of completed at time of qs. */
+       bool            passed_quiesc;  /* User-mode/idle loop etc. */
+       bool            qs_pending;     /* Core waits for quiesc state. */
+       bool            beenonline;     /* CPU online at least once. */
+       struct rcu_node *mynode;        /* This CPU's leaf of hierarchy */
+       unsigned long grpmask;          /* Mask to apply to leaf qsmask. */
+
+       /* 2) batch handling */
+       /*
+        * If nxtlist is not NULL, it is partitioned as follows.
+        * Any of the partitions might be empty, in which case the
+        * pointer to that partition will be equal to the pointer for
+        * the following partition.  When the list is empty, all of
+        * the nxttail elements point to nxtlist, which is NULL.
+        *
+        * [*nxttail[RCU_NEXT_READY_TAIL], NULL = *nxttail[RCU_NEXT_TAIL]):
+        *      Entries that might have arrived after current GP ended
+        * [*nxttail[RCU_WAIT_TAIL], *nxttail[RCU_NEXT_READY_TAIL]):
+        *      Entries known to have arrived before current GP ended
+        * [*nxttail[RCU_DONE_TAIL], *nxttail[RCU_WAIT_TAIL]):
+        *      Entries that batch # <= ->completed - 1: waiting for current GP
+        * [nxtlist, *nxttail[RCU_DONE_TAIL]):
+        *      Entries that batch # <= ->completed
+        *      The grace period for these entries has completed, and
+        *      the other grace-period-completed entries may be moved
+        *      here temporarily in rcu_process_callbacks().
+        */
+       struct rcu_head *nxtlist;
+       struct rcu_head **nxttail[RCU_NEXT_SIZE];
+       long            qlen;           /* # of queued callbacks */
+       long            blimit;         /* Upper limit on a processed batch */
+
+#ifdef CONFIG_NO_HZ
+       /* 3) dynticks interface. */
+       struct rcu_dynticks *dynticks;  /* Shared per-CPU dynticks state. */
+       int dynticks_snap;              /* Per-GP tracking for dynticks. */
+       int dynticks_nmi_snap;          /* Per-GP tracking for dynticks_nmi. */
+#endif /* #ifdef CONFIG_NO_HZ */
+
+       /* 4) reasons this CPU needed to be kicked by force_quiescent_state */
+#ifdef CONFIG_NO_HZ
+       unsigned long dynticks_fqs;     /* Kicked due to dynticks idle. */
+#endif /* #ifdef CONFIG_NO_HZ */
+       unsigned long offline_fqs;      /* Kicked due to being offline. */
+       unsigned long resched_ipi;      /* Sent a resched IPI. */
+
+       /* 5) state to allow this CPU to force_quiescent_state on others */
+       long n_rcu_pending;             /* rcu_pending() calls since boot. */
+       long n_rcu_pending_force_qs;    /* when to force quiescent states. */
+
+       int cpu;
+};
+
+/* Values for signaled field in struct rcu_state. */
+#define RCU_GP_INIT            0       /* Grace period being initialized. */
+#define RCU_SAVE_DYNTICK       1       /* Need to scan dyntick state. */
+#define RCU_FORCE_QS           2       /* Need to force quiescent state. */
+#ifdef CONFIG_NO_HZ
+#define RCU_SIGNAL_INIT                RCU_SAVE_DYNTICK
+#else /* #ifdef CONFIG_NO_HZ */
+#define RCU_SIGNAL_INIT                RCU_FORCE_QS
+#endif /* #else #ifdef CONFIG_NO_HZ */
+
+#define RCU_JIFFIES_TILL_FORCE_QS       3      /* for rsp->jiffies_force_qs */
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+#define RCU_SECONDS_TILL_STALL_CHECK   (10 * HZ)  /* for rsp->jiffies_stall */
+#define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ)  /* for rsp->jiffies_stall */
+#define RCU_STALL_RAT_DELAY            2         /* Allow other CPUs time */
+                                                 /*  to take at least one */
+                                                 /*  scheduling clock irq */
+                                                 /*  before ratting on them. */
+
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+
+/*
+ * RCU global state, including node hierarchy.  This hierarchy is
+ * represented in "heap" form in a dense array.  The root (first level)
+ * of the hierarchy is in ->node[0] (referenced by ->level[0]), the second
+ * level in ->node[1] through ->node[m] (->node[1] referenced by ->level[1]),
+ * and the third level in ->node[m+1] and following (->node[m+1] referenced
+ * by ->level[2]).  The number of levels is determined by the number of
+ * CPUs and by CONFIG_RCU_FANOUT.  Small systems will have a "hierarchy"
+ * consisting of a single rcu_node.
+ */
+struct rcu_state {
+       struct rcu_node node[NUM_RCU_NODES];    /* Hierarchy. */
+       struct rcu_node *level[NUM_RCU_LVLS];   /* Hierarchy levels. */
+       u32 levelcnt[MAX_RCU_LVLS + 1];         /* # nodes in each level. */
+       u8 levelspread[NUM_RCU_LVLS];           /* kids/node in each level. */
+       struct rcu_data *rda[NR_CPUS];          /* array of rdp pointers. */
+
+       /* The following fields are guarded by the root rcu_node's lock. */
+
+       u8      signaled ____cacheline_internodealigned_in_smp;
+                                               /* Force QS state. */
+       long    gpnum;                          /* Current gp number. */
+       long    completed;                      /* # of last completed gp. */
+       spinlock_t onofflock;                   /* exclude on/offline and */
+                                               /*  starting new GP. */
+       spinlock_t fqslock;                     /* Only one task forcing */
+                                               /*  quiescent states. */
+       unsigned long jiffies_force_qs;         /* Time at which to invoke */
+                                               /*  force_quiescent_state(). */
+       unsigned long n_force_qs;               /* Number of calls to */
+                                               /*  force_quiescent_state(). */
+       unsigned long n_force_qs_lh;            /* ~Number of calls leaving */
+                                               /*  due to lock unavailable. */
+       unsigned long n_force_qs_ngp;           /* Number of calls leaving */
+                                               /*  due to no GP active. */
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+       unsigned long gp_start;                 /* Time at which GP started, */
+                                               /*  but in jiffies. */
+       unsigned long jiffies_stall;            /* Time at which to check */
+                                               /*  for CPU stalls. */
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+#ifdef CONFIG_NO_HZ
+       long dynticks_completed;                /* Value of completed @ snap. */
+#endif /* #ifdef CONFIG_NO_HZ */
+};
+
+extern struct rcu_state rcu_state;
+DECLARE_PER_CPU(struct rcu_data, rcu_data);
+
+extern struct rcu_state rcu_bh_state;
+DECLARE_PER_CPU(struct rcu_data, rcu_bh_data);
+
+/*
+ * Increment the quiescent state counter.
+ * The counter is a bit degenerated: We do not need to know
+ * how many quiescent states passed, just if there was at least
+ * one since the start of the grace period. Thus just a flag.
+ */
+static inline void rcu_qsctr_inc(int cpu)
+{
+       struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
+       rdp->passed_quiesc = 1;
+       rdp->passed_quiesc_completed = rdp->completed;
+}
+static inline void rcu_bh_qsctr_inc(int cpu)
+{
+       struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu);
+       rdp->passed_quiesc = 1;
+       rdp->passed_quiesc_completed = rdp->completed;
+}
+
+extern int rcu_pending(int cpu);
+extern int rcu_needs_cpu(int cpu);
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern struct lockdep_map rcu_lock_map;
+# define rcu_read_acquire()    \
+                       lock_acquire(&rcu_lock_map, 0, 0, 2, 1, NULL, _THIS_IP_)
+# define rcu_read_release()    lock_release(&rcu_lock_map, 1, _THIS_IP_)
+#else
+# define rcu_read_acquire()    do { } while (0)
+# define rcu_read_release()    do { } while (0)
+#endif
+
+static inline void __rcu_read_lock(void)
+{
+       preempt_disable();
+       __acquire(RCU);
+       rcu_read_acquire();
+}
+static inline void __rcu_read_unlock(void)
+{
+       rcu_read_release();
+       __release(RCU);
+       preempt_enable();
+}
+static inline void __rcu_read_lock_bh(void)
+{
+       local_bh_disable();
+       __acquire(RCU_BH);
+       rcu_read_acquire();
+}
+static inline void __rcu_read_unlock_bh(void)
+{
+       rcu_read_release();
+       __release(RCU_BH);
+       local_bh_enable();
+}
+
+#define __synchronize_sched() synchronize_rcu()
+
+#define call_rcu_sched(head, func) call_rcu(head, func)
+
+static inline void rcu_init_sched(void)
+{
+}
+
+extern void __rcu_init(void);
+extern void rcu_check_callbacks(int cpu, int user);
+extern void rcu_restart_cpu(int cpu);
+
+extern long rcu_batches_completed(void);
+extern long rcu_batches_completed_bh(void);
+
+#ifdef CONFIG_NO_HZ
+void rcu_enter_nohz(void);
+void rcu_exit_nohz(void);
+#else /* CONFIG_NO_HZ */
+static inline void rcu_enter_nohz(void)
+{
+}
+static inline void rcu_exit_nohz(void)
+{
+}
+#endif /* CONFIG_NO_HZ */
+
+#endif /* __LINUX_RCUTREE_H */
index d363467c8f13e31a7c1ff4eaa92ee0dd961d67d6..b3b3596600826847abc6b59fff5973e7c2f78cac 100644 (file)
@@ -118,6 +118,8 @@ void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu);
 
 unsigned long ring_buffer_entries(struct ring_buffer *buffer);
 unsigned long ring_buffer_overruns(struct ring_buffer *buffer);
+unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu);
+unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu);
 
 u64 ring_buffer_time_stamp(int cpu);
 void ring_buffer_normalize_time_stamp(int cpu, u64 *ts);
index 4e4f1277f3bf487517faf1d2dd4f275a6ddbad7f..feb3b939ec4bc779cb4dd2907e5fc1292af7af1a 100644 (file)
 /* SH-SCI */
 #define PORT_SCIFA     83
 
+#define PORT_S3C6400   84
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
index 000da12b5cf03650ad90db9be142d803930fb62e..f96d13c281e81d03bf0b791ccb10b1a918e12055 100644 (file)
@@ -253,9 +253,9 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
  * request comes from.
  */
 #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
-extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
+extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long);
 #define kmalloc_track_caller(size, flags) \
-       __kmalloc_track_caller(size, flags, __builtin_return_address(0))
+       __kmalloc_track_caller(size, flags, _RET_IP_)
 #else
 #define kmalloc_track_caller(size, flags) \
        __kmalloc(size, flags)
@@ -271,10 +271,10 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
  * allocation request comes from.
  */
 #if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
-extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
+extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long);
 #define kmalloc_node_track_caller(size, flags, node) \
        __kmalloc_node_track_caller(size, flags, node, \
-                       __builtin_return_address(0))
+                       _RET_IP_)
 #else
 #define kmalloc_node_track_caller(size, flags, node) \
        __kmalloc_node(size, flags, node)
@@ -285,7 +285,7 @@ extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
 #define kmalloc_node_track_caller(size, flags, node) \
        kmalloc_track_caller(size, flags)
 
-#endif /* DEBUG_SLAB */
+#endif /* CONFIG_NUMA */
 
 /*
  * Shortcuts
index b18ec5533e8c594509e83a666cac089a774a060f..325af1de0351a0062fab92f2a6d8d2226879a2be 100644 (file)
@@ -7,9 +7,31 @@ struct device;
 struct dma_attrs;
 struct scatterlist;
 
+/*
+ * Maximum allowable number of contiguous slabs to map,
+ * must be a power of 2.  What is the appropriate value ?
+ * The complexity of {map,unmap}_single is linearly dependent on this value.
+ */
+#define IO_TLB_SEGSIZE 128
+
+
+/*
+ * log of the size of each IO TLB slab.  The number of slabs is command line
+ * controllable.
+ */
+#define IO_TLB_SHIFT 11
+
 extern void
 swiotlb_init(void);
 
+extern void *swiotlb_alloc_boot(size_t bytes, unsigned long nslabs);
+extern void *swiotlb_alloc(unsigned order, unsigned long nslabs);
+
+extern dma_addr_t swiotlb_phys_to_bus(phys_addr_t address);
+extern phys_addr_t swiotlb_bus_to_phys(dma_addr_t address);
+
+extern int swiotlb_arch_range_needs_mapping(void *ptr, size_t size);
+
 extern void
 *swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                        dma_addr_t *dma_handle, gfp_t flags);
index 9007313b5b7168ae03ed85e63d80ce6afe0ce438..998a55d80acf1b1c62bd8d91755448f9a0edebd6 100644 (file)
 #ifndef _LINUX_TIMEX_H
 #define _LINUX_TIMEX_H
 
-#include <linux/compiler.h>
 #include <linux/time.h>
 
-#include <asm/param.h>
-
 #define NTP_API                4       /* NTP API version */
 
-/*
- * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
- * for a slightly underdamped convergence characteristic. SHIFT_KH
- * establishes the damping of the FLL and is chosen by wisdom and black
- * art.
- *
- * MAXTC establishes the maximum time constant of the PLL. With the
- * SHIFT_KG and SHIFT_KF values given and a time constant range from
- * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
- * respectively.
- */
-#define SHIFT_PLL      4       /* PLL frequency factor (shift) */
-#define SHIFT_FLL      2       /* FLL frequency factor (shift) */
-#define MAXTC          10      /* maximum time constant (shift) */
-
-/*
- * SHIFT_USEC defines the scaling (shift) of the time_freq and
- * time_tolerance variables, which represent the current frequency
- * offset and maximum frequency tolerance.
- */
-#define SHIFT_USEC 16          /* frequency offset scale (shift) */
-#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))
-#define PPM_SCALE_INV_SHIFT 19
-#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \
-                      PPM_SCALE + 1)
-
-#define MAXPHASE 500000000l    /* max phase error (ns) */
-#define MAXFREQ 500000         /* max frequency error (ns/s) */
-#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT)
-#define MINSEC 256             /* min interval between updates (s) */
-#define MAXSEC 2048            /* max interval between updates (s) */
-#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */
-
 /*
  * syscall interface - used (mainly by NTP daemon)
  * to discipline kernel clock oscillator
@@ -199,8 +163,45 @@ struct timex {
 #define TIME_BAD       TIME_ERROR /* bw compat */
 
 #ifdef __KERNEL__
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/param.h>
+
 #include <asm/timex.h>
 
+/*
+ * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
+ * for a slightly underdamped convergence characteristic. SHIFT_KH
+ * establishes the damping of the FLL and is chosen by wisdom and black
+ * art.
+ *
+ * MAXTC establishes the maximum time constant of the PLL. With the
+ * SHIFT_KG and SHIFT_KF values given and a time constant range from
+ * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
+ * respectively.
+ */
+#define SHIFT_PLL      4       /* PLL frequency factor (shift) */
+#define SHIFT_FLL      2       /* FLL frequency factor (shift) */
+#define MAXTC          10      /* maximum time constant (shift) */
+
+/*
+ * SHIFT_USEC defines the scaling (shift) of the time_freq and
+ * time_tolerance variables, which represent the current frequency
+ * offset and maximum frequency tolerance.
+ */
+#define SHIFT_USEC 16          /* frequency offset scale (shift) */
+#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))
+#define PPM_SCALE_INV_SHIFT 19
+#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \
+                      PPM_SCALE + 1)
+
+#define MAXPHASE 500000000l    /* max phase error (ns) */
+#define MAXFREQ 500000         /* max frequency error (ns/s) */
+#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT)
+#define MINSEC 256             /* min interval between updates (s) */
+#define MAXSEC 2048            /* max interval between updates (s) */
+#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */
+
 /*
  * kernel variables
  * Note: maximum error = NTP synch distance = dispersion + delay / 2;
index 1d98330b1f2c174fa239f8dbfc0b5533b4f99dc6..121f349cb7ec0a5063711d6656d6c45e42521b06 100644 (file)
@@ -135,19 +135,14 @@ typedef           __s64           int64_t;
  *
  * Linux always considers sectors to be 512 bytes long independently
  * of the devices real block size.
+ *
+ * blkcnt_t is the type of the inode's block count.
  */
 #ifdef CONFIG_LBD
 typedef u64 sector_t;
-#else
-typedef unsigned long sector_t;
-#endif
-
-/*
- * The type of the inode's block count.
- */
-#ifdef CONFIG_LSF
 typedef u64 blkcnt_t;
 #else
+typedef unsigned long sector_t;
 typedef unsigned long blkcnt_t;
 #endif
 
index fec6decfb983503ec8ae24bafa793f09b5f902b2..6b58367d145e8735eaebbf16bfec0733406389fb 100644 (file)
@@ -78,7 +78,7 @@ static inline unsigned long __copy_from_user_nocache(void *to,
                                                        \
                set_fs(KERNEL_DS);                      \
                pagefault_disable();                    \
-               ret = __get_user(retval, (__force typeof(retval) __user *)(addr));              \
+               ret = __copy_from_user_inatomic(&(retval), (__force typeof(retval) __user *)(addr), sizeof(retval));            \
                pagefault_enable();                     \
                set_fs(old_fs);                         \
                ret;                                    \
index 4669d7e72e75c92e5499fe74100e88ce09eedec1..1f126e30766cbb42d41557bf2a4aed6192f354ba 100644 (file)
@@ -293,6 +293,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */
 #define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */
 #define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2     */
 #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 planar */
 #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16  YVU411 planar */
 #define V4L2_PIX_FMT_Y41P    v4l2_fourcc('Y', '4', '1', 'P') /* 12  YUV 4:1:1     */
@@ -304,6 +305,8 @@ struct v4l2_pix_format {
 /* two planes -- one Y, one Cr + Cb interleaved  */
 #define V4L2_PIX_FMT_NV12    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
 #define V4L2_PIX_FMT_NV21    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 4:2:0  */
+#define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
+#define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
 
 /*  The following formats are not defined in the V4L2 specification */
 #define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
@@ -1050,7 +1053,7 @@ enum v4l2_mpeg_video_bitrate_mode {
 #define V4L2_CID_MPEG_VIDEO_MUTE               (V4L2_CID_MPEG_BASE+210)
 #define V4L2_CID_MPEG_VIDEO_MUTE_YUV           (V4L2_CID_MPEG_BASE+211)
 
-/*  MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
+/*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
 #define V4L2_CID_MPEG_CX2341X_BASE                             (V4L2_CTRL_CLASS_MPEG | 0x1000)
 #define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE        (V4L2_CID_MPEG_CX2341X_BASE+0)
 enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
@@ -1117,6 +1120,12 @@ enum  v4l2_exposure_auto_type {
 #define V4L2_CID_FOCUS_RELATIVE                        (V4L2_CID_CAMERA_CLASS_BASE+11)
 #define V4L2_CID_FOCUS_AUTO                    (V4L2_CID_CAMERA_CLASS_BASE+12)
 
+#define V4L2_CID_ZOOM_ABSOLUTE                 (V4L2_CID_CAMERA_CLASS_BASE+13)
+#define V4L2_CID_ZOOM_RELATIVE                 (V4L2_CID_CAMERA_CLASS_BASE+14)
+#define V4L2_CID_ZOOM_CONTINUOUS               (V4L2_CID_CAMERA_CLASS_BASE+15)
+
+#define V4L2_CID_PRIVACY                       (V4L2_CID_CAMERA_CLASS_BASE+16)
+
 /*
  *     T U N I N G
  */
@@ -1369,6 +1378,7 @@ struct v4l2_streamparm {
 #define V4L2_CHIP_MATCH_HOST       0  /* Match against chip ID on host (0 for the host) */
 #define V4L2_CHIP_MATCH_I2C_DRIVER 1  /* Match against I2C driver ID */
 #define V4L2_CHIP_MATCH_I2C_ADDR   2  /* Match against I2C 7-bit address */
+#define V4L2_CHIP_MATCH_AC97       3  /* Match against anciliary AC97 chip */
 
 struct v4l2_register {
        __u32 match_type; /* Match type */
@@ -1458,6 +1468,8 @@ struct v4l2_chip_ident {
 #define VIDIOC_G_CHIP_IDENT     _IOWR('V', 81, struct v4l2_chip_ident)
 #endif
 #define VIDIOC_S_HW_FREQ_SEEK   _IOW('V', 82, struct v4l2_hw_freq_seek)
+/* Reminder: when adding new ioctls please add support for them to
+   drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
 #ifdef __OLD_VIDIOC_
 /* for compatibility, will go away some day */
index c30c7bfbf39bcb0f26507b88a9e82ec336d6eff6..8726ff77763e47389e0cb61eec678c85228b06c6 100644 (file)
@@ -10,6 +10,9 @@
 /* The feature bitmap for virtio balloon */
 #define VIRTIO_BALLOON_F_MUST_TELL_HOST        0 /* Tell before reclaiming pages */
 
+/* Size of a PFN in the balloon interface. */
+#define VIRTIO_BALLOON_PFN_SHIFT 12
+
 struct virtio_balloon_config
 {
        /* Number of pages host wants Guest to give up. */
index 19a0da0dba41203a59d5d2bce2762d2c2b78a240..7615ffcdd555cb2d3b1fa80b5f380c492881b394 100644 (file)
@@ -7,6 +7,17 @@
 /* The ID for virtio console */
 #define VIRTIO_ID_CONSOLE      3
 
+/* Feature bits */
+#define VIRTIO_CONSOLE_F_SIZE  0       /* Does host provide console size? */
+
+struct virtio_console_config {
+       /* colums of the screens */
+       __u16 cols;
+       /* rows of the screens */
+       __u16 rows;
+} __attribute__((packed));
+
+
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
 #endif /* __KERNEL__ */
index cdef3574293274eb7fa61d7a34c9315cfbe6ab88..cd0fd5d181a6f259e8e24f7fb12f107cd35a4515 100644 (file)
 
 /* Virtio ABI version, this must match exactly */
 #define VIRTIO_PCI_ABI_VERSION         0
+
+/* How many bits to shift physical queue address written to QUEUE_PFN.
+ * 12 is historical, and due to x86 page size. */
+#define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
+
+/* The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize again. */
+#define VIRTIO_PCI_VRING_ALIGN         4096
 #endif
index c4a598fb3826f1de5f2fe6f62a536c148d3f77a9..71e03722fb5946fa60ab67a88a7250bee3c77b7c 100644 (file)
@@ -83,7 +83,7 @@ struct vring {
  *     __u16 avail_idx;
  *     __u16 available[num];
  *
- *     // Padding to the next page boundary.
+ *     // Padding to the next align boundary.
  *     char pad[];
  *
  *     // A ring of used descriptor heads with free-running index.
@@ -93,19 +93,19 @@ struct vring {
  * };
  */
 static inline void vring_init(struct vring *vr, unsigned int num, void *p,
-                             unsigned long pagesize)
+                             unsigned long align)
 {
        vr->num = num;
        vr->desc = p;
        vr->avail = p + num*sizeof(struct vring_desc);
-       vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + pagesize-1)
-                           & ~(pagesize - 1));
+       vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
+                           & ~(align - 1));
 }
 
-static inline unsigned vring_size(unsigned int num, unsigned long pagesize)
+static inline unsigned vring_size(unsigned int num, unsigned long align)
 {
        return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
-                + pagesize - 1) & ~(pagesize - 1))
+                + align - 1) & ~(align - 1))
                + sizeof(__u16) * 2 + sizeof(struct vring_used_elem) * num;
 }
 
@@ -115,6 +115,7 @@ struct virtio_device;
 struct virtqueue;
 
 struct virtqueue *vring_new_virtqueue(unsigned int num,
+                                     unsigned int vring_align,
                                      struct virtio_device *vdev,
                                      void *pages,
                                      void (*notify)(struct virtqueue *vq),
index e7ff44a35ca00e7a5b07d900866f5b7006d2b24d..5d0f56054d2698fcaec03b2d39461a1a848faf31 100644 (file)
@@ -12,8 +12,6 @@
 /* bttv address list */
 #define I2C_ADDR_TSA5522       0xc2
 #define I2C_ADDR_TDA7432       0x8a
-#define I2C_ADDR_BT832_ALT1    0x88
-#define I2C_ADDR_BT832_ALT2    0x8a // alternate setting
 #define I2C_ADDR_TDA8425       0x82
 #define I2C_ADDR_TDA9840       0x84
 #define I2C_ADDR_TDA9850       0xb6 /* also used by 9855,9873 */
index 38f2d93c3957014ed5431b61caae60bc3ab4c50d..5bf2ea00678c0c9c245c8c1826b71f516025af7e 100644 (file)
@@ -157,6 +157,8 @@ extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_ati_tv_wonder_hd_600[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_kworld_plus_tv_analog[IR_KEYTAB_SIZE];
 #endif
 
 /*
diff --git a/include/media/ov772x.h b/include/media/ov772x.h
new file mode 100644 (file)
index 0000000..e391d55
--- /dev/null
@@ -0,0 +1,21 @@
+/* ov772x Camera
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __OV772X_H__
+#define __OV772X_H__
+
+#include <media/soc_camera.h>
+
+struct ov772x_camera_info {
+       unsigned long          buswidth;
+       struct soc_camera_link link;
+};
+
+#endif /* __OV772X_H__ */
index 1d104096619cf78d779e573c6a6fb1795117e81c..6bbb0d93bb5f39b34a368a450b73caae2eeccd66 100644 (file)
@@ -216,8 +216,7 @@ void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
 extern struct saa7146_use_ops saa7146_video_uops;
 int saa7146_start_preview(struct saa7146_fh *fh);
 int saa7146_stop_preview(struct saa7146_fh *fh);
-int saa7146_video_do_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, void *arg);
+int saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
 
 /* from saa7146_vbi.c */
 extern struct saa7146_use_ops saa7146_vbi_uops;
index c5de7bb19fda759febc5a35aca76cf738a7afcc8..425b6a98c95c220e703cb98a5b2eb32a04bb2f08 100644 (file)
 #ifndef SOC_CAMERA_H
 #define SOC_CAMERA_H
 
+#include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/videodev2.h>
 #include <media/videobuf-core.h>
-#include <linux/pm.h>
 
 struct soc_camera_device {
        struct list_head list;
@@ -36,14 +37,19 @@ struct soc_camera_device {
        unsigned char iface;            /* Host number */
        unsigned char devnum;           /* Device number per host */
        unsigned char buswidth;         /* See comment in .c */
+       struct soc_camera_sense *sense; /* See comment in struct definition */
        struct soc_camera_ops *ops;
        struct video_device *vdev;
        const struct soc_camera_data_format *current_fmt;
        const struct soc_camera_data_format *formats;
        int num_formats;
+       struct soc_camera_format_xlate *user_formats;
+       int num_user_formats;
        struct module *owner;
-       /* soc_camera.c private count. Only accessed with video_lock held */
+       void *host_priv;                /* Per-device host private data */
+       /* soc_camera.c private count. Only accessed with .video_lock held */
        int use_count;
+       struct mutex video_lock;        /* Protects device data */
 };
 
 struct soc_camera_file {
@@ -56,7 +62,7 @@ struct soc_camera_host {
        struct device dev;
        unsigned char nr;                               /* Host number */
        void *priv;
-       char *drv_name;
+       const char *drv_name;
        struct soc_camera_host_ops *ops;
 };
 
@@ -64,25 +70,33 @@ struct soc_camera_host_ops {
        struct module *owner;
        int (*add)(struct soc_camera_device *);
        void (*remove)(struct soc_camera_device *);
-       int (*suspend)(struct soc_camera_device *, pm_message_t state);
+       int (*suspend)(struct soc_camera_device *, pm_message_t);
        int (*resume)(struct soc_camera_device *);
-       int (*set_fmt_cap)(struct soc_camera_device *, __u32,
-                          struct v4l2_rect *);
-       int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+       int (*get_formats)(struct soc_camera_device *, int,
+                          struct soc_camera_format_xlate *);
+       int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
+       int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        void (*init_videobuf)(struct videobuf_queue *,
                              struct soc_camera_device *);
        int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
        int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
-       int (*try_bus_param)(struct soc_camera_device *, __u32);
        int (*set_bus_param)(struct soc_camera_device *, __u32);
        unsigned int (*poll)(struct file *, poll_table *);
 };
 
+#define SOCAM_SENSOR_INVERT_PCLK       (1 << 0)
+#define SOCAM_SENSOR_INVERT_MCLK       (1 << 1)
+#define SOCAM_SENSOR_INVERT_HSYNC      (1 << 2)
+#define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
+#define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
+
 struct soc_camera_link {
        /* Camera bus id, used to match a camera and a bus */
        int bus_id;
        /* GPIO number to switch between 8 and 10 bit modes */
        unsigned int gpio;
+       /* Per camera SOCAM_SENSOR_* bus flags */
+       unsigned long flags;
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
@@ -106,13 +120,35 @@ extern void soc_camera_device_unregister(struct soc_camera_device *icd);
 extern int soc_camera_video_start(struct soc_camera_device *icd);
 extern void soc_camera_video_stop(struct soc_camera_device *icd);
 
+extern const struct soc_camera_data_format *soc_camera_format_by_fourcc(
+       struct soc_camera_device *icd, unsigned int fourcc);
+extern const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
+       struct soc_camera_device *icd, unsigned int fourcc);
+
 struct soc_camera_data_format {
-       char *name;
+       const char *name;
        unsigned int depth;
        __u32 fourcc;
        enum v4l2_colorspace colorspace;
 };
 
+/**
+ * struct soc_camera_format_xlate - match between host and sensor formats
+ * @cam_fmt: sensor format provided by the sensor
+ * @host_fmt: host format after host translation from cam_fmt
+ * @buswidth: bus width for this format
+ *
+ * Host and sensor translation structure. Used in table of host and sensor
+ * formats matchings in soc_camera_device. A host can override the generic list
+ * generation by implementing get_formats(), and use it for format checks and
+ * format setup.
+ */
+struct soc_camera_format_xlate {
+       const struct soc_camera_data_format *cam_fmt;
+       const struct soc_camera_data_format *host_fmt;
+       unsigned char buswidth;
+};
+
 struct soc_camera_ops {
        struct module *owner;
        int (*probe)(struct soc_camera_device *);
@@ -123,13 +159,14 @@ struct soc_camera_ops {
        int (*release)(struct soc_camera_device *);
        int (*start_capture)(struct soc_camera_device *);
        int (*stop_capture)(struct soc_camera_device *);
-       int (*set_fmt_cap)(struct soc_camera_device *, __u32,
-                          struct v4l2_rect *);
-       int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+       int (*set_fmt)(struct soc_camera_device *, __u32, struct v4l2_rect *);
+       int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
        unsigned long (*query_bus_param)(struct soc_camera_device *);
        int (*set_bus_param)(struct soc_camera_device *, unsigned long);
        int (*get_chip_id)(struct soc_camera_device *,
                           struct v4l2_chip_ident *);
+       int (*set_std)(struct soc_camera_device *, v4l2_std_id *);
+       int (*enum_input)(struct soc_camera_device *, struct v4l2_input *);
 #ifdef CONFIG_VIDEO_ADV_DEBUG
        int (*get_register)(struct soc_camera_device *, struct v4l2_register *);
        int (*set_register)(struct soc_camera_device *, struct v4l2_register *);
@@ -140,6 +177,32 @@ struct soc_camera_ops {
        int num_controls;
 };
 
+#define SOCAM_SENSE_PCLK_CHANGED       (1 << 0)
+
+/**
+ * This struct can be attached to struct soc_camera_device by the host driver
+ * to request sense from the camera, for example, when calling .set_fmt(). The
+ * host then can check which flags are set and verify respective values if any.
+ * For example, if SOCAM_SENSE_PCLK_CHANGED is set, it means, pixclock has
+ * changed during this operation. After completion the host should detach sense.
+ *
+ * @flags              ored SOCAM_SENSE_* flags
+ * @master_clock       if the host wants to be informed about pixel-clock
+ *                     change, it better set master_clock.
+ * @pixel_clock_max    maximum pixel clock frequency supported by the host,
+ *                     camera is not allowed to exceed this.
+ * @pixel_clock                if the camera driver changed pixel clock during this
+ *                     operation, it sets SOCAM_SENSE_PCLK_CHANGED, uses
+ *                     master_clock to calculate the new pixel-clock and
+ *                     sets this field.
+ */
+struct soc_camera_sense {
+       unsigned long flags;
+       unsigned long master_clock;
+       unsigned long pixel_clock_max;
+       unsigned long pixel_clock;
+};
+
 static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
        struct soc_camera_ops *ops, int id)
 {
@@ -158,15 +221,20 @@ static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
 #define SOCAM_HSYNC_ACTIVE_LOW         (1 << 3)
 #define SOCAM_VSYNC_ACTIVE_HIGH                (1 << 4)
 #define SOCAM_VSYNC_ACTIVE_LOW         (1 << 5)
-#define SOCAM_DATAWIDTH_8              (1 << 6)
-#define SOCAM_DATAWIDTH_9              (1 << 7)
-#define SOCAM_DATAWIDTH_10             (1 << 8)
-#define SOCAM_DATAWIDTH_16             (1 << 9)
-#define SOCAM_PCLK_SAMPLE_RISING       (1 << 10)
-#define SOCAM_PCLK_SAMPLE_FALLING      (1 << 11)
+#define SOCAM_DATAWIDTH_4              (1 << 6)
+#define SOCAM_DATAWIDTH_8              (1 << 7)
+#define SOCAM_DATAWIDTH_9              (1 << 8)
+#define SOCAM_DATAWIDTH_10             (1 << 9)
+#define SOCAM_DATAWIDTH_15             (1 << 10)
+#define SOCAM_DATAWIDTH_16             (1 << 11)
+#define SOCAM_PCLK_SAMPLE_RISING       (1 << 12)
+#define SOCAM_PCLK_SAMPLE_FALLING      (1 << 13)
+#define SOCAM_DATA_ACTIVE_HIGH         (1 << 14)
+#define SOCAM_DATA_ACTIVE_LOW          (1 << 15)
 
-#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \
-                             SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_16)
+#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \
+                             SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \
+                             SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16)
 
 static inline unsigned long soc_camera_bus_param_compatible(
                        unsigned long camera_flags, unsigned long bus_flags)
@@ -182,4 +250,7 @@ static inline unsigned long soc_camera_bus_param_compatible(
        return (!hsync || !vsync || !pclk) ? 0 : common_flags;
 }
 
+extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
+                                                  unsigned long flags);
+
 #endif
diff --git a/include/media/tvp514x.h b/include/media/tvp514x.h
new file mode 100644 (file)
index 0000000..5e7ee96
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * drivers/media/video/tvp514x.h
+ *
+ * Copyright (C) 2008 Texas Instruments Inc
+ * Author: Vaibhav Hiremath <hvaibhav@ti.com>
+ *
+ * Contributors:
+ *     Sivaraj R <sivaraj@ti.com>
+ *     Brijesh R Jadav <brijesh.j@ti.com>
+ *     Hardik Shah <hardik.shah@ti.com>
+ *     Manjunath Hadli <mrh@ti.com>
+ *     Karicheri Muralidharan <m-karicheri2@ti.com>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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 _TVP514X_H
+#define _TVP514X_H
+
+/*
+ * Other macros
+ */
+#define TVP514X_MODULE_NAME            "tvp514x"
+
+#define TVP514X_XCLK_BT656             (27000000)
+
+/* Number of pixels and number of lines per frame for different standards */
+#define NTSC_NUM_ACTIVE_PIXELS         (720)
+#define NTSC_NUM_ACTIVE_LINES          (480)
+#define PAL_NUM_ACTIVE_PIXELS          (720)
+#define PAL_NUM_ACTIVE_LINES           (576)
+
+/**
+ * enum tvp514x_input - enum for different decoder input pin
+ *             configuration.
+ */
+enum tvp514x_input {
+       /*
+        * CVBS input selection
+        */
+       INPUT_CVBS_VI1A = 0x0,
+       INPUT_CVBS_VI1B,
+       INPUT_CVBS_VI1C,
+       INPUT_CVBS_VI2A = 0x04,
+       INPUT_CVBS_VI2B,
+       INPUT_CVBS_VI2C,
+       INPUT_CVBS_VI3A = 0x08,
+       INPUT_CVBS_VI3B,
+       INPUT_CVBS_VI3C,
+       INPUT_CVBS_VI4A = 0x0C,
+       /*
+        * S-Video input selection
+        */
+       INPUT_SVIDEO_VI2A_VI1A = 0x44,
+       INPUT_SVIDEO_VI2B_VI1B,
+       INPUT_SVIDEO_VI2C_VI1C,
+       INPUT_SVIDEO_VI2A_VI3A = 0x54,
+       INPUT_SVIDEO_VI2B_VI3B,
+       INPUT_SVIDEO_VI2C_VI3C,
+       INPUT_SVIDEO_VI4A_VI1A = 0x4C,
+       INPUT_SVIDEO_VI4A_VI1B,
+       INPUT_SVIDEO_VI4A_VI1C,
+       INPUT_SVIDEO_VI4A_VI3A = 0x5C,
+       INPUT_SVIDEO_VI4A_VI3B,
+       INPUT_SVIDEO_VI4A_VI3C,
+
+       /* Need to add entries for
+        * RGB, YPbPr and SCART.
+        */
+       INPUT_INVALID
+};
+
+/**
+ * enum tvp514x_output - enum for output format
+ *                     supported.
+ *
+ */
+enum tvp514x_output {
+       OUTPUT_10BIT_422_EMBEDDED_SYNC = 0,
+       OUTPUT_20BIT_422_SEPERATE_SYNC,
+       OUTPUT_10BIT_422_SEPERATE_SYNC = 3,
+       OUTPUT_INVALID
+};
+
+/**
+ * struct tvp514x_platform_data - Platform data values and access functions.
+ * @power_set: Power state access function, zero is off, non-zero is on.
+ * @ifparm: Interface parameters access function.
+ * @priv_data_set: Device private data (pointer) access function.
+ * @clk_polarity: Clock polarity of the current interface.
+ * @ hs_polarity: HSYNC Polarity configuration for current interface.
+ * @ vs_polarity: VSYNC Polarity configuration for current interface.
+ */
+struct tvp514x_platform_data {
+       char *master;
+       int (*power_set) (enum v4l2_power on);
+       int (*ifparm) (struct v4l2_ifparm *p);
+       int (*priv_data_set) (void *);
+       /* Interface control params */
+       bool clk_polarity;
+       bool hs_polarity;
+       bool vs_polarity;
+};
+
+
+#endif                         /* ifndef _TVP514X_H */
diff --git a/include/media/tw9910.h b/include/media/tw9910.h
new file mode 100644 (file)
index 0000000..73231e7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * tw9910 Driver header
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x.h
+ *
+ * Copyright (C) Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __TW9910_H__
+#define __TW9910_H__
+
+#include <media/soc_camera.h>
+
+enum tw9910_mpout_pin {
+       TW9910_MPO_VLOSS,
+       TW9910_MPO_HLOCK,
+       TW9910_MPO_SLOCK,
+       TW9910_MPO_VLOCK,
+       TW9910_MPO_MONO,
+       TW9910_MPO_DET50,
+       TW9910_MPO_FIELD,
+       TW9910_MPO_RTCO,
+};
+
+struct tw9910_video_info {
+       unsigned long          buswidth;
+       enum tw9910_mpout_pin  mpout;
+       struct soc_camera_link link;
+};
+
+
+#endif /* __TW9910_H__ */
index d73a8e9028a56f425e60eb1ecaddf642e5d34e66..43dbb659f1f57533f6cba2bd8df37ff5d47591c5 100644 (file)
@@ -60,6 +60,8 @@ enum {
 
        /* OmniVision sensors: reserved range 250-299 */
        V4L2_IDENT_OV7670 = 250,
+       V4L2_IDENT_OV7720 = 251,
+       V4L2_IDENT_OV7725 = 252,
 
        /* Conexant MPEG encoder/decoders: reserved range 410-420 */
        V4L2_IDENT_CX23415 = 415,
@@ -69,6 +71,9 @@ enum {
        /* module vp27smpx: just ident 2700 */
        V4L2_IDENT_VP27SMPX = 2700,
 
+       /* module tvp5150 */
+       V4L2_IDENT_TVP5150 = 5150,
+
        /* module cs5345: just ident 5345 */
        V4L2_IDENT_CS5345 = 5345,
 
@@ -82,6 +87,9 @@ enum {
        /* module wm8775: just ident 8775 */
        V4L2_IDENT_WM8775 = 8775,
 
+       /* module tw9910: just ident 9910 */
+       V4L2_IDENT_TW9910 = 9910,
+
        /* module cs53132a: just ident 53132 */
        V4L2_IDENT_CS53l32A = 53132,
 
@@ -166,8 +174,10 @@ enum {
        V4L2_IDENT_MT9M001C12ST         = 45000,
        V4L2_IDENT_MT9M001C12STM        = 45005,
        V4L2_IDENT_MT9M111              = 45007,
+       V4L2_IDENT_MT9M112              = 45008,
        V4L2_IDENT_MT9V022IX7ATC        = 45010, /* No way to detect "normal" I77ATx */
        V4L2_IDENT_MT9V022IX7ATM        = 45015, /* and "lead free" IA7ATx chips */
+       V4L2_IDENT_MT9T031              = 45020,
 };
 
 #endif
index 2f8719abf5cb84fa363ce22fcb33309cb69897ed..f99c866d8c37f0cd4506e8f28b6d2911bb7a71ab 100644 (file)
 
 /* ------------------------------------------------------------------------- */
 
+/* These printk constructs can be used with v4l2_device and v4l2_subdev */
+#define v4l2_printk(level, dev, fmt, arg...) \
+       printk(level "%s: " fmt, (dev)->name , ## arg)
+
+#define v4l2_err(dev, fmt, arg...) \
+       v4l2_printk(KERN_ERR, dev, fmt , ## arg)
+
+#define v4l2_warn(dev, fmt, arg...) \
+       v4l2_printk(KERN_WARNING, dev, fmt , ## arg)
+
+#define v4l2_info(dev, fmt, arg...) \
+       v4l2_printk(KERN_INFO, dev, fmt , ## arg)
+
+/* These three macros assume that the debug level is set with a module
+   parameter called 'debug'. */
+#define v4l2_dbg(level, debug, dev, fmt, arg...)                       \
+       do {                                                            \
+               if (debug >= (level))                                   \
+                       v4l2_printk(KERN_DEBUG, dev, fmt , ## arg);     \
+       } while (0)
+
+/* ------------------------------------------------------------------------- */
+
 /* Priority helper functions */
 
 struct v4l2_prio_state {
@@ -104,11 +127,29 @@ struct i2c_driver;
 struct i2c_adapter;
 struct i2c_client;
 struct i2c_device_id;
+struct v4l2_device;
+struct v4l2_subdev;
+struct v4l2_subdev_ops;
 
 int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
                const char *name,
                int (*probe)(struct i2c_client *, const struct i2c_device_id *));
 
+/* Load an i2c module and return an initialized v4l2_subdev struct.
+   Only call request_module if module_name != NULL.
+   The client_type argument is the name of the chip that's on the adapter. */
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
+               const char *module_name, const char *client_type, u8 addr);
+/* Probe and load an i2c module and return an initialized v4l2_subdev struct.
+   Only call request_module if module_name != NULL.
+   The client_type argument is the name of the chip that's on the adapter. */
+struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
+               const char *module_name, const char *client_type,
+               const unsigned short *addrs);
+/* Initialize an v4l2_subdev with data from an i2c_client struct */
+void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
+               const struct v4l2_subdev_ops *ops);
+
 /* ------------------------------------------------------------------------- */
 
 /* Internal ioctls */
index a0a6b41c5e0944e3e655e51151e5a60e3abf2db4..0a88d1d17d30accc82ec89aff84313dc04d81821 100644 (file)
 #define VFL_TYPE_MAX           4
 
 struct v4l2_ioctl_callbacks;
+struct v4l2_device;
+
+/* Flag to mark the video_device struct as unregistered.
+   Drivers can set this flag if they want to block all future
+   device access. It is set by video_unregister_device. */
+#define V4L2_FL_UNREGISTERED   (0)
 
 /*
  * Newer version of video_device, handled by videodev2.c
@@ -39,15 +45,20 @@ struct video_device
 
        /* sysfs */
        struct device dev;              /* v4l device */
-       struct cdev cdev;               /* character device */
-       void (*cdev_release)(struct kobject *kobj);
+       struct cdev *cdev;              /* character device */
+
+       /* Set either parent or v4l2_dev if your driver uses v4l2_device */
        struct device *parent;          /* device parent */
+       struct v4l2_device *v4l2_dev;   /* v4l2_device parent */
 
        /* device info */
        char name[32];
        int vfl_type;
+       /* 'minor' is set to -1 if the registration failed */
        int minor;
        u16 num;
+       /* use bitops to set/clear/test flags */
+       unsigned long flags;
        /* attribute to differentiate multiple indices on one physical device */
        int index;
 
@@ -58,7 +69,7 @@ struct video_device
        v4l2_std_id current_norm;       /* Current tvnorm */
 
        /* callbacks */
-       void (*release)(struct video_device *vfd);
+       void (*release)(struct video_device *vdev);
 
        /* ioctl callbacks */
        const struct v4l2_ioctl_ops *ioctl_ops;
@@ -67,36 +78,41 @@ struct video_device
 /* dev to video-device */
 #define to_video_device(cd) container_of(cd, struct video_device, dev)
 
-/* Register and unregister devices. Note that if video_register_device fails,
+/* Register video devices. Note that if video_register_device fails,
    the release() callback of the video_device structure is *not* called, so
    the caller is responsible for freeing any data. Usually that means that
-   you call video_device_release() on failure. */
-int __must_check video_register_device(struct video_device *vfd, int type, int nr);
-int __must_check video_register_device_index(struct video_device *vfd,
+   you call video_device_release() on failure.
+
+   Also note that vdev->minor is set to -1 if the registration failed. */
+int __must_check video_register_device(struct video_device *vdev, int type, int nr);
+int __must_check video_register_device_index(struct video_device *vdev,
                                                int type, int nr, int index);
-void video_unregister_device(struct video_device *vfd);
+
+/* Unregister video devices. Will do nothing if vdev == NULL or
+   vdev->minor < 0. */
+void video_unregister_device(struct video_device *vdev);
 
 /* helper functions to alloc/release struct video_device, the
    latter can also be used for video_device->release(). */
 struct video_device * __must_check video_device_alloc(void);
 
-/* this release function frees the vfd pointer */
-void video_device_release(struct video_device *vfd);
+/* this release function frees the vdev pointer */
+void video_device_release(struct video_device *vdev);
 
 /* this release function does nothing, use when the video_device is a
    static global struct. Note that having a static video_device is
    a dubious construction at best. */
-void video_device_release_empty(struct video_device *vfd);
+void video_device_release_empty(struct video_device *vdev);
 
 /* helper functions to access driver private data. */
-static inline void *video_get_drvdata(struct video_device *dev)
+static inline void *video_get_drvdata(struct video_device *vdev)
 {
-       return dev_get_drvdata(&dev->dev);
+       return dev_get_drvdata(&vdev->dev);
 }
 
-static inline void video_set_drvdata(struct video_device *dev, void *data)
+static inline void video_set_drvdata(struct video_device *vdev, void *data)
 {
-       dev_set_drvdata(&dev->dev, data);
+       dev_set_drvdata(&vdev->dev, data);
 }
 
 struct video_device *video_devdata(struct file *file);
@@ -108,4 +124,9 @@ static inline void *video_drvdata(struct file *file)
        return video_get_drvdata(video_devdata(file));
 }
 
+static inline int video_is_unregistered(struct video_device *vdev)
+{
+       return test_bit(V4L2_FL_UNREGISTERED, &vdev->flags);
+}
+
 #endif /* _V4L2_DEV_H */
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
new file mode 100644 (file)
index 0000000..97b283a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+    V4L2 device support header.
+
+    Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _V4L2_DEVICE_H
+#define _V4L2_DEVICE_H
+
+#include <media/v4l2-subdev.h>
+
+/* Each instance of a V4L2 device should create the v4l2_device struct,
+   either stand-alone or embedded in a larger struct.
+
+   It allows easy access to sub-devices (see v4l2-subdev.h) and provides
+   basic V4L2 device-level support.
+ */
+
+#define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16)
+
+struct v4l2_device {
+       /* dev->driver_data points to this struct */
+       struct device *dev;
+       /* used to keep track of the registered subdevs */
+       struct list_head subdevs;
+       /* lock this struct; can be used by the driver as well if this
+          struct is embedded into a larger struct. */
+       spinlock_t lock;
+       /* unique device name, by default the driver name + bus ID */
+       char name[V4L2_DEVICE_NAME_SIZE];
+};
+
+/* Initialize v4l2_dev and make dev->driver_data point to v4l2_dev */
+int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+/* Set v4l2_dev->dev->driver_data to NULL and unregister all sub-devices */
+void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
+
+/* Register a subdev with a v4l2 device. While registered the subdev module
+   is marked as in-use. An error is returned if the module is no longer
+   loaded when you attempt to register it. */
+int __must_check v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd);
+/* Unregister a subdev with a v4l2 device. Can also be called if the subdev
+   wasn't registered. In that case it will do nothing. */
+void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
+
+/* Iterate over all subdevs. */
+#define v4l2_device_for_each_subdev(sd, dev)                           \
+       list_for_each_entry(sd, &(dev)->subdevs, list)
+
+/* Call the specified callback for all subdevs matching the condition.
+   Ignore any errors. Note that you cannot add or delete a subdev
+   while walking the subdevs list. */
+#define __v4l2_device_call_subdevs(dev, cond, o, f, args...)           \
+       do {                                                            \
+               struct v4l2_subdev *sd;                                 \
+                                                                       \
+               list_for_each_entry(sd, &(dev)->subdevs, list)          \
+                       if ((cond) && sd->ops->o && sd->ops->o->f)      \
+                               sd->ops->o->f(sd , ##args);             \
+       } while (0)
+
+/* Call the specified callback for all subdevs matching the condition.
+   If the callback returns an error other than 0 or -ENOIOCTLCMD, then
+   return with that error code. Note that you cannot add or delete a
+   subdev while walking the subdevs list. */
+#define __v4l2_device_call_subdevs_until_err(dev, cond, o, f, args...)  \
+({                                                                     \
+       struct v4l2_subdev *sd;                                         \
+       int err = 0;                                                    \
+                                                                       \
+       list_for_each_entry(sd, &(dev)->subdevs, list) {                \
+               if ((cond) && sd->ops->o && sd->ops->o->f)              \
+                       err = sd->ops->o->f(sd , ##args);               \
+               if (err && err != -ENOIOCTLCMD)                         \
+                       break;                                          \
+       }                                                               \
+       (err == -ENOIOCTLCMD) ? 0 : err;                                \
+})
+
+/* Call the specified callback for all subdevs matching grp_id (if 0, then
+   match them all). Ignore any errors. Note that you cannot add or delete
+   a subdev while walking the subdevs list. */
+#define v4l2_device_call_all(dev, grp_id, o, f, args...)               \
+       __v4l2_device_call_subdevs(dev,                                 \
+                       !(grp_id) || sd->grp_id == (grp_id), o, f , ##args)
+
+/* Call the specified callback for all subdevs matching grp_id (if 0, then
+   match them all). If the callback returns an error other than 0 or
+   -ENOIOCTLCMD, then return with that error code. Note that you cannot
+   add or delete a subdev while walking the subdevs list. */
+#define v4l2_device_call_until_err(dev, grp_id, o, f, args...)                 \
+       __v4l2_device_call_subdevs_until_err(dev,                       \
+                      !(grp_id) || sd->grp_id == (grp_id), o, f , ##args)
+
+#endif
index 9c2df41dbf92b7900a4966f26e0aedbec3f10099..ecda3c72583705cc2dda3422c83b8deba7031b28 100644 (file)
@@ -183,6 +183,9 @@ enum v4l2_int_ioctl_num {
        vidioc_int_s_crop_num,
        vidioc_int_g_parm_num,
        vidioc_int_s_parm_num,
+       vidioc_int_querystd_num,
+       vidioc_int_s_std_num,
+       vidioc_int_s_video_routing_num,
 
        /*
         *
@@ -284,6 +287,9 @@ V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
 V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
 V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
 V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
+V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
+V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
+V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
 
 V4L2_INT_WRAPPER_0(dev_init);
 V4L2_INT_WRAPPER_0(dev_exit);
index e6ba25b3d7c8bd345b5c5c30732f2c4f78d59f5a..fcdb58c4ce07b6872a3cbe57d72abdbb6e080a35 100644 (file)
@@ -232,6 +232,12 @@ struct v4l2_ioctl_ops {
        int (*vidioc_g_chip_ident)     (struct file *file, void *fh,
                                        struct v4l2_chip_ident *chip);
 
+       int (*vidioc_enum_framesizes)   (struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize);
+
+       int (*vidioc_enum_frameintervals) (struct file *file, void *fh,
+                                          struct v4l2_frmivalenum *fival);
+
        /* For other private ioctls */
        int (*vidioc_default)          (struct file *file, void *fh,
                                        int cmd, void *arg);
@@ -285,15 +291,13 @@ extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
                                unsigned long arg);
 
 /* Include support for obsoleted stuff */
-extern int video_usercopy(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg,
-                         int (*func)(struct inode *inode, struct file *file,
-                                     unsigned int cmd, void *arg));
+extern int video_usercopy(struct file *file, unsigned int cmd,
+                               unsigned long arg, v4l2_kioctl func);
 
 /* Standard handlers for V4L ioctl's */
 
 /* This prototype is used on fops.unlocked_ioctl */
-extern int __video_ioctl2(struct file *file,
+extern long __video_ioctl2(struct file *file,
                        unsigned int cmd, unsigned long arg);
 
 /* This prototype is used on fops.ioctl
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
new file mode 100644 (file)
index 0000000..ceef016
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+    V4L2 sub-device support header.
+
+    Copyright (C) 2008  Hans Verkuil <hverkuil@xs4all.nl>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _V4L2_SUBDEV_H
+#define _V4L2_SUBDEV_H
+
+#include <media/v4l2-common.h>
+
+struct v4l2_device;
+struct v4l2_subdev;
+struct tuner_setup;
+
+/* Sub-devices are devices that are connected somehow to the main bridge
+   device. These devices are usually audio/video muxers/encoders/decoders or
+   sensors and webcam controllers.
+
+   Usually these devices are controlled through an i2c bus, but other busses
+   may also be used.
+
+   The v4l2_subdev struct provides a way of accessing these devices in a
+   generic manner. Most operations that these sub-devices support fall in
+   a few categories: core ops, audio ops, video ops and tuner ops.
+
+   More categories can be added if needed, although this should remain a
+   limited set (no more than approx. 8 categories).
+
+   Each category has its own set of ops that subdev drivers can implement.
+
+   A subdev driver can leave the pointer to the category ops NULL if
+   it does not implement them (e.g. an audio subdev will generally not
+   implement the video category ops). The exception is the core category:
+   this must always be present.
+
+   These ops are all used internally so it is no problem to change, remove
+   or add ops or move ops from one to another category. Currently these
+   ops are based on the original ioctls, but since ops are not limited to
+   one argument there is room for improvement here once all i2c subdev
+   drivers are converted to use these ops.
+ */
+
+/* Core ops: it is highly recommended to implement at least these ops:
+
+   g_chip_ident
+   log_status
+   g_register
+   s_register
+
+   This provides basic debugging support.
+
+   The ioctl ops is meant for generic ioctl-like commands. Depending on
+   the use-case it might be better to use subdev-specific ops (currently
+   not yet implemented) since ops provide proper type-checking.
+ */
+struct v4l2_subdev_core_ops {
+       int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip);
+       int (*log_status)(struct v4l2_subdev *sd);
+       int (*init)(struct v4l2_subdev *sd, u32 val);
+       int (*s_standby)(struct v4l2_subdev *sd, u32 standby);
+       int (*reset)(struct v4l2_subdev *sd, u32 val);
+       int (*s_gpio)(struct v4l2_subdev *sd, u32 val);
+       int (*queryctrl)(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
+       int (*g_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+       int (*s_ctrl)(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+       int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm);
+       int (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       int (*g_register)(struct v4l2_subdev *sd, struct v4l2_register *reg);
+       int (*s_register)(struct v4l2_subdev *sd, struct v4l2_register *reg);
+#endif
+};
+
+struct v4l2_subdev_tuner_ops {
+       int (*s_mode)(struct v4l2_subdev *sd, enum v4l2_tuner_type);
+       int (*s_radio)(struct v4l2_subdev *sd);
+       int (*s_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
+       int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
+       int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
+       int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
+       int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm);
+       int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type);
+       int (*s_config)(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *config);
+};
+
+struct v4l2_subdev_audio_ops {
+       int (*s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
+       int (*s_i2s_clock_freq)(struct v4l2_subdev *sd, u32 freq);
+       int (*s_routing)(struct v4l2_subdev *sd, const struct v4l2_routing *route);
+};
+
+struct v4l2_subdev_video_ops {
+       int (*s_routing)(struct v4l2_subdev *sd, const struct v4l2_routing *route);
+       int (*s_crystal_freq)(struct v4l2_subdev *sd, struct v4l2_crystal_freq *freq);
+       int (*decode_vbi_line)(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi_line);
+       int (*s_vbi_data)(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *vbi_data);
+       int (*g_vbi_data)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_data *vbi_data);
+       int (*g_sliced_vbi_cap)(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_cap *cap);
+       int (*s_std_output)(struct v4l2_subdev *sd, v4l2_std_id std);
+       int (*s_stream)(struct v4l2_subdev *sd, int enable);
+       int (*s_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+       int (*g_fmt)(struct v4l2_subdev *sd, struct v4l2_format *fmt);
+};
+
+struct v4l2_subdev_ops {
+       const struct v4l2_subdev_core_ops  *core;
+       const struct v4l2_subdev_tuner_ops *tuner;
+       const struct v4l2_subdev_audio_ops *audio;
+       const struct v4l2_subdev_video_ops *video;
+};
+
+#define V4L2_SUBDEV_NAME_SIZE 32
+
+/* Each instance of a subdev driver should create this struct, either
+   stand-alone or embedded in a larger struct.
+ */
+struct v4l2_subdev {
+       struct list_head list;
+       struct module *owner;
+       struct v4l2_device *dev;
+       const struct v4l2_subdev_ops *ops;
+       /* name must be unique */
+       char name[V4L2_SUBDEV_NAME_SIZE];
+       /* can be used to group similar subdevs, value is driver-specific */
+       u32 grp_id;
+       /* pointer to private data */
+       void *priv;
+};
+
+static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)
+{
+       sd->priv = p;
+}
+
+static inline void *v4l2_get_subdevdata(const struct v4l2_subdev *sd)
+{
+       return sd->priv;
+}
+
+/* Convert an ioctl-type command to the proper v4l2_subdev_ops function call.
+   This is used by subdev modules that can be called by both old-style ioctl
+   commands and through the v4l2_subdev_ops.
+
+   The ioctl API of the subdev driver can call this function to call the
+   right ops based on the ioctl cmd and arg.
+
+   Once all subdev drivers have been converted and all drivers no longer
+   use the ioctl interface, then this function can be removed.
+ */
+int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg);
+
+static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
+                                       const struct v4l2_subdev_ops *ops)
+{
+       INIT_LIST_HEAD(&sd->list);
+       /* ops->core MUST be set */
+       BUG_ON(!ops || !ops->core);
+       sd->ops = ops;
+       sd->dev = NULL;
+       sd->name[0] = '\0';
+       sd->grp_id = 0;
+       sd->priv = NULL;
+}
+
+/* Call an ops of a v4l2_subdev, doing the right checks against
+   NULL pointers.
+
+   Example: err = v4l2_subdev_call(sd, core, g_chip_ident, &chip);
+ */
+#define v4l2_subdev_call(sd, o, f, args...)                            \
+       (!(sd) ? -ENODEV : (((sd) && (sd)->ops->o && (sd)->ops->o->f) ? \
+               (sd)->ops->o->f((sd) , ##args) : -ENOIOCTLCMD))
+
+#endif
index 8a63c404ef449d391a08ffd5760f46325f76babf..13627191a60d194de08aaa4b410aa752cfd7cb21 100644 (file)
@@ -936,10 +936,90 @@ source "block/Kconfig"
 config PREEMPT_NOTIFIERS
        bool
 
+choice
+       prompt "RCU Implementation"
+       default CLASSIC_RCU
+
 config CLASSIC_RCU
-       def_bool !PREEMPT_RCU
+       bool "Classic RCU"
        help
          This option selects the classic RCU implementation that is
          designed for best read-side performance on non-realtime
-         systems.  Classic RCU is the default.  Note that the
-         PREEMPT_RCU symbol is used to select/deselect this option.
+         systems.
+
+         Select this option if you are unsure.
+
+config TREE_RCU
+       bool "Tree-based hierarchical RCU"
+       help
+         This option selects the RCU implementation that is
+         designed for very large SMP system with hundreds or
+         thousands of CPUs.
+
+config PREEMPT_RCU
+       bool "Preemptible RCU"
+       depends on PREEMPT
+       help
+         This option reduces the latency of the kernel by making certain
+         RCU sections preemptible. Normally RCU code is non-preemptible, if
+         this option is selected then read-only RCU sections become
+         preemptible. This helps latency, but may expose bugs due to
+         now-naive assumptions about each RCU read-side critical section
+         remaining on a given CPU through its execution.
+
+endchoice
+
+config RCU_TRACE
+       bool "Enable tracing for RCU"
+       depends on TREE_RCU || PREEMPT_RCU
+       help
+         This option provides tracing in RCU which presents stats
+         in debugfs for debugging RCU implementation.
+
+         Say Y here if you want to enable RCU tracing
+         Say N if you are unsure.
+
+config RCU_FANOUT
+       int "Tree-based hierarchical RCU fanout value"
+       range 2 64 if 64BIT
+       range 2 32 if !64BIT
+       depends on TREE_RCU
+       default 64 if 64BIT
+       default 32 if !64BIT
+       help
+         This option controls the fanout of hierarchical implementations
+         of RCU, allowing RCU to work efficiently on machines with
+         large numbers of CPUs.  This value must be at least the cube
+         root of NR_CPUS, which allows NR_CPUS up to 32,768 for 32-bit
+         systems and up to 262,144 for 64-bit systems.
+
+         Select a specific number if testing RCU itself.
+         Take the default if unsure.
+
+config RCU_FANOUT_EXACT
+       bool "Disable tree-based hierarchical RCU auto-balancing"
+       depends on TREE_RCU
+       default n
+       help
+         This option forces use of the exact RCU_FANOUT value specified,
+         regardless of imbalances in the hierarchy.  This is useful for
+         testing RCU itself, and might one day be useful on systems with
+         strong NUMA behavior.
+
+         Without RCU_FANOUT_EXACT, the code will balance the hierarchy.
+
+         Say N if unsure.
+
+config TREE_RCU_TRACE
+       def_bool RCU_TRACE && TREE_RCU
+       select DEBUG_FS
+       help
+         This option provides tracing for the TREE_RCU implementation,
+         permitting Makefile to trivially select kernel/rcutree_trace.c.
+
+config PREEMPT_RCU_TRACE
+       def_bool RCU_TRACE && PREEMPT_RCU
+       select DEBUG_FS
+       help
+         This option provides tracing for the PREEMPT_RCU implementation,
+         permitting Makefile to trivially select kernel/rcupreempt_trace.c.
index 17e9757bfde2310c6bc7a8407fee6eba7cd4b0ad..2a7ce0f8e45353af2204c017c1921afdd0ba5c91 100644 (file)
@@ -540,6 +540,15 @@ void __init __weak thread_info_cache_init(void)
 {
 }
 
+void __init __weak arch_early_irq_init(void)
+{
+}
+
+void __init __weak early_irq_init(void)
+{
+       arch_early_irq_init();
+}
+
 asmlinkage void __init start_kernel(void)
 {
        char * command_line;
@@ -604,6 +613,8 @@ asmlinkage void __init start_kernel(void)
        sort_main_extable();
        trap_init();
        rcu_init();
+       /* init some links before init_ISA_irqs() */
+       early_irq_init();
        init_IRQ();
        pidhash_init();
        init_timers();
index 9fdba03dc1fcd119c31274fb3590480aa1db9f05..bf987b95b3560fbd0a7d8a820335100a55e1d105 100644 (file)
@@ -52,28 +52,3 @@ config PREEMPT
 
 endchoice
 
-config PREEMPT_RCU
-       bool "Preemptible RCU"
-       depends on PREEMPT
-       default n
-       help
-         This option reduces the latency of the kernel by making certain
-         RCU sections preemptible. Normally RCU code is non-preemptible, if
-         this option is selected then read-only RCU sections become
-         preemptible. This helps latency, but may expose bugs due to
-         now-naive assumptions about each RCU read-side critical section
-         remaining on a given CPU through its execution.
-
-         Say N if you are unsure.
-
-config RCU_TRACE
-       bool "Enable tracing for RCU - currently stats in debugfs"
-       depends on PREEMPT_RCU
-       select DEBUG_FS
-       default y
-       help
-         This option provides tracing in RCU which presents stats
-         in debugfs for debugging RCU implementation.
-
-         Say Y here if you want to enable RCU tracing
-         Say N if you are unsure.
index 027edda6351137b5f8c1ee085c2c5320d204e904..e1c5bf3365c0a4cdee8e0279f31b3c6742a9c6ef 100644 (file)
@@ -73,10 +73,10 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o
+obj-$(CONFIG_TREE_RCU) += rcutree.o
 obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o
-ifeq ($(CONFIG_PREEMPT_RCU),y)
-obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o
-endif
+obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o
+obj-$(CONFIG_PREEMPT_RCU_TRACE) += rcupreempt_trace.o
 obj-$(CONFIG_RELAY) += relay.o
 obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
index c7422ca920382b47445ace263bdba0fe6fbf6bf8..c9e5a1c14e081eb8dd9873e0eef89d964c344bc1 100644 (file)
@@ -1037,8 +1037,6 @@ NORET_TYPE void do_exit(long code)
                 * task into the wait for ever nirwana as well.
                 */
                tsk->flags |= PF_EXITPIDONE;
-               if (tsk->io_context)
-                       exit_io_context();
                set_current_state(TASK_UNINTERRUPTIBLE);
                schedule();
        }
@@ -1328,10 +1326,10 @@ static int wait_task_zombie(struct task_struct *p, int options,
                 * group, which consolidates times for all threads in the
                 * group including the group leader.
                 */
+               thread_group_cputime(p, &cputime);
                spin_lock_irq(&p->parent->sighand->siglock);
                psig = p->parent->signal;
                sig = p->signal;
-               thread_group_cputime(p, &cputime);
                psig->cutime =
                        cputime_add(psig->cutime,
                        cputime_add(cputime.utime,
index feb0317cf09ab5960d0288a31ec00d03ae5a6335..e136ed8d82ba56ab81283a48fe3d6cfb41c23c79 100644 (file)
@@ -67,3 +67,19 @@ int kernel_text_address(unsigned long addr)
                return 1;
        return module_text_address(addr) != NULL;
 }
+
+/*
+ * On some architectures (PPC64, IA64) function pointers
+ * are actually only tokens to some data that then holds the
+ * real function address. As a result, to find if a function
+ * pointer is part of the kernel text, we need to do some
+ * special dereferencing first.
+ */
+int func_ptr_is_kernel_text(void *ptr)
+{
+       unsigned long addr;
+       addr = (unsigned long) dereference_function_descriptor(ptr);
+       if (core_kernel_text(addr))
+               return 1;
+       return module_text_address(addr) != NULL;
+}
index 6144b36cd897512273f18c94f0d89958b21666c4..43cbf30669e6de76d4bc315864489deab3336eff 100644 (file)
@@ -415,8 +415,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
        set_mm_counter(mm, file_rss, 0);
        set_mm_counter(mm, anon_rss, 0);
        spin_lock_init(&mm->page_table_lock);
-       rwlock_init(&mm->ioctx_list_lock);
-       mm->ioctx_list = NULL;
+       spin_lock_init(&mm->ioctx_lock);
+       INIT_HLIST_HEAD(&mm->ioctx_list);
        mm->free_area_cache = TASK_UNMAPPED_BASE;
        mm->cached_hole_size = ~0UL;
        mm_init_owner(mm, p);
index 4fe790e89d0f34af1cc24359d32bca3b58e970ca..7c6cbabe52b3c0368e800790b638e82eb00aa657 100644 (file)
@@ -92,11 +92,12 @@ struct futex_pi_state {
  * A futex_q has a woken state, just like tasks have TASK_RUNNING.
  * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
  * The order of wakup is always to make the first condition true, then
- * wake up q->waiters, then make the second condition true.
+ * wake up q->waiter, then make the second condition true.
  */
 struct futex_q {
        struct plist_node list;
-       wait_queue_head_t waiters;
+       /* There can only be a single waiter */
+       wait_queue_head_t waiter;
 
        /* Which hash list lock to use: */
        spinlock_t *lock_ptr;
@@ -122,24 +123,6 @@ struct futex_hash_bucket {
 
 static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
 
-/*
- * Take mm->mmap_sem, when futex is shared
- */
-static inline void futex_lock_mm(struct rw_semaphore *fshared)
-{
-       if (fshared)
-               down_read(fshared);
-}
-
-/*
- * Release mm->mmap_sem, when the futex is shared
- */
-static inline void futex_unlock_mm(struct rw_semaphore *fshared)
-{
-       if (fshared)
-               up_read(fshared);
-}
-
 /*
  * We hash on the keys returned from get_futex_key (see below).
  */
@@ -161,6 +144,45 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
                && key1->both.offset == key2->both.offset);
 }
 
+/*
+ * Take a reference to the resource addressed by a key.
+ * Can be called while holding spinlocks.
+ *
+ */
+static void get_futex_key_refs(union futex_key *key)
+{
+       if (!key->both.ptr)
+               return;
+
+       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+       case FUT_OFF_INODE:
+               atomic_inc(&key->shared.inode->i_count);
+               break;
+       case FUT_OFF_MMSHARED:
+               atomic_inc(&key->private.mm->mm_count);
+               break;
+       }
+}
+
+/*
+ * Drop a reference to the resource addressed by a key.
+ * The hash bucket spinlock must not be held.
+ */
+static void drop_futex_key_refs(union futex_key *key)
+{
+       if (!key->both.ptr)
+               return;
+
+       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+       case FUT_OFF_INODE:
+               iput(key->shared.inode);
+               break;
+       case FUT_OFF_MMSHARED:
+               mmdrop(key->private.mm);
+               break;
+       }
+}
+
 /**
  * get_futex_key - Get parameters which are the keys for a futex.
  * @uaddr: virtual address of the futex
@@ -179,12 +201,10 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
  * For other futexes, it points to &current->mm->mmap_sem and
  * caller must have taken the reader lock. but NOT any spinlocks.
  */
-static int get_futex_key(u32 __user *uaddr, struct rw_semaphore *fshared,
-                        union futex_key *key)
+static int get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
 {
        unsigned long address = (unsigned long)uaddr;
        struct mm_struct *mm = current->mm;
-       struct vm_area_struct *vma;
        struct page *page;
        int err;
 
@@ -208,100 +228,50 @@ static int get_futex_key(u32 __user *uaddr, struct rw_semaphore *fshared,
                        return -EFAULT;
                key->private.mm = mm;
                key->private.address = address;
+               get_futex_key_refs(key);
                return 0;
        }
-       /*
-        * The futex is hashed differently depending on whether
-        * it's in a shared or private mapping.  So check vma first.
-        */
-       vma = find_extend_vma(mm, address);
-       if (unlikely(!vma))
-               return -EFAULT;
 
-       /*
-        * Permissions.
-        */
-       if (unlikely((vma->vm_flags & (VM_IO|VM_READ)) != VM_READ))
-               return (vma->vm_flags & VM_IO) ? -EPERM : -EACCES;
+again:
+       err = get_user_pages_fast(address, 1, 0, &page);
+       if (err < 0)
+               return err;
+
+       lock_page(page);
+       if (!page->mapping) {
+               unlock_page(page);
+               put_page(page);
+               goto again;
+       }
 
        /*
         * Private mappings are handled in a simple way.
         *
         * NOTE: When userspace waits on a MAP_SHARED mapping, even if
         * it's a read-only handle, it's expected that futexes attach to
-        * the object not the particular process.  Therefore we use
-        * VM_MAYSHARE here, not VM_SHARED which is restricted to shared
-        * mappings of _writable_ handles.
+        * the object not the particular process.
         */
-       if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
-               key->both.offset |= FUT_OFF_MMSHARED; /* reference taken on mm */
+       if (PageAnon(page)) {
+               key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
                key->private.mm = mm;
                key->private.address = address;
-               return 0;
+       } else {
+               key->both.offset |= FUT_OFF_INODE; /* inode-based key */
+               key->shared.inode = page->mapping->host;
+               key->shared.pgoff = page->index;
        }
 
-       /*
-        * Linear file mappings are also simple.
-        */
-       key->shared.inode = vma->vm_file->f_path.dentry->d_inode;
-       key->both.offset |= FUT_OFF_INODE; /* inode-based key. */
-       if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
-               key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
-                                    + vma->vm_pgoff);
-               return 0;
-       }
+       get_futex_key_refs(key);
 
-       /*
-        * We could walk the page table to read the non-linear
-        * pte, and get the page index without fetching the page
-        * from swap.  But that's a lot of code to duplicate here
-        * for a rare case, so we simply fetch the page.
-        */
-       err = get_user_pages(current, mm, address, 1, 0, 0, &page, NULL);
-       if (err >= 0) {
-               key->shared.pgoff =
-                       page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
-               put_page(page);
-               return 0;
-       }
-       return err;
-}
-
-/*
- * Take a reference to the resource addressed by a key.
- * Can be called while holding spinlocks.
- *
- */
-static void get_futex_key_refs(union futex_key *key)
-{
-       if (key->both.ptr == NULL)
-               return;
-       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
-               case FUT_OFF_INODE:
-                       atomic_inc(&key->shared.inode->i_count);
-                       break;
-               case FUT_OFF_MMSHARED:
-                       atomic_inc(&key->private.mm->mm_count);
-                       break;
-       }
+       unlock_page(page);
+       put_page(page);
+       return 0;
 }
 
-/*
- * Drop a reference to the resource addressed by a key.
- * The hash bucket spinlock must not be held.
- */
-static void drop_futex_key_refs(union futex_key *key)
+static inline
+void put_futex_key(int fshared, union futex_key *key)
 {
-       if (!key->both.ptr)
-               return;
-       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
-               case FUT_OFF_INODE:
-                       iput(key->shared.inode);
-                       break;
-               case FUT_OFF_MMSHARED:
-                       mmdrop(key->private.mm);
-                       break;
-       }
+       drop_futex_key_refs(key);
 }
 
 static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
@@ -328,10 +298,8 @@ static int get_futex_value_locked(u32 *dest, u32 __user *from)
 
 /*
  * Fault handling.
- * if fshared is non NULL, current->mm->mmap_sem is already held
  */
-static int futex_handle_fault(unsigned long address,
-                             struct rw_semaphore *fshared, int attempt)
+static int futex_handle_fault(unsigned long address, int attempt)
 {
        struct vm_area_struct * vma;
        struct mm_struct *mm = current->mm;
@@ -340,8 +308,7 @@ static int futex_handle_fault(unsigned long address,
        if (attempt > 2)
                return ret;
 
-       if (!fshared)
-               down_read(&mm->mmap_sem);
+       down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (vma && address >= vma->vm_start &&
            (vma->vm_flags & VM_WRITE)) {
@@ -361,8 +328,7 @@ static int futex_handle_fault(unsigned long address,
                                current->min_flt++;
                }
        }
-       if (!fshared)
-               up_read(&mm->mmap_sem);
+       up_read(&mm->mmap_sem);
        return ret;
 }
 
@@ -385,6 +351,7 @@ static int refill_pi_state_cache(void)
        /* pi_mutex gets initialized later */
        pi_state->owner = NULL;
        atomic_set(&pi_state->refcount, 1);
+       pi_state->key = FUTEX_KEY_INIT;
 
        current->pi_state_cache = pi_state;
 
@@ -469,7 +436,7 @@ void exit_pi_state_list(struct task_struct *curr)
        struct list_head *next, *head = &curr->pi_state_list;
        struct futex_pi_state *pi_state;
        struct futex_hash_bucket *hb;
-       union futex_key key;
+       union futex_key key = FUTEX_KEY_INIT;
 
        if (!futex_cmpxchg_enabled)
                return;
@@ -614,7 +581,7 @@ static void wake_futex(struct futex_q *q)
         * The lock in wake_up_all() is a crucial memory barrier after the
         * plist_del() and also before assigning to q->lock_ptr.
         */
-       wake_up_all(&q->waiters);
+       wake_up(&q->waiter);
        /*
         * The waiting task can free the futex_q as soon as this is written,
         * without taking any locks.  This must come last.
@@ -726,20 +693,17 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
  * Wake up all waiters hashed on the physical page that is mapped
  * to this virtual address:
  */
-static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
-                     int nr_wake, u32 bitset)
+static int futex_wake(u32 __user *uaddr, int fshared, int nr_wake, u32 bitset)
 {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
        struct plist_head *head;
-       union futex_key key;
+       union futex_key key = FUTEX_KEY_INIT;
        int ret;
 
        if (!bitset)
                return -EINVAL;
 
-       futex_lock_mm(fshared);
-
        ret = get_futex_key(uaddr, fshared, &key);
        if (unlikely(ret != 0))
                goto out;
@@ -767,7 +731,7 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
 
        spin_unlock(&hb->lock);
 out:
-       futex_unlock_mm(fshared);
+       put_futex_key(fshared, &key);
        return ret;
 }
 
@@ -776,19 +740,16 @@ out:
  * to this virtual address:
  */
 static int
-futex_wake_op(u32 __user *uaddr1, struct rw_semaphore *fshared,
-             u32 __user *uaddr2,
+futex_wake_op(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
              int nr_wake, int nr_wake2, int op)
 {
-       union futex_key key1, key2;
+       union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
        struct futex_hash_bucket *hb1, *hb2;
        struct plist_head *head;
        struct futex_q *this, *next;
        int ret, op_ret, attempt = 0;
 
 retryfull:
-       futex_lock_mm(fshared);
-
        ret = get_futex_key(uaddr1, fshared, &key1);
        if (unlikely(ret != 0))
                goto out;
@@ -833,18 +794,12 @@ retry:
                 */
                if (attempt++) {
                        ret = futex_handle_fault((unsigned long)uaddr2,
-                                                fshared, attempt);
+                                                attempt);
                        if (ret)
                                goto out;
                        goto retry;
                }
 
-               /*
-                * If we would have faulted, release mmap_sem,
-                * fault it in and start all over again.
-                */
-               futex_unlock_mm(fshared);
-
                ret = get_user(dummy, uaddr2);
                if (ret)
                        return ret;
@@ -880,7 +835,8 @@ retry:
        if (hb1 != hb2)
                spin_unlock(&hb2->lock);
 out:
-       futex_unlock_mm(fshared);
+       put_futex_key(fshared, &key2);
+       put_futex_key(fshared, &key1);
 
        return ret;
 }
@@ -889,19 +845,16 @@ out:
  * Requeue all waiters hashed on one physical page to another
  * physical page.
  */
-static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
-                        u32 __user *uaddr2,
+static int futex_requeue(u32 __user *uaddr1, int fshared, u32 __user *uaddr2,
                         int nr_wake, int nr_requeue, u32 *cmpval)
 {
-       union futex_key key1, key2;
+       union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
        struct futex_hash_bucket *hb1, *hb2;
        struct plist_head *head1;
        struct futex_q *this, *next;
        int ret, drop_count = 0;
 
  retry:
-       futex_lock_mm(fshared);
-
        ret = get_futex_key(uaddr1, fshared, &key1);
        if (unlikely(ret != 0))
                goto out;
@@ -924,12 +877,6 @@ static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
                        if (hb1 != hb2)
                                spin_unlock(&hb2->lock);
 
-                       /*
-                        * If we would have faulted, release mmap_sem, fault
-                        * it in and start all over again.
-                        */
-                       futex_unlock_mm(fshared);
-
                        ret = get_user(curval, uaddr1);
 
                        if (!ret)
@@ -981,7 +928,8 @@ out_unlock:
                drop_futex_key_refs(&key1);
 
 out:
-       futex_unlock_mm(fshared);
+       put_futex_key(fshared, &key2);
+       put_futex_key(fshared, &key1);
        return ret;
 }
 
@@ -990,7 +938,7 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
 {
        struct futex_hash_bucket *hb;
 
-       init_waitqueue_head(&q->waiters);
+       init_waitqueue_head(&q->waiter);
 
        get_futex_key_refs(&q->key);
        hb = hash_futex(&q->key);
@@ -1103,8 +1051,7 @@ static void unqueue_me_pi(struct futex_q *q)
  * private futexes.
  */
 static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-                               struct task_struct *newowner,
-                               struct rw_semaphore *fshared)
+                               struct task_struct *newowner, int fshared)
 {
        u32 newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
        struct futex_pi_state *pi_state = q->pi_state;
@@ -1183,7 +1130,7 @@ retry:
 handle_fault:
        spin_unlock(q->lock_ptr);
 
-       ret = futex_handle_fault((unsigned long)uaddr, fshared, attempt++);
+       ret = futex_handle_fault((unsigned long)uaddr, attempt++);
 
        spin_lock(q->lock_ptr);
 
@@ -1203,12 +1150,13 @@ handle_fault:
  * In case we must use restart_block to restart a futex_wait,
  * we encode in the 'flags' shared capability
  */
-#define FLAGS_SHARED  1
+#define FLAGS_SHARED           0x01
+#define FLAGS_CLOCKRT          0x02
 
 static long futex_wait_restart(struct restart_block *restart);
 
-static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
-                     u32 val, ktime_t *abs_time, u32 bitset)
+static int futex_wait(u32 __user *uaddr, int fshared,
+                     u32 val, ktime_t *abs_time, u32 bitset, int clockrt)
 {
        struct task_struct *curr = current;
        DECLARE_WAITQUEUE(wait, curr);
@@ -1225,8 +1173,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
        q.pi_state = NULL;
        q.bitset = bitset;
  retry:
-       futex_lock_mm(fshared);
-
+       q.key = FUTEX_KEY_INIT;
        ret = get_futex_key(uaddr, fshared, &q.key);
        if (unlikely(ret != 0))
                goto out_release_sem;
@@ -1258,12 +1205,6 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
        if (unlikely(ret)) {
                queue_unlock(&q, hb);
 
-               /*
-                * If we would have faulted, release mmap_sem, fault it in and
-                * start all over again.
-                */
-               futex_unlock_mm(fshared);
-
                ret = get_user(uval, uaddr);
 
                if (!ret)
@@ -1277,12 +1218,6 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
        /* Only actually queue if *uaddr contained val.  */
        queue_me(&q, hb);
 
-       /*
-        * Now the futex is queued and we have checked the data, we
-        * don't want to hold mmap_sem while we sleep.
-        */
-       futex_unlock_mm(fshared);
-
        /*
         * There might have been scheduling since the queue_me(), as we
         * cannot hold a spinlock across the get_user() in case it
@@ -1294,7 +1229,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
 
        /* add_wait_queue is the barrier after __set_current_state. */
        __set_current_state(TASK_INTERRUPTIBLE);
-       add_wait_queue(&q.waiters, &wait);
+       add_wait_queue(&q.waiter, &wait);
        /*
         * !plist_node_empty() is safe here without any lock.
         * q.lock_ptr != 0 is not safe, because of ordering against wakeup.
@@ -1307,8 +1242,10 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
                        slack = current->timer_slack_ns;
                        if (rt_task(current))
                                slack = 0;
-                       hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC,
-                                               HRTIMER_MODE_ABS);
+                       hrtimer_init_on_stack(&t.timer,
+                                             clockrt ? CLOCK_REALTIME :
+                                             CLOCK_MONOTONIC,
+                                             HRTIMER_MODE_ABS);
                        hrtimer_init_sleeper(&t, current);
                        hrtimer_set_expires_range_ns(&t.timer, *abs_time, slack);
 
@@ -1363,6 +1300,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
 
                if (fshared)
                        restart->futex.flags |= FLAGS_SHARED;
+               if (clockrt)
+                       restart->futex.flags |= FLAGS_CLOCKRT;
                return -ERESTART_RESTARTBLOCK;
        }
 
@@ -1370,7 +1309,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
        queue_unlock(&q, hb);
 
  out_release_sem:
-       futex_unlock_mm(fshared);
+       put_futex_key(fshared, &q.key);
        return ret;
 }
 
@@ -1378,15 +1317,16 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
 static long futex_wait_restart(struct restart_block *restart)
 {
        u32 __user *uaddr = (u32 __user *)restart->futex.uaddr;
-       struct rw_semaphore *fshared = NULL;
+       int fshared = 0;
        ktime_t t;
 
        t.tv64 = restart->futex.time;
        restart->fn = do_no_restart_syscall;
        if (restart->futex.flags & FLAGS_SHARED)
-               fshared = &current->mm->mmap_sem;
+               fshared = 1;
        return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
-                               restart->futex.bitset);
+                               restart->futex.bitset,
+                               restart->futex.flags & FLAGS_CLOCKRT);
 }
 
 
@@ -1396,7 +1336,7 @@ static long futex_wait_restart(struct restart_block *restart)
  * if there are waiters then it will block, it does PI, etc. (Due to
  * races the kernel might see a 0 value of the futex too.)
  */
-static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
+static int futex_lock_pi(u32 __user *uaddr, int fshared,
                         int detect, ktime_t *time, int trylock)
 {
        struct hrtimer_sleeper timeout, *to = NULL;
@@ -1419,8 +1359,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
 
        q.pi_state = NULL;
  retry:
-       futex_lock_mm(fshared);
-
+       q.key = FUTEX_KEY_INIT;
        ret = get_futex_key(uaddr, fshared, &q.key);
        if (unlikely(ret != 0))
                goto out_release_sem;
@@ -1509,7 +1448,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
                         * exit to complete.
                         */
                        queue_unlock(&q, hb);
-                       futex_unlock_mm(fshared);
                        cond_resched();
                        goto retry;
 
@@ -1541,12 +1479,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
         */
        queue_me(&q, hb);
 
-       /*
-        * Now the futex is queued and we have checked the data, we
-        * don't want to hold mmap_sem while we sleep.
-        */
-       futex_unlock_mm(fshared);
-
        WARN_ON(!q.pi_state);
        /*
         * Block on the PI mutex:
@@ -1559,7 +1491,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
                ret = ret ? 0 : -EWOULDBLOCK;
        }
 
-       futex_lock_mm(fshared);
        spin_lock(q.lock_ptr);
 
        if (!ret) {
@@ -1625,7 +1556,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
 
        /* Unqueue and drop the lock */
        unqueue_me_pi(&q);
-       futex_unlock_mm(fshared);
 
        if (to)
                destroy_hrtimer_on_stack(&to->timer);
@@ -1635,34 +1565,30 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
        queue_unlock(&q, hb);
 
  out_release_sem:
-       futex_unlock_mm(fshared);
+       put_futex_key(fshared, &q.key);
        if (to)
                destroy_hrtimer_on_stack(&to->timer);
        return ret;
 
  uaddr_faulted:
        /*
-        * We have to r/w  *(int __user *)uaddr, but we can't modify it
-        * non-atomically.  Therefore, if get_user below is not
-        * enough, we need to handle the fault ourselves, while
-        * still holding the mmap_sem.
-        *
-        * ... and hb->lock. :-) --ANK
+        * We have to r/w  *(int __user *)uaddr, and we have to modify it
+        * atomically.  Therefore, if we continue to fault after get_user()
+        * below, we need to handle the fault ourselves, while still holding
+        * the mmap_sem.  This can occur if the uaddr is under contention as
+        * we have to drop the mmap_sem in order to call get_user().
         */
        queue_unlock(&q, hb);
 
        if (attempt++) {
-               ret = futex_handle_fault((unsigned long)uaddr, fshared,
-                                        attempt);
+               ret = futex_handle_fault((unsigned long)uaddr, attempt);
                if (ret)
                        goto out_release_sem;
                goto retry_unlocked;
        }
 
-       futex_unlock_mm(fshared);
-
        ret = get_user(uval, uaddr);
-       if (!ret && (uval != -EFAULT))
+       if (!ret)
                goto retry;
 
        if (to)
@@ -1675,13 +1601,13 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
  * This is the in-kernel slowpath: we look up the PI state (if any),
  * and do the rt-mutex unlock.
  */
-static int futex_unlock_pi(u32 __user *uaddr, struct rw_semaphore *fshared)
+static int futex_unlock_pi(u32 __user *uaddr, int fshared)
 {
        struct futex_hash_bucket *hb;
        struct futex_q *this, *next;
        u32 uval;
        struct plist_head *head;
-       union futex_key key;
+       union futex_key key = FUTEX_KEY_INIT;
        int ret, attempt = 0;
 
 retry:
@@ -1692,10 +1618,6 @@ retry:
         */
        if ((uval & FUTEX_TID_MASK) != task_pid_vnr(current))
                return -EPERM;
-       /*
-        * First take all the futex related locks:
-        */
-       futex_lock_mm(fshared);
 
        ret = get_futex_key(uaddr, fshared, &key);
        if (unlikely(ret != 0))
@@ -1754,34 +1676,30 @@ retry_unlocked:
 out_unlock:
        spin_unlock(&hb->lock);
 out:
-       futex_unlock_mm(fshared);
+       put_futex_key(fshared, &key);
 
        return ret;
 
 pi_faulted:
        /*
-        * We have to r/w  *(int __user *)uaddr, but we can't modify it
-        * non-atomically.  Therefore, if get_user below is not
-        * enough, we need to handle the fault ourselves, while
-        * still holding the mmap_sem.
-        *
-        * ... and hb->lock. --ANK
+        * We have to r/w  *(int __user *)uaddr, and we have to modify it
+        * atomically.  Therefore, if we continue to fault after get_user()
+        * below, we need to handle the fault ourselves, while still holding
+        * the mmap_sem.  This can occur if the uaddr is under contention as
+        * we have to drop the mmap_sem in order to call get_user().
         */
        spin_unlock(&hb->lock);
 
        if (attempt++) {
-               ret = futex_handle_fault((unsigned long)uaddr, fshared,
-                                        attempt);
+               ret = futex_handle_fault((unsigned long)uaddr, attempt);
                if (ret)
                        goto out;
                uval = 0;
                goto retry_unlocked;
        }
 
-       futex_unlock_mm(fshared);
-
        ret = get_user(uval, uaddr);
-       if (!ret && (uval != -EFAULT))
+       if (!ret)
                goto retry;
 
        return ret;
@@ -1908,8 +1826,7 @@ retry:
                 * PI futexes happens in exit_pi_state():
                 */
                if (!pi && (uval & FUTEX_WAITERS))
-                       futex_wake(uaddr, &curr->mm->mmap_sem, 1,
-                                  FUTEX_BITSET_MATCH_ANY);
+                       futex_wake(uaddr, 1, 1, FUTEX_BITSET_MATCH_ANY);
        }
        return 0;
 }
@@ -2003,18 +1920,22 @@ void exit_robust_list(struct task_struct *curr)
 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
                u32 __user *uaddr2, u32 val2, u32 val3)
 {
-       int ret = -ENOSYS;
+       int clockrt, ret = -ENOSYS;
        int cmd = op & FUTEX_CMD_MASK;
-       struct rw_semaphore *fshared = NULL;
+       int fshared = 0;
 
        if (!(op & FUTEX_PRIVATE_FLAG))
-               fshared = &current->mm->mmap_sem;
+               fshared = 1;
+
+       clockrt = op & FUTEX_CLOCK_REALTIME;
+       if (clockrt && cmd != FUTEX_WAIT_BITSET)
+               return -ENOSYS;
 
        switch (cmd) {
        case FUTEX_WAIT:
                val3 = FUTEX_BITSET_MATCH_ANY;
        case FUTEX_WAIT_BITSET:
-               ret = futex_wait(uaddr, fshared, val, timeout, val3);
+               ret = futex_wait(uaddr, fshared, val, timeout, val3, clockrt);
                break;
        case FUTEX_WAKE:
                val3 = FUTEX_BITSET_MATCH_ANY;
index 47e63349d1b2d262be2d8be568af8d3d93de3333..bda9cb92427673a4c2e47676596e854d57d7dca3 100644 (file)
@@ -442,22 +442,6 @@ static inline void debug_hrtimer_activate(struct hrtimer *timer) { }
 static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { }
 #endif
 
-/*
- * Check, whether the timer is on the callback pending list
- */
-static inline int hrtimer_cb_pending(const struct hrtimer *timer)
-{
-       return timer->state & HRTIMER_STATE_PENDING;
-}
-
-/*
- * Remove a timer from the callback pending list
- */
-static inline void hrtimer_remove_cb_pending(struct hrtimer *timer)
-{
-       list_del_init(&timer->cb_entry);
-}
-
 /* High resolution timer related functions */
 #ifdef CONFIG_HIGH_RES_TIMERS
 
@@ -651,6 +635,8 @@ static inline void hrtimer_init_timer_hres(struct hrtimer *timer)
 {
 }
 
+static void __run_hrtimer(struct hrtimer *timer);
+
 /*
  * When High resolution timers are active, try to reprogram. Note, that in case
  * the state has HRTIMER_STATE_CALLBACK set, no reprogramming and no expiry
@@ -661,31 +647,14 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
                                            struct hrtimer_clock_base *base)
 {
        if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
-
-               /* Timer is expired, act upon the callback mode */
-               switch(timer->cb_mode) {
-               case HRTIMER_CB_IRQSAFE_PERCPU:
-               case HRTIMER_CB_IRQSAFE_UNLOCKED:
-                       /*
-                        * This is solely for the sched tick emulation with
-                        * dynamic tick support to ensure that we do not
-                        * restart the tick right on the edge and end up with
-                        * the tick timer in the softirq ! The calling site
-                        * takes care of this. Also used for hrtimer sleeper !
-                        */
-                       debug_hrtimer_deactivate(timer);
-                       return 1;
-               case HRTIMER_CB_SOFTIRQ:
-                       /*
-                        * Move everything else into the softirq pending list !
-                        */
-                       list_add_tail(&timer->cb_entry,
-                                     &base->cpu_base->cb_pending);
-                       timer->state = HRTIMER_STATE_PENDING;
-                       return 1;
-               default:
-                       BUG();
-               }
+               /*
+                * XXX: recursion check?
+                * hrtimer_forward() should round up with timer granularity
+                * so that we never get into inf recursion here,
+                * it doesn't do that though
+                */
+               __run_hrtimer(timer);
+               return 1;
        }
        return 0;
 }
@@ -724,11 +693,6 @@ static int hrtimer_switch_to_hres(void)
        return 1;
 }
 
-static inline void hrtimer_raise_softirq(void)
-{
-       raise_softirq(HRTIMER_SOFTIRQ);
-}
-
 #else
 
 static inline int hrtimer_hres_active(void) { return 0; }
@@ -747,7 +711,6 @@ static inline int hrtimer_reprogram(struct hrtimer *timer,
 {
        return 0;
 }
-static inline void hrtimer_raise_softirq(void) { }
 
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
@@ -890,10 +853,7 @@ static void __remove_hrtimer(struct hrtimer *timer,
                             struct hrtimer_clock_base *base,
                             unsigned long newstate, int reprogram)
 {
-       /* High res. callback list. NOP for !HIGHRES */
-       if (hrtimer_cb_pending(timer))
-               hrtimer_remove_cb_pending(timer);
-       else {
+       if (timer->state & HRTIMER_STATE_ENQUEUED) {
                /*
                 * Remove the timer from the rbtree and replace the
                 * first entry pointer if necessary.
@@ -953,7 +913,7 @@ hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_n
 {
        struct hrtimer_clock_base *base, *new_base;
        unsigned long flags;
-       int ret, raise;
+       int ret;
 
        base = lock_hrtimer_base(timer, &flags);
 
@@ -988,26 +948,8 @@ hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_n
        enqueue_hrtimer(timer, new_base,
                        new_base->cpu_base == &__get_cpu_var(hrtimer_bases));
 
-       /*
-        * The timer may be expired and moved to the cb_pending
-        * list. We can not raise the softirq with base lock held due
-        * to a possible deadlock with runqueue lock.
-        */
-       raise = timer->state == HRTIMER_STATE_PENDING;
-
-       /*
-        * We use preempt_disable to prevent this task from migrating after
-        * setting up the softirq and raising it. Otherwise, if me migrate
-        * we will raise the softirq on the wrong CPU.
-        */
-       preempt_disable();
-
        unlock_hrtimer_base(timer, &flags);
 
-       if (raise)
-               hrtimer_raise_softirq();
-       preempt_enable();
-
        return ret;
 }
 EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
@@ -1192,75 +1134,6 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
 }
 EXPORT_SYMBOL_GPL(hrtimer_get_res);
 
-static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
-{
-       spin_lock_irq(&cpu_base->lock);
-
-       while (!list_empty(&cpu_base->cb_pending)) {
-               enum hrtimer_restart (*fn)(struct hrtimer *);
-               struct hrtimer *timer;
-               int restart;
-               int emulate_hardirq_ctx = 0;
-
-               timer = list_entry(cpu_base->cb_pending.next,
-                                  struct hrtimer, cb_entry);
-
-               debug_hrtimer_deactivate(timer);
-               timer_stats_account_hrtimer(timer);
-
-               fn = timer->function;
-               /*
-                * A timer might have been added to the cb_pending list
-                * when it was migrated during a cpu-offline operation.
-                * Emulate hardirq context for such timers.
-                */
-               if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU ||
-                   timer->cb_mode == HRTIMER_CB_IRQSAFE_UNLOCKED)
-                       emulate_hardirq_ctx = 1;
-
-               __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0);
-               spin_unlock_irq(&cpu_base->lock);
-
-               if (unlikely(emulate_hardirq_ctx)) {
-                       local_irq_disable();
-                       restart = fn(timer);
-                       local_irq_enable();
-               } else
-                       restart = fn(timer);
-
-               spin_lock_irq(&cpu_base->lock);
-
-               timer->state &= ~HRTIMER_STATE_CALLBACK;
-               if (restart == HRTIMER_RESTART) {
-                       BUG_ON(hrtimer_active(timer));
-                       /*
-                        * Enqueue the timer, allow reprogramming of the event
-                        * device
-                        */
-                       enqueue_hrtimer(timer, timer->base, 1);
-               } else if (hrtimer_active(timer)) {
-                       /*
-                        * If the timer was rearmed on another CPU, reprogram
-                        * the event device.
-                        */
-                       struct hrtimer_clock_base *base = timer->base;
-
-                       if (base->first == &timer->node &&
-                           hrtimer_reprogram(timer, base)) {
-                               /*
-                                * Timer is expired. Thus move it from tree to
-                                * pending list again.
-                                */
-                               __remove_hrtimer(timer, base,
-                                                HRTIMER_STATE_PENDING, 0);
-                               list_add_tail(&timer->cb_entry,
-                                             &base->cpu_base->cb_pending);
-                       }
-               }
-       }
-       spin_unlock_irq(&cpu_base->lock);
-}
-
 static void __run_hrtimer(struct hrtimer *timer)
 {
        struct hrtimer_clock_base *base = timer->base;
@@ -1268,25 +1141,21 @@ static void __run_hrtimer(struct hrtimer *timer)
        enum hrtimer_restart (*fn)(struct hrtimer *);
        int restart;
 
+       WARN_ON(!irqs_disabled());
+
        debug_hrtimer_deactivate(timer);
        __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
        timer_stats_account_hrtimer(timer);
-
        fn = timer->function;
-       if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU ||
-           timer->cb_mode == HRTIMER_CB_IRQSAFE_UNLOCKED) {
-               /*
-                * Used for scheduler timers, avoid lock inversion with
-                * rq->lock and tasklist_lock.
-                *
-                * These timers are required to deal with enqueue expiry
-                * themselves and are not allowed to migrate.
-                */
-               spin_unlock(&cpu_base->lock);
-               restart = fn(timer);
-               spin_lock(&cpu_base->lock);
-       } else
-               restart = fn(timer);
+
+       /*
+        * Because we run timers from hardirq context, there is no chance
+        * they get migrated to another cpu, therefore its safe to unlock
+        * the timer base.
+        */
+       spin_unlock(&cpu_base->lock);
+       restart = fn(timer);
+       spin_lock(&cpu_base->lock);
 
        /*
         * Note: We clear the CALLBACK bit after enqueue_hrtimer to avoid
@@ -1311,7 +1180,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
        struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
        struct hrtimer_clock_base *base;
        ktime_t expires_next, now;
-       int i, raise = 0;
+       int i;
 
        BUG_ON(!cpu_base->hres_active);
        cpu_base->nr_events++;
@@ -1360,16 +1229,6 @@ void hrtimer_interrupt(struct clock_event_device *dev)
                                break;
                        }
 
-                       /* Move softirq callbacks to the pending list */
-                       if (timer->cb_mode == HRTIMER_CB_SOFTIRQ) {
-                               __remove_hrtimer(timer, base,
-                                                HRTIMER_STATE_PENDING, 0);
-                               list_add_tail(&timer->cb_entry,
-                                             &base->cpu_base->cb_pending);
-                               raise = 1;
-                               continue;
-                       }
-
                        __run_hrtimer(timer);
                }
                spin_unlock(&cpu_base->lock);
@@ -1383,10 +1242,6 @@ void hrtimer_interrupt(struct clock_event_device *dev)
                if (tick_program_event(expires_next, 0))
                        goto retry;
        }
-
-       /* Raise softirq ? */
-       if (raise)
-               raise_softirq(HRTIMER_SOFTIRQ);
 }
 
 /**
@@ -1413,11 +1268,6 @@ void hrtimer_peek_ahead_timers(void)
        local_irq_restore(flags);
 }
 
-static void run_hrtimer_softirq(struct softirq_action *h)
-{
-       run_hrtimer_pending(&__get_cpu_var(hrtimer_bases));
-}
-
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
 /*
@@ -1429,8 +1279,6 @@ static void run_hrtimer_softirq(struct softirq_action *h)
  */
 void hrtimer_run_pending(void)
 {
-       struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases);
-
        if (hrtimer_hres_active())
                return;
 
@@ -1444,8 +1292,6 @@ void hrtimer_run_pending(void)
         */
        if (tick_check_oneshot_change(!hrtimer_is_hres_enabled()))
                hrtimer_switch_to_hres();
-
-       run_hrtimer_pending(cpu_base);
 }
 
 /*
@@ -1482,14 +1328,6 @@ void hrtimer_run_queues(void)
                                        hrtimer_get_expires_tv64(timer))
                                break;
 
-                       if (timer->cb_mode == HRTIMER_CB_SOFTIRQ) {
-                               __remove_hrtimer(timer, base,
-                                       HRTIMER_STATE_PENDING, 0);
-                               list_add_tail(&timer->cb_entry,
-                                       &base->cpu_base->cb_pending);
-                               continue;
-                       }
-
                        __run_hrtimer(timer);
                }
                spin_unlock(&cpu_base->lock);
@@ -1516,9 +1354,6 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task)
 {
        sl->timer.function = hrtimer_wakeup;
        sl->task = task;
-#ifdef CONFIG_HIGH_RES_TIMERS
-       sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
-#endif
 }
 
 static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
@@ -1655,36 +1490,22 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++)
                cpu_base->clock_base[i].cpu_base = cpu_base;
 
-       INIT_LIST_HEAD(&cpu_base->cb_pending);
        hrtimer_init_hres(cpu_base);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
 
-static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
-                               struct hrtimer_clock_base *new_base, int dcpu)
+static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+                               struct hrtimer_clock_base *new_base)
 {
        struct hrtimer *timer;
        struct rb_node *node;
-       int raise = 0;
 
        while ((node = rb_first(&old_base->active))) {
                timer = rb_entry(node, struct hrtimer, node);
                BUG_ON(hrtimer_callback_running(timer));
                debug_hrtimer_deactivate(timer);
 
-               /*
-                * Should not happen. Per CPU timers should be
-                * canceled _before_ the migration code is called
-                */
-               if (timer->cb_mode == HRTIMER_CB_IRQSAFE_PERCPU) {
-                       __remove_hrtimer(timer, old_base,
-                                        HRTIMER_STATE_INACTIVE, 0);
-                       WARN(1, "hrtimer (%p %p)active but cpu %d dead\n",
-                            timer, timer->function, dcpu);
-                       continue;
-               }
-
                /*
                 * Mark it as STATE_MIGRATE not INACTIVE otherwise the
                 * timer could be seen as !active and just vanish away
@@ -1693,69 +1514,34 @@ static int migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
                __remove_hrtimer(timer, old_base, HRTIMER_STATE_MIGRATE, 0);
                timer->base = new_base;
                /*
-                * Enqueue the timer. Allow reprogramming of the event device
+                * Enqueue the timers on the new cpu, but do not reprogram 
+                * the timer as that would enable a deadlock between
+                * hrtimer_enqueue_reprogramm() running the timer and us still
+                * holding a nested base lock.
+                *
+                * Instead we tickle the hrtimer interrupt after the migration
+                * is done, which will run all expired timers and re-programm
+                * the timer device.
                 */
-               enqueue_hrtimer(timer, new_base, 1);
+               enqueue_hrtimer(timer, new_base, 0);
 
-#ifdef CONFIG_HIGH_RES_TIMERS
-               /*
-                * Happens with high res enabled when the timer was
-                * already expired and the callback mode is
-                * HRTIMER_CB_IRQSAFE_UNLOCKED (hrtimer_sleeper). The
-                * enqueue code does not move them to the soft irq
-                * pending list for performance/latency reasons, but
-                * in the migration state, we need to do that
-                * otherwise we end up with a stale timer.
-                */
-               if (timer->state == HRTIMER_STATE_MIGRATE) {
-                       timer->state = HRTIMER_STATE_PENDING;
-                       list_add_tail(&timer->cb_entry,
-                                     &new_base->cpu_base->cb_pending);
-                       raise = 1;
-               }
-#endif
                /* Clear the migration state bit */
                timer->state &= ~HRTIMER_STATE_MIGRATE;
        }
-       return raise;
-}
-
-#ifdef CONFIG_HIGH_RES_TIMERS
-static int migrate_hrtimer_pending(struct hrtimer_cpu_base *old_base,
-                                  struct hrtimer_cpu_base *new_base)
-{
-       struct hrtimer *timer;
-       int raise = 0;
-
-       while (!list_empty(&old_base->cb_pending)) {
-               timer = list_entry(old_base->cb_pending.next,
-                                  struct hrtimer, cb_entry);
-
-               __remove_hrtimer(timer, timer->base, HRTIMER_STATE_PENDING, 0);
-               timer->base = &new_base->clock_base[timer->base->index];
-               list_add_tail(&timer->cb_entry, &new_base->cb_pending);
-               raise = 1;
-       }
-       return raise;
-}
-#else
-static int migrate_hrtimer_pending(struct hrtimer_cpu_base *old_base,
-                                  struct hrtimer_cpu_base *new_base)
-{
-       return 0;
 }
-#endif
 
-static void migrate_hrtimers(int cpu)
+static int migrate_hrtimers(int scpu)
 {
        struct hrtimer_cpu_base *old_base, *new_base;
-       int i, raise = 0;
+       int dcpu, i;
 
-       BUG_ON(cpu_online(cpu));
-       old_base = &per_cpu(hrtimer_bases, cpu);
+       BUG_ON(cpu_online(scpu));
+       old_base = &per_cpu(hrtimer_bases, scpu);
        new_base = &get_cpu_var(hrtimer_bases);
 
-       tick_cancel_sched_timer(cpu);
+       dcpu = smp_processor_id();
+
+       tick_cancel_sched_timer(scpu);
        /*
         * The caller is globally serialized and nobody else
         * takes two locks at once, deadlock is not possible.
@@ -1764,41 +1550,47 @@ static void migrate_hrtimers(int cpu)
        spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
 
        for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
-               if (migrate_hrtimer_list(&old_base->clock_base[i],
-                                        &new_base->clock_base[i], cpu))
-                       raise = 1;
+               migrate_hrtimer_list(&old_base->clock_base[i],
+                                    &new_base->clock_base[i]);
        }
 
-       if (migrate_hrtimer_pending(old_base, new_base))
-               raise = 1;
-
        spin_unlock(&old_base->lock);
        spin_unlock_irq(&new_base->lock);
        put_cpu_var(hrtimer_bases);
 
-       if (raise)
-               hrtimer_raise_softirq();
+       return dcpu;
+}
+
+static void tickle_timers(void *arg)
+{
+       hrtimer_peek_ahead_timers();
 }
+
 #endif /* CONFIG_HOTPLUG_CPU */
 
 static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
                                        unsigned long action, void *hcpu)
 {
-       unsigned int cpu = (long)hcpu;
+       int scpu = (long)hcpu;
 
        switch (action) {
 
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               init_hrtimers_cpu(cpu);
+               init_hrtimers_cpu(scpu);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu);
-               migrate_hrtimers(cpu);
+       {
+               int dcpu;
+
+               clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &scpu);
+               dcpu = migrate_hrtimers(scpu);
+               smp_call_function_single(dcpu, tickle_timers, NULL, 0);
                break;
+       }
 #endif
 
        default:
@@ -1817,9 +1609,6 @@ void __init hrtimers_init(void)
        hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE,
                          (void *)(long)smp_processor_id());
        register_cpu_notifier(&hrtimers_nb);
-#ifdef CONFIG_HIGH_RES_TIMERS
-       open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq);
-#endif
 }
 
 /**
index 681c52dbfe229bbffc32db74c395f3f149738ed4..4dd5b1edac984bca7326297ecee3daf0239301f1 100644 (file)
@@ -3,3 +3,4 @@ obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
+obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o
index cc0f7321b8cede4192a4ceb9ffc97311ec9cc7d0..650ce4102a6333d9ddf097692583e55659a25333 100644 (file)
@@ -40,6 +40,9 @@ unsigned long probe_irq_on(void)
         * flush such a longstanding irq before considering it as spurious.
         */
        for_each_irq_desc_reverse(i, desc) {
+               if (!desc)
+                       continue;
+
                spin_lock_irq(&desc->lock);
                if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
                        /*
@@ -68,6 +71,9 @@ unsigned long probe_irq_on(void)
         * happened in the previous stage, it may have masked itself)
         */
        for_each_irq_desc_reverse(i, desc) {
+               if (!desc)
+                       continue;
+
                spin_lock_irq(&desc->lock);
                if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
                        desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
@@ -86,6 +92,9 @@ unsigned long probe_irq_on(void)
         * Now filter out any obviously spurious interrupts
         */
        for_each_irq_desc(i, desc) {
+               if (!desc)
+                       continue;
+
                spin_lock_irq(&desc->lock);
                status = desc->status;
 
@@ -124,6 +133,9 @@ unsigned int probe_irq_mask(unsigned long val)
        int i;
 
        for_each_irq_desc(i, desc) {
+               if (!desc)
+                       continue;
+
                spin_lock_irq(&desc->lock);
                status = desc->status;
 
@@ -166,6 +178,9 @@ int probe_irq_off(unsigned long val)
        unsigned int status;
 
        for_each_irq_desc(i, desc) {
+               if (!desc)
+                       continue;
+
                spin_lock_irq(&desc->lock);
                status = desc->status;
 
index 10b5092e9bfe749da57b2ab408e3f6d38ae81d75..6eb3c7952b6496fc9c5f8da49b982d79866e1504 100644 (file)
  */
 void dynamic_irq_init(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_desc *desc;
        unsigned long flags;
 
+       desc = irq_to_desc(irq);
        if (!desc) {
                WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
                return;
@@ -124,6 +125,7 @@ int set_irq_type(unsigned int irq, unsigned int type)
                return -ENODEV;
        }
 
+       type &= IRQ_TYPE_SENSE_MASK;
        if (type == IRQ_TYPE_NONE)
                return 0;
 
@@ -352,6 +354,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
 
        spin_lock(&desc->lock);
        mask_ack_irq(desc, irq);
+       desc = irq_remap_to_desc(irq, desc);
 
        if (unlikely(desc->status & IRQ_INPROGRESS))
                goto out_unlock;
@@ -429,6 +432,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        desc->status &= ~IRQ_INPROGRESS;
 out:
        desc->chip->eoi(irq);
+       desc = irq_remap_to_desc(irq, desc);
 
        spin_unlock(&desc->lock);
 }
@@ -465,12 +469,14 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
                    !desc->action)) {
                desc->status |= (IRQ_PENDING | IRQ_MASKED);
                mask_ack_irq(desc, irq);
+               desc = irq_remap_to_desc(irq, desc);
                goto out_unlock;
        }
        kstat_incr_irqs_this_cpu(irq, desc);
 
        /* Start handling the irq */
        desc->chip->ack(irq);
+       desc = irq_remap_to_desc(irq, desc);
 
        /* Mark the IRQ currently in progress.*/
        desc->status |= IRQ_INPROGRESS;
@@ -531,8 +537,10 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
        if (!noirqdebug)
                note_interrupt(irq, desc, action_ret);
 
-       if (desc->chip->eoi)
+       if (desc->chip->eoi) {
                desc->chip->eoi(irq);
+               desc = irq_remap_to_desc(irq, desc);
+       }
 }
 
 void
@@ -567,8 +575,10 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 
        /* Uninstall? */
        if (handle == handle_bad_irq) {
-               if (desc->chip != &no_irq_chip)
+               if (desc->chip != &no_irq_chip) {
                        mask_ack_irq(desc, irq);
+                       desc = irq_remap_to_desc(irq, desc);
+               }
                desc->status |= IRQ_DISABLED;
                desc->depth = 1;
        }
index c815b42d0f5bf12baed5e25eb92c7f2d5e4b4472..6492400cb50dfb0659a9627dcc342485a5a21021 100644 (file)
 #include <linux/random.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/rculist.h>
+#include <linux/hash.h>
 
 #include "internals.h"
 
+/*
+ * lockdep: we want to handle all irq_desc locks as a single lock-class:
+ */
+struct lock_class_key irq_desc_lock_class;
+
 /**
  * handle_bad_irq - handle spurious and unhandled irqs
  * @irq:       the interrupt number
@@ -49,6 +56,155 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
 int nr_irqs = NR_IRQS;
 EXPORT_SYMBOL_GPL(nr_irqs);
 
+void __init __attribute__((weak)) arch_early_irq_init(void)
+{
+}
+
+#ifdef CONFIG_SPARSE_IRQ
+static struct irq_desc irq_desc_init = {
+       .irq        = -1,
+       .status     = IRQ_DISABLED,
+       .chip       = &no_irq_chip,
+       .handle_irq = handle_bad_irq,
+       .depth      = 1,
+       .lock       = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+       .affinity   = CPU_MASK_ALL
+#endif
+};
+
+void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
+{
+       unsigned long bytes;
+       char *ptr;
+       int node;
+
+       /* Compute how many bytes we need per irq and allocate them */
+       bytes = nr * sizeof(unsigned int);
+
+       node = cpu_to_node(cpu);
+       ptr = kzalloc_node(bytes, GFP_ATOMIC, node);
+       printk(KERN_DEBUG "  alloc kstat_irqs on cpu %d node %d\n", cpu, node);
+
+       if (ptr)
+               desc->kstat_irqs = (unsigned int *)ptr;
+}
+
+void __attribute__((weak)) arch_init_chip_data(struct irq_desc *desc, int cpu)
+{
+}
+
+static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu)
+{
+       memcpy(desc, &irq_desc_init, sizeof(struct irq_desc));
+       desc->irq = irq;
+#ifdef CONFIG_SMP
+       desc->cpu = cpu;
+#endif
+       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+       init_kstat_irqs(desc, cpu, nr_cpu_ids);
+       if (!desc->kstat_irqs) {
+               printk(KERN_ERR "can not alloc kstat_irqs\n");
+               BUG_ON(1);
+       }
+       arch_init_chip_data(desc, cpu);
+}
+
+/*
+ * Protect the sparse_irqs:
+ */
+DEFINE_SPINLOCK(sparse_irq_lock);
+
+struct irq_desc *irq_desc_ptrs[NR_IRQS] __read_mostly;
+
+static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
+       [0 ... NR_IRQS_LEGACY-1] = {
+               .irq        = -1,
+               .status     = IRQ_DISABLED,
+               .chip       = &no_irq_chip,
+               .handle_irq = handle_bad_irq,
+               .depth      = 1,
+               .lock       = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
+#ifdef CONFIG_SMP
+               .affinity   = CPU_MASK_ALL
+#endif
+       }
+};
+
+/* FIXME: use bootmem alloc ...*/
+static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];
+
+void __init early_irq_init(void)
+{
+       struct irq_desc *desc;
+       int legacy_count;
+       int i;
+
+       desc = irq_desc_legacy;
+       legacy_count = ARRAY_SIZE(irq_desc_legacy);
+
+       for (i = 0; i < legacy_count; i++) {
+               desc[i].irq = i;
+               desc[i].kstat_irqs = kstat_irqs_legacy[i];
+
+               irq_desc_ptrs[i] = desc + i;
+       }
+
+       for (i = legacy_count; i < NR_IRQS; i++)
+               irq_desc_ptrs[i] = NULL;
+
+       arch_early_irq_init();
+}
+
+struct irq_desc *irq_to_desc(unsigned int irq)
+{
+       return (irq < NR_IRQS) ? irq_desc_ptrs[irq] : NULL;
+}
+
+struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+       int node;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_WARNING "irq >= NR_IRQS in irq_to_desc_alloc: %d %d\n",
+                               irq, NR_IRQS);
+               WARN_ON(1);
+               return NULL;
+       }
+
+       desc = irq_desc_ptrs[irq];
+       if (desc)
+               return desc;
+
+       spin_lock_irqsave(&sparse_irq_lock, flags);
+
+       /* We have to check it to avoid races with another CPU */
+       desc = irq_desc_ptrs[irq];
+       if (desc)
+               goto out_unlock;
+
+       node = cpu_to_node(cpu);
+       desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
+       printk(KERN_DEBUG "  alloc irq_desc for %d on cpu %d node %d\n",
+                irq, cpu, node);
+       if (!desc) {
+               printk(KERN_ERR "can not alloc irq_desc\n");
+               BUG_ON(1);
+       }
+       init_one_irq_desc(irq, desc, cpu);
+
+       irq_desc_ptrs[irq] = desc;
+
+out_unlock:
+       spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+       return desc;
+}
+
+#else
+
 struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
        [0 ... NR_IRQS-1] = {
                .status = IRQ_DISABLED,
@@ -62,6 +218,8 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
        }
 };
 
+#endif
+
 /*
  * What should we do if we get a hw irq event on an illegal vector?
  * Each architecture has to answer this themself.
@@ -179,8 +337,11 @@ unsigned int __do_IRQ(unsigned int irq)
                /*
                 * No locking required for CPU-local interrupts:
                 */
-               if (desc->chip->ack)
+               if (desc->chip->ack) {
                        desc->chip->ack(irq);
+                       /* get new one */
+                       desc = irq_remap_to_desc(irq, desc);
+               }
                if (likely(!(desc->status & IRQ_DISABLED))) {
                        action_ret = handle_IRQ_event(irq, desc->action);
                        if (!noirqdebug)
@@ -191,8 +352,10 @@ unsigned int __do_IRQ(unsigned int irq)
        }
 
        spin_lock(&desc->lock);
-       if (desc->chip->ack)
+       if (desc->chip->ack) {
                desc->chip->ack(irq);
+               desc = irq_remap_to_desc(irq, desc);
+       }
        /*
         * REPLAY is when Linux resends an IRQ that was dropped earlier
         * WAITING is used by probe to mark irqs that are being tested
@@ -259,19 +422,25 @@ out:
 }
 #endif
 
-
-#ifdef CONFIG_TRACE_IRQFLAGS
-/*
- * lockdep: we want to handle all irq_desc locks as a single lock-class:
- */
-static struct lock_class_key irq_desc_lock_class;
-
 void early_init_irq_lock_class(void)
 {
        struct irq_desc *desc;
        int i;
 
-       for_each_irq_desc(i, desc)
+       for_each_irq_desc(i, desc) {
+               if (!desc)
+                       continue;
+
                lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+       }
+}
+
+#ifdef CONFIG_SPARSE_IRQ
+unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       return desc->kstat_irqs[cpu];
 }
 #endif
+EXPORT_SYMBOL(kstat_irqs_cpu);
+
index 64c1c7253dae091b931652aa235ba3c44b6060c5..e6d0a43cc1255c2abb3778fcec5f5b1d4e5290ec 100644 (file)
@@ -13,6 +13,11 @@ extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
 extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                unsigned long flags);
 
+extern struct lock_class_key irq_desc_lock_class;
+extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr);
+extern spinlock_t sparse_irq_lock;
+extern struct irq_desc *irq_desc_ptrs[NR_IRQS];
+
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
 extern void register_handler_proc(unsigned int irq, struct irqaction *action);
index 801addda3c43d4a7a767b27468fee05232cb6f89..540f6c49f3fa156b2bd0d61ad2c5090ea0e46013 100644 (file)
@@ -370,16 +370,18 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                return 0;
        }
 
-       ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK);
+       /* caller masked out all except trigger mode flags */
+       ret = chip->set_type(irq, flags);
 
        if (ret)
                pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
-                               (int)(flags & IRQF_TRIGGER_MASK),
-                               irq, chip->set_type);
+                               (int)flags, irq, chip->set_type);
        else {
+               if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+                       flags |= IRQ_LEVEL;
                /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
-               desc->status &= ~IRQ_TYPE_SENSE_MASK;
-               desc->status |= flags & IRQ_TYPE_SENSE_MASK;
+               desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
+               desc->status |= flags;
        }
 
        return ret;
@@ -459,7 +461,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
 
                /* Setup the type (level, edge polarity) if configured: */
                if (new->flags & IRQF_TRIGGER_MASK) {
-                       ret = __irq_set_trigger(desc, irq, new->flags);
+                       ret = __irq_set_trigger(desc, irq,
+                                       new->flags & IRQF_TRIGGER_MASK);
 
                        if (ret) {
                                spin_unlock_irqrestore(&desc->lock, flags);
@@ -673,6 +676,18 @@ int request_irq(unsigned int irq, irq_handler_t handler,
        struct irq_desc *desc;
        int retval;
 
+       /*
+        * handle_IRQ_event() always ignores IRQF_DISABLED except for
+        * the _first_ irqaction (sigh).  That can cause oopsing, but
+        * the behavior is classified as "will not fix" so we need to
+        * start nudging drivers away from using that idiom.
+        */
+       if ((irqflags & (IRQF_SHARED|IRQF_DISABLED))
+                       == (IRQF_SHARED|IRQF_DISABLED))
+               pr_warning("IRQ %d/%s: IRQF_DISABLED is not "
+                               "guaranteed on shared IRQs\n",
+                               irq, devname);
+
 #ifdef CONFIG_LOCKDEP
        /*
         * Lockdep wants atomic interrupt handlers:
diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c
new file mode 100644 (file)
index 0000000..089c374
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * NUMA irq-desc migration code
+ *
+ * Migrate IRQ data structures (irq_desc, chip_data, etc.) over to
+ * the new "home node" of the IRQ.
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include "internals.h"
+
+static void init_copy_kstat_irqs(struct irq_desc *old_desc,
+                                struct irq_desc *desc,
+                                int cpu, int nr)
+{
+       unsigned long bytes;
+
+       init_kstat_irqs(desc, cpu, nr);
+
+       if (desc->kstat_irqs != old_desc->kstat_irqs) {
+               /* Compute how many bytes we need per irq and allocate them */
+               bytes = nr * sizeof(unsigned int);
+
+               memcpy(desc->kstat_irqs, old_desc->kstat_irqs, bytes);
+       }
+}
+
+static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc)
+{
+       if (old_desc->kstat_irqs == desc->kstat_irqs)
+               return;
+
+       kfree(old_desc->kstat_irqs);
+       old_desc->kstat_irqs = NULL;
+}
+
+static void init_copy_one_irq_desc(int irq, struct irq_desc *old_desc,
+                struct irq_desc *desc, int cpu)
+{
+       memcpy(desc, old_desc, sizeof(struct irq_desc));
+       desc->cpu = cpu;
+       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+       init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids);
+       arch_init_copy_chip_data(old_desc, desc, cpu);
+}
+
+static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc)
+{
+       free_kstat_irqs(old_desc, desc);
+       arch_free_chip_data(old_desc, desc);
+}
+
+static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
+                                               int cpu)
+{
+       struct irq_desc *desc;
+       unsigned int irq;
+       unsigned long flags;
+       int node;
+
+       irq = old_desc->irq;
+
+       spin_lock_irqsave(&sparse_irq_lock, flags);
+
+       /* We have to check it to avoid races with another CPU */
+       desc = irq_desc_ptrs[irq];
+
+       if (desc && old_desc != desc)
+                       goto out_unlock;
+
+       node = cpu_to_node(cpu);
+       desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
+       printk(KERN_DEBUG "  move irq_desc for %d to cpu %d node %d\n",
+                irq, cpu, node);
+       if (!desc) {
+               printk(KERN_ERR "can not get new irq_desc for moving\n");
+               /* still use old one */
+               desc = old_desc;
+               goto out_unlock;
+       }
+       init_copy_one_irq_desc(irq, old_desc, desc, cpu);
+
+       irq_desc_ptrs[irq] = desc;
+
+       /* free the old one */
+       free_one_irq_desc(old_desc, desc);
+       kfree(old_desc);
+
+out_unlock:
+       spin_unlock_irqrestore(&sparse_irq_lock, flags);
+
+       return desc;
+}
+
+struct irq_desc *move_irq_desc(struct irq_desc *desc, int cpu)
+{
+       int old_cpu;
+       int node, old_node;
+
+       /* those all static, do move them */
+       if (desc->irq < NR_IRQS_LEGACY)
+               return desc;
+
+       old_cpu = desc->cpu;
+       printk(KERN_DEBUG
+                "try to move irq_desc from cpu %d to %d\n", old_cpu, cpu);
+       if (old_cpu != cpu) {
+               node = cpu_to_node(cpu);
+               old_node = cpu_to_node(old_cpu);
+               if (old_node != node)
+                       desc = __real_move_irq_desc(desc, cpu);
+               else
+                       desc->cpu = cpu;
+       }
+
+       return desc;
+}
+
index d257e7d6a8a4ba4b10504dcd8490c812fe37504c..f6b3440f05bc50dbe68cdb7026e4e287e227b934 100644 (file)
@@ -243,7 +243,11 @@ void init_irq_proc(void)
        /*
         * Create entries for all existing IRQs.
         */
-       for_each_irq_desc(irq, desc)
+       for_each_irq_desc(irq, desc) {
+               if (!desc)
+                       continue;
+
                register_irq_proc(irq, desc);
+       }
 }
 
index dd364c11e56e0f82e0e923fcc3b60d17524e991d..3738107531fd29190b62e628d4d7da8f1081ec96 100644 (file)
@@ -91,6 +91,9 @@ static int misrouted_irq(int irq)
        int i, ok = 0;
 
        for_each_irq_desc(i, desc) {
+               if (!desc)
+                       continue;
+
                if (!i)
                         continue;
 
@@ -112,6 +115,8 @@ static void poll_spurious_irqs(unsigned long dummy)
        for_each_irq_desc(i, desc) {
                unsigned int status;
 
+               if (!desc)
+                       continue;
                if (!i)
                         continue;
 
index 74b1878b8bb8170a21957e74600465437aa225bd..06b0c3568f0b230a8c6b669d055c8c442a7eb790 100644 (file)
@@ -137,16 +137,16 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock)
 #ifdef CONFIG_LOCK_STAT
 static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats);
 
-static int lock_contention_point(struct lock_class *class, unsigned long ip)
+static int lock_point(unsigned long points[], unsigned long ip)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
-               if (class->contention_point[i] == 0) {
-                       class->contention_point[i] = ip;
+       for (i = 0; i < LOCKSTAT_POINTS; i++) {
+               if (points[i] == 0) {
+                       points[i] = ip;
                        break;
                }
-               if (class->contention_point[i] == ip)
+               if (points[i] == ip)
                        break;
        }
 
@@ -186,6 +186,9 @@ struct lock_class_stats lock_stats(struct lock_class *class)
                for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++)
                        stats.contention_point[i] += pcs->contention_point[i];
 
+               for (i = 0; i < ARRAY_SIZE(stats.contending_point); i++)
+                       stats.contending_point[i] += pcs->contending_point[i];
+
                lock_time_add(&pcs->read_waittime, &stats.read_waittime);
                lock_time_add(&pcs->write_waittime, &stats.write_waittime);
 
@@ -210,6 +213,7 @@ void clear_lock_stats(struct lock_class *class)
                memset(cpu_stats, 0, sizeof(struct lock_class_stats));
        }
        memset(class->contention_point, 0, sizeof(class->contention_point));
+       memset(class->contending_point, 0, sizeof(class->contending_point));
 }
 
 static struct lock_class_stats *get_lock_stats(struct lock_class *class)
@@ -288,14 +292,12 @@ void lockdep_off(void)
 {
        current->lockdep_recursion++;
 }
-
 EXPORT_SYMBOL(lockdep_off);
 
 void lockdep_on(void)
 {
        current->lockdep_recursion--;
 }
-
 EXPORT_SYMBOL(lockdep_on);
 
 /*
@@ -577,7 +579,8 @@ static void print_lock_class_header(struct lock_class *class, int depth)
 /*
  * printk all lock dependencies starting at <entry>:
  */
-static void print_lock_dependencies(struct lock_class *class, int depth)
+static void __used
+print_lock_dependencies(struct lock_class *class, int depth)
 {
        struct lock_list *entry;
 
@@ -2509,7 +2512,6 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
        if (subclass)
                register_lock_class(lock, subclass, 1);
 }
-
 EXPORT_SYMBOL_GPL(lockdep_init_map);
 
 /*
@@ -2690,8 +2692,9 @@ static int check_unlock(struct task_struct *curr, struct lockdep_map *lock,
 }
 
 static int
-__lock_set_subclass(struct lockdep_map *lock,
-                   unsigned int subclass, unsigned long ip)
+__lock_set_class(struct lockdep_map *lock, const char *name,
+                struct lock_class_key *key, unsigned int subclass,
+                unsigned long ip)
 {
        struct task_struct *curr = current;
        struct held_lock *hlock, *prev_hlock;
@@ -2718,6 +2721,7 @@ __lock_set_subclass(struct lockdep_map *lock,
        return print_unlock_inbalance_bug(curr, lock, ip);
 
 found_it:
+       lockdep_init_map(lock, name, key, 0);
        class = register_lock_class(lock, subclass, 0);
        hlock->class_idx = class - lock_classes + 1;
 
@@ -2902,9 +2906,9 @@ static void check_flags(unsigned long flags)
 #endif
 }
 
-void
-lock_set_subclass(struct lockdep_map *lock,
-                 unsigned int subclass, unsigned long ip)
+void lock_set_class(struct lockdep_map *lock, const char *name,
+                   struct lock_class_key *key, unsigned int subclass,
+                   unsigned long ip)
 {
        unsigned long flags;
 
@@ -2914,13 +2918,12 @@ lock_set_subclass(struct lockdep_map *lock,
        raw_local_irq_save(flags);
        current->lockdep_recursion = 1;
        check_flags(flags);
-       if (__lock_set_subclass(lock, subclass, ip))
+       if (__lock_set_class(lock, name, key, subclass, ip))
                check_chain_key(current);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
-
-EXPORT_SYMBOL_GPL(lock_set_subclass);
+EXPORT_SYMBOL_GPL(lock_set_class);
 
 /*
  * We are not always called with irqs disabled - do that here,
@@ -2944,7 +2947,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL_GPL(lock_acquire);
 
 void lock_release(struct lockdep_map *lock, int nested,
@@ -2962,7 +2964,6 @@ void lock_release(struct lockdep_map *lock, int nested,
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL_GPL(lock_release);
 
 #ifdef CONFIG_LOCK_STAT
@@ -3000,7 +3001,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
        struct held_lock *hlock, *prev_hlock;
        struct lock_class_stats *stats;
        unsigned int depth;
-       int i, point;
+       int i, contention_point, contending_point;
 
        depth = curr->lockdep_depth;
        if (DEBUG_LOCKS_WARN_ON(!depth))
@@ -3024,18 +3025,22 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip)
 found_it:
        hlock->waittime_stamp = sched_clock();
 
-       point = lock_contention_point(hlock_class(hlock), ip);
+       contention_point = lock_point(hlock_class(hlock)->contention_point, ip);
+       contending_point = lock_point(hlock_class(hlock)->contending_point,
+                                     lock->ip);
 
        stats = get_lock_stats(hlock_class(hlock));
-       if (point < ARRAY_SIZE(stats->contention_point))
-               stats->contention_point[point]++;
+       if (contention_point < LOCKSTAT_POINTS)
+               stats->contention_point[contention_point]++;
+       if (contending_point < LOCKSTAT_POINTS)
+               stats->contending_point[contending_point]++;
        if (lock->cpu != smp_processor_id())
                stats->bounces[bounce_contended + !!hlock->read]++;
        put_lock_stats(stats);
 }
 
 static void
-__lock_acquired(struct lockdep_map *lock)
+__lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        struct task_struct *curr = current;
        struct held_lock *hlock, *prev_hlock;
@@ -3084,6 +3089,7 @@ found_it:
        put_lock_stats(stats);
 
        lock->cpu = cpu;
+       lock->ip = ip;
 }
 
 void lock_contended(struct lockdep_map *lock, unsigned long ip)
@@ -3105,7 +3111,7 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 }
 EXPORT_SYMBOL_GPL(lock_contended);
 
-void lock_acquired(struct lockdep_map *lock)
+void lock_acquired(struct lockdep_map *lock, unsigned long ip)
 {
        unsigned long flags;
 
@@ -3118,7 +3124,7 @@ void lock_acquired(struct lockdep_map *lock)
        raw_local_irq_save(flags);
        check_flags(flags);
        current->lockdep_recursion = 1;
-       __lock_acquired(lock);
+       __lock_acquired(lock, ip);
        current->lockdep_recursion = 0;
        raw_local_irq_restore(flags);
 }
@@ -3442,7 +3448,6 @@ retry:
        if (unlock)
                read_unlock(&tasklist_lock);
 }
-
 EXPORT_SYMBOL_GPL(debug_show_all_locks);
 
 /*
@@ -3463,7 +3468,6 @@ void debug_show_held_locks(struct task_struct *task)
 {
                __debug_show_held_locks(task);
 }
-
 EXPORT_SYMBOL_GPL(debug_show_held_locks);
 
 void lockdep_sys_exit(void)
index 20dbcbf9c7dd2cf34486f3e9f307f1e3cf8a97bc..13716b8138961ee9f5feffe23ad9115fc27766e3 100644 (file)
@@ -470,11 +470,12 @@ static void seq_line(struct seq_file *m, char c, int offset, int length)
 
 static void snprint_time(char *buf, size_t bufsiz, s64 nr)
 {
-       unsigned long rem;
+       s64 div;
+       s32 rem;
 
        nr += 5; /* for display rounding */
-       rem = do_div(nr, 1000); /* XXX: do_div_signed */
-       snprintf(buf, bufsiz, "%lld.%02d", (long long)nr, (int)rem/10);
+       div = div_s64_rem(nr, 1000, &rem);
+       snprintf(buf, bufsiz, "%lld.%02d", (long long)div, (int)rem/10);
 }
 
 static void seq_time(struct seq_file *m, s64 time)
@@ -556,7 +557,7 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
        if (stats->read_holdtime.nr)
                namelen += 2;
 
-       for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
+       for (i = 0; i < LOCKSTAT_POINTS; i++) {
                char sym[KSYM_SYMBOL_LEN];
                char ip[32];
 
@@ -573,6 +574,23 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
                                stats->contention_point[i],
                                ip, sym);
        }
+       for (i = 0; i < LOCKSTAT_POINTS; i++) {
+               char sym[KSYM_SYMBOL_LEN];
+               char ip[32];
+
+               if (class->contending_point[i] == 0)
+                       break;
+
+               if (!i)
+                       seq_line(m, '-', 40-namelen, namelen);
+
+               sprint_symbol(sym, class->contending_point[i]);
+               snprintf(ip, sizeof(ip), "[<%p>]",
+                               (void *)class->contending_point[i]);
+               seq_printf(m, "%40s %14lu %29s %s\n", name,
+                               stats->contending_point[i],
+                               ip, sym);
+       }
        if (i) {
                seq_puts(m, "\n");
                seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1));
@@ -582,7 +600,7 @@ static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
 
 static void seq_header(struct seq_file *m)
 {
-       seq_printf(m, "lock_stat version 0.2\n");
+       seq_printf(m, "lock_stat version 0.3\n");
        seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
        seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
                        "%14s %14s\n",
index 12c779dc65d48a56f1941cc41d73f9593828cf0a..4f45d4b658ef6ab1fda9357725b01361a6768a76 100644 (file)
@@ -59,7 +59,7 @@ EXPORT_SYMBOL(__mutex_init);
  * We also put the fastpath first in the kernel image, to make sure the
  * branch is predicted by the CPU as default-untaken.
  */
-static void noinline __sched
+static __used noinline void __sched
 __mutex_lock_slowpath(atomic_t *lock_count);
 
 /***
@@ -96,7 +96,7 @@ void inline __sched mutex_lock(struct mutex *lock)
 EXPORT_SYMBOL(mutex_lock);
 #endif
 
-static noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
+static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
 
 /***
  * mutex_unlock - release the mutex
@@ -184,7 +184,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
        }
 
 done:
-       lock_acquired(&lock->dep_map);
+       lock_acquired(&lock->dep_map, ip);
        /* got the lock - rejoice! */
        mutex_remove_waiter(lock, &waiter, task_thread_info(task));
        debug_mutex_set_owner(lock, task_thread_info(task));
@@ -268,7 +268,7 @@ __mutex_unlock_common_slowpath(atomic_t *lock_count, int nested)
 /*
  * Release the lock, slowpath:
  */
-static noinline void
+static __used noinline void
 __mutex_unlock_slowpath(atomic_t *lock_count)
 {
        __mutex_unlock_common_slowpath(lock_count, 1);
@@ -313,7 +313,7 @@ int __sched mutex_lock_killable(struct mutex *lock)
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
-static noinline void __sched
+static __used noinline void __sched
 __mutex_lock_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
index 4282c0a40a57ada651b86c7dcce2389abf489448..61d5aa5eced3466393582e4f566b63c468ea7cc3 100644 (file)
@@ -82,6 +82,14 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
 
        while (nb && nr_to_call) {
                next_nb = rcu_dereference(nb->next);
+
+#ifdef CONFIG_DEBUG_NOTIFIERS
+               if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
+                       WARN(1, "Invalid notifier called!");
+                       nb = next_nb;
+                       continue;
+               }
+#endif
                ret = nb->notifier_call(nb, val, v);
 
                if (nr_calls)
index 4d5088355bfefba8956ff5c91cbc4b932d23eff6..13f06349a7868aa2ad79635266b94050eb932545 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/debug_locks.h>
 #include <linux/random.h>
 #include <linux/kallsyms.h>
+#include <linux/dmi.h>
 
 int panic_on_oops;
 static unsigned long tainted_mask;
@@ -321,36 +322,27 @@ void oops_exit(void)
 }
 
 #ifdef WANT_WARN_ON_SLOWPATH
-void warn_on_slowpath(const char *file, int line)
-{
-       char function[KSYM_SYMBOL_LEN];
-       unsigned long caller = (unsigned long) __builtin_return_address(0);
-       sprint_symbol(function, caller);
-
-       printk(KERN_WARNING "------------[ cut here ]------------\n");
-       printk(KERN_WARNING "WARNING: at %s:%d %s()\n", file,
-               line, function);
-       print_modules();
-       dump_stack();
-       print_oops_end_marker();
-       add_taint(TAINT_WARN);
-}
-EXPORT_SYMBOL(warn_on_slowpath);
-
-
 void warn_slowpath(const char *file, int line, const char *fmt, ...)
 {
        va_list args;
        char function[KSYM_SYMBOL_LEN];
        unsigned long caller = (unsigned long)__builtin_return_address(0);
+       const char *board;
+
        sprint_symbol(function, caller);
 
        printk(KERN_WARNING "------------[ cut here ]------------\n");
        printk(KERN_WARNING "WARNING: at %s:%d %s()\n", file,
                line, function);
-       va_start(args, fmt);
-       vprintk(fmt, args);
-       va_end(args);
+       board = dmi_get_system_info(DMI_PRODUCT_NAME);
+       if (board)
+               printk(KERN_WARNING "Hardware name: %s\n", board);
+
+       if (fmt) {
+               va_start(args, fmt);
+               vprintk(fmt, args);
+               va_end(args);
+       }
 
        print_modules();
        dump_stack();
index 4e5288a831de2e696260c12f97d60fdbcfc551a3..157de3a478321ab80c8c05cee5ffd07da68bab39 100644 (file)
@@ -58,21 +58,21 @@ void thread_group_cputime(
        struct task_struct *tsk,
        struct task_cputime *times)
 {
-       struct signal_struct *sig;
+       struct task_cputime *totals, *tot;
        int i;
-       struct task_cputime *tot;
 
-       sig = tsk->signal;
-       if (unlikely(!sig) || !sig->cputime.totals) {
+       totals = tsk->signal->cputime.totals;
+       if (!totals) {
                times->utime = tsk->utime;
                times->stime = tsk->stime;
                times->sum_exec_runtime = tsk->se.sum_exec_runtime;
                return;
        }
+
        times->stime = times->utime = cputime_zero;
        times->sum_exec_runtime = 0;
        for_each_possible_cpu(i) {
-               tot = per_cpu_ptr(tsk->signal->cputime.totals, i);
+               tot = per_cpu_ptr(totals, i);
                times->utime = cputime_add(times->utime, tot->utime);
                times->stime = cputime_add(times->stime, tot->stime);
                times->sum_exec_runtime += tot->sum_exec_runtime;
index a140e44eebbacbe88b989e98b1bbdc744a99c94f..887c63787de6634b9d46ddcdbb386d5d3ffe5250 100644 (file)
@@ -116,7 +116,7 @@ static DEFINE_SPINLOCK(idr_lock);
  *         must supply functions here, even if the function just returns
  *         ENOSYS.  The standard POSIX timer management code assumes the
  *         following: 1.) The k_itimer struct (sched.h) is used for the
- *         timer.  2.) The list, it_lock, it_clock, it_id and it_process
+ *         timer.  2.) The list, it_lock, it_clock, it_id and it_pid
  *         fields are not modified by timer code.
  *
  *          At this time all functions EXCEPT clock_nanosleep can be
@@ -319,7 +319,8 @@ void do_schedule_next_timer(struct siginfo *info)
 
 int posix_timer_event(struct k_itimer *timr, int si_private)
 {
-       int shared, ret;
+       struct task_struct *task;
+       int shared, ret = -1;
        /*
         * FIXME: if ->sigq is queued we can race with
         * dequeue_signal()->do_schedule_next_timer().
@@ -333,8 +334,13 @@ int posix_timer_event(struct k_itimer *timr, int si_private)
         */
        timr->sigq->info.si_sys_private = si_private;
 
-       shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID);
-       ret = send_sigqueue(timr->sigq, timr->it_process, shared);
+       rcu_read_lock();
+       task = pid_task(timr->it_pid, PIDTYPE_PID);
+       if (task) {
+               shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID);
+               ret = send_sigqueue(timr->sigq, task, shared);
+       }
+       rcu_read_unlock();
        /* If we failed to send the signal the timer stops. */
        return ret > 0;
 }
@@ -411,7 +417,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
        return ret;
 }
 
-static struct task_struct * good_sigevent(sigevent_t * event)
+static struct pid *good_sigevent(sigevent_t * event)
 {
        struct task_struct *rtn = current->group_leader;
 
@@ -425,7 +431,7 @@ static struct task_struct * good_sigevent(sigevent_t * event)
            ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX)))
                return NULL;
 
-       return rtn;
+       return task_pid(rtn);
 }
 
 void register_posix_clock(const clockid_t clock_id, struct k_clock *new_clock)
@@ -464,6 +470,7 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
                idr_remove(&posix_timers_id, tmr->it_id);
                spin_unlock_irqrestore(&idr_lock, flags);
        }
+       put_pid(tmr->it_pid);
        sigqueue_free(tmr->sigq);
        kmem_cache_free(posix_timers_cache, tmr);
 }
@@ -477,7 +484,6 @@ sys_timer_create(const clockid_t which_clock,
 {
        struct k_itimer *new_timer;
        int error, new_timer_id;
-       struct task_struct *process;
        sigevent_t event;
        int it_id_set = IT_ID_NOT_SET;
 
@@ -531,11 +537,9 @@ sys_timer_create(const clockid_t which_clock,
                        goto out;
                }
                rcu_read_lock();
-               process = good_sigevent(&event);
-               if (process)
-                       get_task_struct(process);
+               new_timer->it_pid = get_pid(good_sigevent(&event));
                rcu_read_unlock();
-               if (!process) {
+               if (!new_timer->it_pid) {
                        error = -EINVAL;
                        goto out;
                }
@@ -543,8 +547,7 @@ sys_timer_create(const clockid_t which_clock,
                event.sigev_notify = SIGEV_SIGNAL;
                event.sigev_signo = SIGALRM;
                event.sigev_value.sival_int = new_timer->it_id;
-               process = current->group_leader;
-               get_task_struct(process);
+               new_timer->it_pid = get_pid(task_tgid(current));
        }
 
        new_timer->it_sigev_notify     = event.sigev_notify;
@@ -554,7 +557,7 @@ sys_timer_create(const clockid_t which_clock,
        new_timer->sigq->info.si_code  = SI_TIMER;
 
        spin_lock_irq(&current->sighand->siglock);
-       new_timer->it_process = process;
+       new_timer->it_signal = current->signal;
        list_add(&new_timer->list, &current->signal->posix_timers);
        spin_unlock_irq(&current->sighand->siglock);
 
@@ -589,8 +592,7 @@ static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags)
        timr = idr_find(&posix_timers_id, (int)timer_id);
        if (timr) {
                spin_lock(&timr->it_lock);
-               if (timr->it_process &&
-                   same_thread_group(timr->it_process, current)) {
+               if (timr->it_signal == current->signal) {
                        spin_unlock(&idr_lock);
                        return timr;
                }
@@ -837,8 +839,7 @@ retry_delete:
         * This keeps any tasks waiting on the spin lock from thinking
         * they got something (see the lock code above).
         */
-       put_task_struct(timer->it_process);
-       timer->it_process = NULL;
+       timer->it_signal = NULL;
 
        unlock_timer(timer, flags);
        release_posix_timer(timer, IT_ID_SET);
@@ -864,8 +865,7 @@ retry_delete:
         * This keeps any tasks waiting on the spin lock from thinking
         * they got something (see the lock code above).
         */
-       put_task_struct(timer->it_process);
-       timer->it_process = NULL;
+       timer->it_signal = NULL;
 
        unlock_timer(timer, flags);
        release_posix_timer(timer, IT_ID_SET);
index f492f1583d77f7bcb5cedad94352a18a9d5f9919..e651ab05655f9f92b0bc9e9230ff59990eabb17a 100644 (file)
@@ -662,7 +662,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        if (recursion_bug) {
                recursion_bug = 0;
                strcpy(printk_buf, recursion_bug_msg);
-               printed_len = sizeof(recursion_bug_msg);
+               printed_len = strlen(recursion_bug_msg);
        }
        /* Emit the output into the temporary buffer */
        printed_len += vscnprintf(printk_buf + printed_len,
index 37f72e551542234d2d7d905741e8a5f6fb7532ec..e503a002f330fb1f7ed74ef996384e74ae294d44 100644 (file)
@@ -191,7 +191,7 @@ static void print_other_cpu_stall(struct rcu_ctrlblk *rcp)
 
        /* OK, time to rat on our buddy... */
 
-       printk(KERN_ERR "RCU detected CPU stalls:");
+       printk(KERN_ERR "INFO: RCU detected CPU stalls:");
        for_each_possible_cpu(cpu) {
                if (cpu_isset(cpu, rcp->cpumask))
                        printk(" %d", cpu);
@@ -204,7 +204,7 @@ static void print_cpu_stall(struct rcu_ctrlblk *rcp)
 {
        unsigned long flags;
 
-       printk(KERN_ERR "RCU detected CPU %d stall (t=%lu/%lu jiffies)\n",
+       printk(KERN_ERR "INFO: RCU detected CPU %d stall (t=%lu/%lu jiffies)\n",
                        smp_processor_id(), jiffies,
                        jiffies - rcp->gp_start);
        dump_stack();
index 59236e8b9daa38e1e92a709e769fa75d857bb41e..04982659875a0fe67b4483874674ad862e3a6640 100644 (file)
@@ -551,6 +551,16 @@ void rcu_irq_exit(void)
        }
 }
 
+void rcu_nmi_enter(void)
+{
+       rcu_irq_enter();
+}
+
+void rcu_nmi_exit(void)
+{
+       rcu_irq_exit();
+}
+
 static void dyntick_save_progress_counter(int cpu)
 {
        struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu);
index 35c2d3360ecf750be63922a89101f6cfac249107..7c2665cac17220698caa5009b56ec863653083d3 100644 (file)
@@ -149,12 +149,12 @@ static void rcupreempt_trace_sum(struct rcupreempt_trace *sp)
                sp->done_length += cp->done_length;
                sp->done_add += cp->done_add;
                sp->done_remove += cp->done_remove;
-               atomic_set(&sp->done_invoked, atomic_read(&cp->done_invoked));
+               atomic_add(atomic_read(&cp->done_invoked), &sp->done_invoked);
                sp->rcu_check_callbacks += cp->rcu_check_callbacks;
-               atomic_set(&sp->rcu_try_flip_1,
-                          atomic_read(&cp->rcu_try_flip_1));
-               atomic_set(&sp->rcu_try_flip_e1,
-                          atomic_read(&cp->rcu_try_flip_e1));
+               atomic_add(atomic_read(&cp->rcu_try_flip_1),
+                          &sp->rcu_try_flip_1);
+               atomic_add(atomic_read(&cp->rcu_try_flip_e1),
+                          &sp->rcu_try_flip_e1);
                sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1;
                sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1;
                sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1;
index 85cb90588a55ca54348f00a46cdd9199c6bba2bf..b31065522104f1a324404ea721489909d9a845f7 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/freezer.h>
 #include <linux/cpu.h>
 #include <linux/delay.h>
@@ -108,7 +109,6 @@ struct rcu_torture {
        int rtort_mbtest;
 };
 
-static int fullstop = 0;       /* stop generating callbacks at test end. */
 static LIST_HEAD(rcu_torture_freelist);
 static struct rcu_torture *rcu_torture_current = NULL;
 static long rcu_torture_current_version = 0;
@@ -136,6 +136,30 @@ static int stutter_pause_test = 0;
 #endif
 int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
 
+#define FULLSTOP_SIGNALED 1    /* Bail due to signal. */
+#define FULLSTOP_CLEANUP  2    /* Orderly shutdown. */
+static int fullstop;           /* stop generating callbacks at test end. */
+DEFINE_MUTEX(fullstop_mutex);  /* protect fullstop transitions and */
+                               /*  spawning of kthreads. */
+
+/*
+ * Detect and respond to a signal-based shutdown.
+ */
+static int
+rcutorture_shutdown_notify(struct notifier_block *unused1,
+                          unsigned long unused2, void *unused3)
+{
+       if (fullstop)
+               return NOTIFY_DONE;
+       if (signal_pending(current)) {
+               mutex_lock(&fullstop_mutex);
+               if (!ACCESS_ONCE(fullstop))
+                       fullstop = FULLSTOP_SIGNALED;
+               mutex_unlock(&fullstop_mutex);
+       }
+       return NOTIFY_DONE;
+}
+
 /*
  * Allocate an element from the rcu_tortures pool.
  */
@@ -199,11 +223,12 @@ rcu_random(struct rcu_random_state *rrsp)
 static void
 rcu_stutter_wait(void)
 {
-       while (stutter_pause_test || !rcutorture_runnable)
+       while ((stutter_pause_test || !rcutorture_runnable) && !fullstop) {
                if (rcutorture_runnable)
                        schedule_timeout_interruptible(1);
                else
                        schedule_timeout_interruptible(round_jiffies_relative(HZ));
+       }
 }
 
 /*
@@ -599,7 +624,7 @@ rcu_torture_writer(void *arg)
                rcu_stutter_wait();
        } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
-       while (!kthread_should_stop())
+       while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
                schedule_timeout_uninterruptible(1);
        return 0;
 }
@@ -624,7 +649,7 @@ rcu_torture_fakewriter(void *arg)
        } while (!kthread_should_stop() && !fullstop);
 
        VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
-       while (!kthread_should_stop())
+       while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
                schedule_timeout_uninterruptible(1);
        return 0;
 }
@@ -734,7 +759,7 @@ rcu_torture_reader(void *arg)
        VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
        if (irqreader && cur_ops->irqcapable)
                del_timer_sync(&t);
-       while (!kthread_should_stop())
+       while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
                schedule_timeout_uninterruptible(1);
        return 0;
 }
@@ -831,7 +856,7 @@ rcu_torture_stats(void *arg)
        do {
                schedule_timeout_interruptible(stat_interval * HZ);
                rcu_torture_stats_print();
-       } while (!kthread_should_stop());
+       } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
        return 0;
 }
@@ -899,7 +924,7 @@ rcu_torture_shuffle(void *arg)
        do {
                schedule_timeout_interruptible(shuffle_interval * HZ);
                rcu_torture_shuffle_tasks();
-       } while (!kthread_should_stop());
+       } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
        return 0;
 }
@@ -914,10 +939,10 @@ rcu_torture_stutter(void *arg)
        do {
                schedule_timeout_interruptible(stutter * HZ);
                stutter_pause_test = 1;
-               if (!kthread_should_stop())
+               if (!kthread_should_stop() && !fullstop)
                        schedule_timeout_interruptible(stutter * HZ);
                stutter_pause_test = 0;
-       } while (!kthread_should_stop());
+       } while (!kthread_should_stop() && !fullstop);
        VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
        return 0;
 }
@@ -934,12 +959,27 @@ rcu_torture_print_module_parms(char *tag)
                stutter, irqreader);
 }
 
+static struct notifier_block rcutorture_nb = {
+       .notifier_call = rcutorture_shutdown_notify,
+};
+
 static void
 rcu_torture_cleanup(void)
 {
        int i;
 
-       fullstop = 1;
+       mutex_lock(&fullstop_mutex);
+       if (!fullstop) {
+               /* If being signaled, let it happen, then exit. */
+               mutex_unlock(&fullstop_mutex);
+               schedule_timeout_interruptible(10 * HZ);
+               if (cur_ops->cb_barrier != NULL)
+                       cur_ops->cb_barrier();
+               return;
+       }
+       fullstop = FULLSTOP_CLEANUP;
+       mutex_unlock(&fullstop_mutex);
+       unregister_reboot_notifier(&rcutorture_nb);
        if (stutter_task) {
                VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
                kthread_stop(stutter_task);
@@ -1015,6 +1055,8 @@ rcu_torture_init(void)
                { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
                  &srcu_ops, &sched_ops, &sched_ops_sync, };
 
+       mutex_lock(&fullstop_mutex);
+
        /* Process args and tell the world that the torturer is on the job. */
        for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
                cur_ops = torture_ops[i];
@@ -1024,6 +1066,7 @@ rcu_torture_init(void)
        if (i == ARRAY_SIZE(torture_ops)) {
                printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
                       torture_type);
+               mutex_unlock(&fullstop_mutex);
                return (-EINVAL);
        }
        if (cur_ops->init)
@@ -1146,9 +1189,12 @@ rcu_torture_init(void)
                        goto unwind;
                }
        }
+       register_reboot_notifier(&rcutorture_nb);
+       mutex_unlock(&fullstop_mutex);
        return 0;
 
 unwind:
+       mutex_unlock(&fullstop_mutex);
        rcu_torture_cleanup();
        return firsterr;
 }
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
new file mode 100644 (file)
index 0000000..a342b03
--- /dev/null
@@ -0,0 +1,1535 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ *
+ * Copyright IBM Corporation, 2008
+ *
+ * Authors: Dipankar Sarma <dipankar@in.ibm.com>
+ *         Manfred Spraul <manfred@colorfullife.com>
+ *         Paul E. McKenney <paulmck@linux.vnet.ibm.com> Hierarchical version
+ *
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *     Documentation/RCU
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/time.h>
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key rcu_lock_key;
+struct lockdep_map rcu_lock_map =
+       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
+EXPORT_SYMBOL_GPL(rcu_lock_map);
+#endif
+
+/* Data structures. */
+
+#define RCU_STATE_INITIALIZER(name) { \
+       .level = { &name.node[0] }, \
+       .levelcnt = { \
+               NUM_RCU_LVL_0,  /* root of hierarchy. */ \
+               NUM_RCU_LVL_1, \
+               NUM_RCU_LVL_2, \
+               NUM_RCU_LVL_3, /* == MAX_RCU_LVLS */ \
+       }, \
+       .signaled = RCU_SIGNAL_INIT, \
+       .gpnum = -300, \
+       .completed = -300, \
+       .onofflock = __SPIN_LOCK_UNLOCKED(&name.onofflock), \
+       .fqslock = __SPIN_LOCK_UNLOCKED(&name.fqslock), \
+       .n_force_qs = 0, \
+       .n_force_qs_ngp = 0, \
+}
+
+struct rcu_state rcu_state = RCU_STATE_INITIALIZER(rcu_state);
+DEFINE_PER_CPU(struct rcu_data, rcu_data);
+
+struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state);
+DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
+
+#ifdef CONFIG_NO_HZ
+DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks);
+#endif /* #ifdef CONFIG_NO_HZ */
+
+static int blimit = 10;                /* Maximum callbacks per softirq. */
+static int qhimark = 10000;    /* If this many pending, ignore blimit. */
+static int qlowmark = 100;     /* Once only this many pending, use blimit. */
+
+static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
+
+/*
+ * Return the number of RCU batches processed thus far for debug & stats.
+ */
+long rcu_batches_completed(void)
+{
+       return rcu_state.completed;
+}
+EXPORT_SYMBOL_GPL(rcu_batches_completed);
+
+/*
+ * Return the number of RCU BH batches processed thus far for debug & stats.
+ */
+long rcu_batches_completed_bh(void)
+{
+       return rcu_bh_state.completed;
+}
+EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
+
+/*
+ * Does the CPU have callbacks ready to be invoked?
+ */
+static int
+cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp)
+{
+       return &rdp->nxtlist != rdp->nxttail[RCU_DONE_TAIL];
+}
+
+/*
+ * Does the current CPU require a yet-as-unscheduled grace period?
+ */
+static int
+cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       /* ACCESS_ONCE() because we are accessing outside of lock. */
+       return *rdp->nxttail[RCU_DONE_TAIL] &&
+              ACCESS_ONCE(rsp->completed) == ACCESS_ONCE(rsp->gpnum);
+}
+
+/*
+ * Return the root node of the specified rcu_state structure.
+ */
+static struct rcu_node *rcu_get_root(struct rcu_state *rsp)
+{
+       return &rsp->node[0];
+}
+
+#ifdef CONFIG_SMP
+
+/*
+ * If the specified CPU is offline, tell the caller that it is in
+ * a quiescent state.  Otherwise, whack it with a reschedule IPI.
+ * Grace periods can end up waiting on an offline CPU when that
+ * CPU is in the process of coming online -- it will be added to the
+ * rcu_node bitmasks before it actually makes it online.  The same thing
+ * can happen while a CPU is in the process of coming online.  Because this
+ * race is quite rare, we check for it after detecting that the grace
+ * period has been delayed rather than checking each and every CPU
+ * each and every time we start a new grace period.
+ */
+static int rcu_implicit_offline_qs(struct rcu_data *rdp)
+{
+       /*
+        * If the CPU is offline, it is in a quiescent state.  We can
+        * trust its state not to change because interrupts are disabled.
+        */
+       if (cpu_is_offline(rdp->cpu)) {
+               rdp->offline_fqs++;
+               return 1;
+       }
+
+       /* The CPU is online, so send it a reschedule IPI. */
+       if (rdp->cpu != smp_processor_id())
+               smp_send_reschedule(rdp->cpu);
+       else
+               set_need_resched();
+       rdp->resched_ipi++;
+       return 0;
+}
+
+#endif /* #ifdef CONFIG_SMP */
+
+#ifdef CONFIG_NO_HZ
+static DEFINE_RATELIMIT_STATE(rcu_rs, 10 * HZ, 5);
+
+/**
+ * rcu_enter_nohz - inform RCU that current CPU is entering nohz
+ *
+ * Enter nohz mode, in other words, -leave- the mode in which RCU
+ * read-side critical sections can occur.  (Though RCU read-side
+ * critical sections can occur in irq handlers in nohz mode, a possibility
+ * handled by rcu_irq_enter() and rcu_irq_exit()).
+ */
+void rcu_enter_nohz(void)
+{
+       unsigned long flags;
+       struct rcu_dynticks *rdtp;
+
+       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
+       local_irq_save(flags);
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       rdtp->dynticks++;
+       rdtp->dynticks_nesting--;
+       WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs);
+       local_irq_restore(flags);
+}
+
+/*
+ * rcu_exit_nohz - inform RCU that current CPU is leaving nohz
+ *
+ * Exit nohz mode, in other words, -enter- the mode in which RCU
+ * read-side critical sections normally occur.
+ */
+void rcu_exit_nohz(void)
+{
+       unsigned long flags;
+       struct rcu_dynticks *rdtp;
+
+       local_irq_save(flags);
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       rdtp->dynticks++;
+       rdtp->dynticks_nesting++;
+       WARN_ON_RATELIMIT(!(rdtp->dynticks & 0x1), &rcu_rs);
+       local_irq_restore(flags);
+       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+}
+
+/**
+ * rcu_nmi_enter - inform RCU of entry to NMI context
+ *
+ * If the CPU was idle with dynamic ticks active, and there is no
+ * irq handler running, this updates rdtp->dynticks_nmi to let the
+ * RCU grace-period handling know that the CPU is active.
+ */
+void rcu_nmi_enter(void)
+{
+       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
+
+       if (rdtp->dynticks & 0x1)
+               return;
+       rdtp->dynticks_nmi++;
+       WARN_ON_RATELIMIT(!(rdtp->dynticks_nmi & 0x1), &rcu_rs);
+       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+}
+
+/**
+ * rcu_nmi_exit - inform RCU of exit from NMI context
+ *
+ * If the CPU was idle with dynamic ticks active, and there is no
+ * irq handler running, this updates rdtp->dynticks_nmi to let the
+ * RCU grace-period handling know that the CPU is no longer active.
+ */
+void rcu_nmi_exit(void)
+{
+       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
+
+       if (rdtp->dynticks & 0x1)
+               return;
+       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
+       rdtp->dynticks_nmi++;
+       WARN_ON_RATELIMIT(rdtp->dynticks_nmi & 0x1, &rcu_rs);
+}
+
+/**
+ * rcu_irq_enter - inform RCU of entry to hard irq context
+ *
+ * If the CPU was idle with dynamic ticks active, this updates the
+ * rdtp->dynticks to let the RCU handling know that the CPU is active.
+ */
+void rcu_irq_enter(void)
+{
+       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
+
+       if (rdtp->dynticks_nesting++)
+               return;
+       rdtp->dynticks++;
+       WARN_ON_RATELIMIT(!(rdtp->dynticks & 0x1), &rcu_rs);
+       smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
+}
+
+/**
+ * rcu_irq_exit - inform RCU of exit from hard irq context
+ *
+ * If the CPU was idle with dynamic ticks active, update the rdp->dynticks
+ * to put let the RCU handling be aware that the CPU is going back to idle
+ * with no ticks.
+ */
+void rcu_irq_exit(void)
+{
+       struct rcu_dynticks *rdtp = &__get_cpu_var(rcu_dynticks);
+
+       if (--rdtp->dynticks_nesting)
+               return;
+       smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
+       rdtp->dynticks++;
+       WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs);
+
+       /* If the interrupt queued a callback, get out of dyntick mode. */
+       if (__get_cpu_var(rcu_data).nxtlist ||
+           __get_cpu_var(rcu_bh_data).nxtlist)
+               set_need_resched();
+}
+
+/*
+ * Record the specified "completed" value, which is later used to validate
+ * dynticks counter manipulations.  Specify "rsp->completed - 1" to
+ * unconditionally invalidate any future dynticks manipulations (which is
+ * useful at the beginning of a grace period).
+ */
+static void dyntick_record_completed(struct rcu_state *rsp, long comp)
+{
+       rsp->dynticks_completed = comp;
+}
+
+#ifdef CONFIG_SMP
+
+/*
+ * Recall the previously recorded value of the completion for dynticks.
+ */
+static long dyntick_recall_completed(struct rcu_state *rsp)
+{
+       return rsp->dynticks_completed;
+}
+
+/*
+ * Snapshot the specified CPU's dynticks counter so that we can later
+ * credit them with an implicit quiescent state.  Return 1 if this CPU
+ * is already in a quiescent state courtesy of dynticks idle mode.
+ */
+static int dyntick_save_progress_counter(struct rcu_data *rdp)
+{
+       int ret;
+       int snap;
+       int snap_nmi;
+
+       snap = rdp->dynticks->dynticks;
+       snap_nmi = rdp->dynticks->dynticks_nmi;
+       smp_mb();       /* Order sampling of snap with end of grace period. */
+       rdp->dynticks_snap = snap;
+       rdp->dynticks_nmi_snap = snap_nmi;
+       ret = ((snap & 0x1) == 0) && ((snap_nmi & 0x1) == 0);
+       if (ret)
+               rdp->dynticks_fqs++;
+       return ret;
+}
+
+/*
+ * Return true if the specified CPU has passed through a quiescent
+ * state by virtue of being in or having passed through an dynticks
+ * idle state since the last call to dyntick_save_progress_counter()
+ * for this same CPU.
+ */
+static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
+{
+       long curr;
+       long curr_nmi;
+       long snap;
+       long snap_nmi;
+
+       curr = rdp->dynticks->dynticks;
+       snap = rdp->dynticks_snap;
+       curr_nmi = rdp->dynticks->dynticks_nmi;
+       snap_nmi = rdp->dynticks_nmi_snap;
+       smp_mb(); /* force ordering with cpu entering/leaving dynticks. */
+
+       /*
+        * If the CPU passed through or entered a dynticks idle phase with
+        * no active irq/NMI handlers, then we can safely pretend that the CPU
+        * already acknowledged the request to pass through a quiescent
+        * state.  Either way, that CPU cannot possibly be in an RCU
+        * read-side critical section that started before the beginning
+        * of the current RCU grace period.
+        */
+       if ((curr != snap || (curr & 0x1) == 0) &&
+           (curr_nmi != snap_nmi || (curr_nmi & 0x1) == 0)) {
+               rdp->dynticks_fqs++;
+               return 1;
+       }
+
+       /* Go check for the CPU being offline. */
+       return rcu_implicit_offline_qs(rdp);
+}
+
+#endif /* #ifdef CONFIG_SMP */
+
+#else /* #ifdef CONFIG_NO_HZ */
+
+static void dyntick_record_completed(struct rcu_state *rsp, long comp)
+{
+}
+
+#ifdef CONFIG_SMP
+
+/*
+ * If there are no dynticks, then the only way that a CPU can passively
+ * be in a quiescent state is to be offline.  Unlike dynticks idle, which
+ * is a point in time during the prior (already finished) grace period,
+ * an offline CPU is always in a quiescent state, and thus can be
+ * unconditionally applied.  So just return the current value of completed.
+ */
+static long dyntick_recall_completed(struct rcu_state *rsp)
+{
+       return rsp->completed;
+}
+
+static int dyntick_save_progress_counter(struct rcu_data *rdp)
+{
+       return 0;
+}
+
+static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
+{
+       return rcu_implicit_offline_qs(rdp);
+}
+
+#endif /* #ifdef CONFIG_SMP */
+
+#endif /* #else #ifdef CONFIG_NO_HZ */
+
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+
+static void record_gp_stall_check_time(struct rcu_state *rsp)
+{
+       rsp->gp_start = jiffies;
+       rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_CHECK;
+}
+
+static void print_other_cpu_stall(struct rcu_state *rsp)
+{
+       int cpu;
+       long delta;
+       unsigned long flags;
+       struct rcu_node *rnp = rcu_get_root(rsp);
+       struct rcu_node *rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
+       struct rcu_node *rnp_end = &rsp->node[NUM_RCU_NODES];
+
+       /* Only let one CPU complain about others per time interval. */
+
+       spin_lock_irqsave(&rnp->lock, flags);
+       delta = jiffies - rsp->jiffies_stall;
+       if (delta < RCU_STALL_RAT_DELAY || rsp->gpnum == rsp->completed) {
+               spin_unlock_irqrestore(&rnp->lock, flags);
+               return;
+       }
+       rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
+       spin_unlock_irqrestore(&rnp->lock, flags);
+
+       /* OK, time to rat on our buddy... */
+
+       printk(KERN_ERR "INFO: RCU detected CPU stalls:");
+       for (; rnp_cur < rnp_end; rnp_cur++) {
+               if (rnp_cur->qsmask == 0)
+                       continue;
+               for (cpu = 0; cpu <= rnp_cur->grphi - rnp_cur->grplo; cpu++)
+                       if (rnp_cur->qsmask & (1UL << cpu))
+                               printk(" %d", rnp_cur->grplo + cpu);
+       }
+       printk(" (detected by %d, t=%ld jiffies)\n",
+              smp_processor_id(), (long)(jiffies - rsp->gp_start));
+       force_quiescent_state(rsp, 0);  /* Kick them all. */
+}
+
+static void print_cpu_stall(struct rcu_state *rsp)
+{
+       unsigned long flags;
+       struct rcu_node *rnp = rcu_get_root(rsp);
+
+       printk(KERN_ERR "INFO: RCU detected CPU %d stall (t=%lu jiffies)\n",
+                       smp_processor_id(), jiffies - rsp->gp_start);
+       dump_stack();
+       spin_lock_irqsave(&rnp->lock, flags);
+       if ((long)(jiffies - rsp->jiffies_stall) >= 0)
+               rsp->jiffies_stall =
+                       jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
+       spin_unlock_irqrestore(&rnp->lock, flags);
+       set_need_resched();  /* kick ourselves to get things going. */
+}
+
+static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       long delta;
+       struct rcu_node *rnp;
+
+       delta = jiffies - rsp->jiffies_stall;
+       rnp = rdp->mynode;
+       if ((rnp->qsmask & rdp->grpmask) && delta >= 0) {
+
+               /* We haven't checked in, so go dump stack. */
+               print_cpu_stall(rsp);
+
+       } else if (rsp->gpnum != rsp->completed &&
+                  delta >= RCU_STALL_RAT_DELAY) {
+
+               /* They had two time units to dump stack, so complain. */
+               print_other_cpu_stall(rsp);
+       }
+}
+
+#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+
+static void record_gp_stall_check_time(struct rcu_state *rsp)
+{
+}
+
+static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+}
+
+#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+
+/*
+ * Update CPU-local rcu_data state to record the newly noticed grace period.
+ * This is used both when we started the grace period and when we notice
+ * that someone else started the grace period.
+ */
+static void note_new_gpnum(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       rdp->qs_pending = 1;
+       rdp->passed_quiesc = 0;
+       rdp->gpnum = rsp->gpnum;
+       rdp->n_rcu_pending_force_qs = rdp->n_rcu_pending +
+                                     RCU_JIFFIES_TILL_FORCE_QS;
+}
+
+/*
+ * Did someone else start a new RCU grace period start since we last
+ * checked?  Update local state appropriately if so.  Must be called
+ * on the CPU corresponding to rdp.
+ */
+static int
+check_for_new_grace_period(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       local_irq_save(flags);
+       if (rdp->gpnum != rsp->gpnum) {
+               note_new_gpnum(rsp, rdp);
+               ret = 1;
+       }
+       local_irq_restore(flags);
+       return ret;
+}
+
+/*
+ * Start a new RCU grace period if warranted, re-initializing the hierarchy
+ * in preparation for detecting the next grace period.  The caller must hold
+ * the root node's ->lock, which is released before return.  Hard irqs must
+ * be disabled.
+ */
+static void
+rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
+       __releases(rcu_get_root(rsp)->lock)
+{
+       struct rcu_data *rdp = rsp->rda[smp_processor_id()];
+       struct rcu_node *rnp = rcu_get_root(rsp);
+       struct rcu_node *rnp_cur;
+       struct rcu_node *rnp_end;
+
+       if (!cpu_needs_another_gp(rsp, rdp)) {
+               spin_unlock_irqrestore(&rnp->lock, flags);
+               return;
+       }
+
+       /* Advance to a new grace period and initialize state. */
+       rsp->gpnum++;
+       rsp->signaled = RCU_GP_INIT; /* Hold off force_quiescent_state. */
+       rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
+       rdp->n_rcu_pending_force_qs = rdp->n_rcu_pending +
+                                     RCU_JIFFIES_TILL_FORCE_QS;
+       record_gp_stall_check_time(rsp);
+       dyntick_record_completed(rsp, rsp->completed - 1);
+       note_new_gpnum(rsp, rdp);
+
+       /*
+        * Because we are first, we know that all our callbacks will
+        * be covered by this upcoming grace period, even the ones
+        * that were registered arbitrarily recently.
+        */
+       rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+       rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+
+       /* Special-case the common single-level case. */
+       if (NUM_RCU_NODES == 1) {
+               rnp->qsmask = rnp->qsmaskinit;
+               spin_unlock_irqrestore(&rnp->lock, flags);
+               return;
+       }
+
+       spin_unlock(&rnp->lock);  /* leave irqs disabled. */
+
+
+       /* Exclude any concurrent CPU-hotplug operations. */
+       spin_lock(&rsp->onofflock);  /* irqs already disabled. */
+
+       /*
+        * Set the quiescent-state-needed bits in all the non-leaf RCU
+        * nodes for all currently online CPUs.  This operation relies
+        * on the layout of the hierarchy within the rsp->node[] array.
+        * Note that other CPUs will access only the leaves of the
+        * hierarchy, which still indicate that no grace period is in
+        * progress.  In addition, we have excluded CPU-hotplug operations.
+        *
+        * We therefore do not need to hold any locks.  Any required
+        * memory barriers will be supplied by the locks guarding the
+        * leaf rcu_nodes in the hierarchy.
+        */
+
+       rnp_end = rsp->level[NUM_RCU_LVLS - 1];
+       for (rnp_cur = &rsp->node[0]; rnp_cur < rnp_end; rnp_cur++)
+               rnp_cur->qsmask = rnp_cur->qsmaskinit;
+
+       /*
+        * Now set up the leaf nodes.  Here we must be careful.  First,
+        * we need to hold the lock in order to exclude other CPUs, which
+        * might be contending for the leaf nodes' locks.  Second, as
+        * soon as we initialize a given leaf node, its CPUs might run
+        * up the rest of the hierarchy.  We must therefore acquire locks
+        * for each node that we touch during this stage.  (But we still
+        * are excluding CPU-hotplug operations.)
+        *
+        * Note that the grace period cannot complete until we finish
+        * the initialization process, as there will be at least one
+        * qsmask bit set in the root node until that time, namely the
+        * one corresponding to this CPU.
+        */
+       rnp_end = &rsp->node[NUM_RCU_NODES];
+       rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
+       for (; rnp_cur < rnp_end; rnp_cur++) {
+               spin_lock(&rnp_cur->lock);      /* irqs already disabled. */
+               rnp_cur->qsmask = rnp_cur->qsmaskinit;
+               spin_unlock(&rnp_cur->lock);    /* irqs already disabled. */
+       }
+
+       rsp->signaled = RCU_SIGNAL_INIT; /* force_quiescent_state now OK. */
+       spin_unlock_irqrestore(&rsp->onofflock, flags);
+}
+
+/*
+ * Advance this CPU's callbacks, but only if the current grace period
+ * has ended.  This may be called only from the CPU to whom the rdp
+ * belongs.
+ */
+static void
+rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       long completed_snap;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       completed_snap = ACCESS_ONCE(rsp->completed);  /* outside of lock. */
+
+       /* Did another grace period end? */
+       if (rdp->completed != completed_snap) {
+
+               /* Advance callbacks.  No harm if list empty. */
+               rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL];
+               rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL];
+               rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+
+               /* Remember that we saw this grace-period completion. */
+               rdp->completed = completed_snap;
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * Similar to cpu_quiet(), for which it is a helper function.  Allows
+ * a group of CPUs to be quieted at one go, though all the CPUs in the
+ * group must be represented by the same leaf rcu_node structure.
+ * That structure's lock must be held upon entry, and it is released
+ * before return.
+ */
+static void
+cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp, struct rcu_node *rnp,
+             unsigned long flags)
+       __releases(rnp->lock)
+{
+       /* Walk up the rcu_node hierarchy. */
+       for (;;) {
+               if (!(rnp->qsmask & mask)) {
+
+                       /* Our bit has already been cleared, so done. */
+                       spin_unlock_irqrestore(&rnp->lock, flags);
+                       return;
+               }
+               rnp->qsmask &= ~mask;
+               if (rnp->qsmask != 0) {
+
+                       /* Other bits still set at this level, so done. */
+                       spin_unlock_irqrestore(&rnp->lock, flags);
+                       return;
+               }
+               mask = rnp->grpmask;
+               if (rnp->parent == NULL) {
+
+                       /* No more levels.  Exit loop holding root lock. */
+
+                       break;
+               }
+               spin_unlock_irqrestore(&rnp->lock, flags);
+               rnp = rnp->parent;
+               spin_lock_irqsave(&rnp->lock, flags);
+       }
+
+       /*
+        * Get here if we are the last CPU to pass through a quiescent
+        * state for this grace period.  Clean up and let rcu_start_gp()
+        * start up the next grace period if one is needed.  Note that
+        * we still hold rnp->lock, as required by rcu_start_gp(), which
+        * will release it.
+        */
+       rsp->completed = rsp->gpnum;
+       rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]);
+       rcu_start_gp(rsp, flags);  /* releases rnp->lock. */
+}
+
+/*
+ * Record a quiescent state for the specified CPU, which must either be
+ * the current CPU or an offline CPU.  The lastcomp argument is used to
+ * make sure we are still in the grace period of interest.  We don't want
+ * to end the current grace period based on quiescent states detected in
+ * an earlier grace period!
+ */
+static void
+cpu_quiet(int cpu, struct rcu_state *rsp, struct rcu_data *rdp, long lastcomp)
+{
+       unsigned long flags;
+       unsigned long mask;
+       struct rcu_node *rnp;
+
+       rnp = rdp->mynode;
+       spin_lock_irqsave(&rnp->lock, flags);
+       if (lastcomp != ACCESS_ONCE(rsp->completed)) {
+
+               /*
+                * Someone beat us to it for this grace period, so leave.
+                * The race with GP start is resolved by the fact that we
+                * hold the leaf rcu_node lock, so that the per-CPU bits
+                * cannot yet be initialized -- so we would simply find our
+                * CPU's bit already cleared in cpu_quiet_msk() if this race
+                * occurred.
+                */
+               rdp->passed_quiesc = 0; /* try again later! */
+               spin_unlock_irqrestore(&rnp->lock, flags);
+               return;
+       }
+       mask = rdp->grpmask;
+       if ((rnp->qsmask & mask) == 0) {
+               spin_unlock_irqrestore(&rnp->lock, flags);
+       } else {
+               rdp->qs_pending = 0;
+
+               /*
+                * This GP can't end until cpu checks in, so all of our
+                * callbacks can be processed during the next GP.
+                */
+               rdp = rsp->rda[smp_processor_id()];
+               rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+
+               cpu_quiet_msk(mask, rsp, rnp, flags); /* releases rnp->lock */
+       }
+}
+
+/*
+ * Check to see if there is a new grace period of which this CPU
+ * is not yet aware, and if so, set up local rcu_data state for it.
+ * Otherwise, see if this CPU has just passed through its first
+ * quiescent state for this grace period, and record that fact if so.
+ */
+static void
+rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       /* If there is now a new grace period, record and return. */
+       if (check_for_new_grace_period(rsp, rdp))
+               return;
+
+       /*
+        * Does this CPU still need to do its part for current grace period?
+        * If no, return and let the other CPUs do their part as well.
+        */
+       if (!rdp->qs_pending)
+               return;
+
+       /*
+        * Was there a quiescent state since the beginning of the grace
+        * period? If no, then exit and wait for the next call.
+        */
+       if (!rdp->passed_quiesc)
+               return;
+
+       /* Tell RCU we are done (but cpu_quiet() will be the judge of that). */
+       cpu_quiet(rdp->cpu, rsp, rdp, rdp->passed_quiesc_completed);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+/*
+ * Remove the outgoing CPU from the bitmasks in the rcu_node hierarchy
+ * and move all callbacks from the outgoing CPU to the current one.
+ */
+static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
+{
+       int i;
+       unsigned long flags;
+       long lastcomp;
+       unsigned long mask;
+       struct rcu_data *rdp = rsp->rda[cpu];
+       struct rcu_data *rdp_me;
+       struct rcu_node *rnp;
+
+       /* Exclude any attempts to start a new grace period. */
+       spin_lock_irqsave(&rsp->onofflock, flags);
+
+       /* Remove the outgoing CPU from the masks in the rcu_node hierarchy. */
+       rnp = rdp->mynode;
+       mask = rdp->grpmask;    /* rnp->grplo is constant. */
+       do {
+               spin_lock(&rnp->lock);          /* irqs already disabled. */
+               rnp->qsmaskinit &= ~mask;
+               if (rnp->qsmaskinit != 0) {
+                       spin_unlock(&rnp->lock); /* irqs already disabled. */
+                       break;
+               }
+               mask = rnp->grpmask;
+               spin_unlock(&rnp->lock);        /* irqs already disabled. */
+               rnp = rnp->parent;
+       } while (rnp != NULL);
+       lastcomp = rsp->completed;
+
+       spin_unlock(&rsp->onofflock);           /* irqs remain disabled. */
+
+       /* Being offline is a quiescent state, so go record it. */
+       cpu_quiet(cpu, rsp, rdp, lastcomp);
+
+       /*
+        * Move callbacks from the outgoing CPU to the running CPU.
+        * Note that the outgoing CPU is now quiscent, so it is now
+        * (uncharacteristically) safe to access it rcu_data structure.
+        * Note also that we must carefully retain the order of the
+        * outgoing CPU's callbacks in order for rcu_barrier() to work
+        * correctly.  Finally, note that we start all the callbacks
+        * afresh, even those that have passed through a grace period
+        * and are therefore ready to invoke.  The theory is that hotplug
+        * events are rare, and that if they are frequent enough to
+        * indefinitely delay callbacks, you have far worse things to
+        * be worrying about.
+        */
+       rdp_me = rsp->rda[smp_processor_id()];
+       if (rdp->nxtlist != NULL) {
+               *rdp_me->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist;
+               rdp_me->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+               rdp->nxtlist = NULL;
+               for (i = 0; i < RCU_NEXT_SIZE; i++)
+                       rdp->nxttail[i] = &rdp->nxtlist;
+               rdp_me->qlen += rdp->qlen;
+               rdp->qlen = 0;
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * Remove the specified CPU from the RCU hierarchy and move any pending
+ * callbacks that it might have to the current CPU.  This code assumes
+ * that at least one CPU in the system will remain running at all times.
+ * Any attempt to offline -all- CPUs is likely to strand RCU callbacks.
+ */
+static void rcu_offline_cpu(int cpu)
+{
+       __rcu_offline_cpu(cpu, &rcu_state);
+       __rcu_offline_cpu(cpu, &rcu_bh_state);
+}
+
+#else /* #ifdef CONFIG_HOTPLUG_CPU */
+
+static void rcu_offline_cpu(int cpu)
+{
+}
+
+#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */
+
+/*
+ * Invoke any RCU callbacks that have made it to the end of their grace
+ * period.  Thottle as specified by rdp->blimit.
+ */
+static void rcu_do_batch(struct rcu_data *rdp)
+{
+       unsigned long flags;
+       struct rcu_head *next, *list, **tail;
+       int count;
+
+       /* If no callbacks are ready, just return.*/
+       if (!cpu_has_callbacks_ready_to_invoke(rdp))
+               return;
+
+       /*
+        * Extract the list of ready callbacks, disabling to prevent
+        * races with call_rcu() from interrupt handlers.
+        */
+       local_irq_save(flags);
+       list = rdp->nxtlist;
+       rdp->nxtlist = *rdp->nxttail[RCU_DONE_TAIL];
+       *rdp->nxttail[RCU_DONE_TAIL] = NULL;
+       tail = rdp->nxttail[RCU_DONE_TAIL];
+       for (count = RCU_NEXT_SIZE - 1; count >= 0; count--)
+               if (rdp->nxttail[count] == rdp->nxttail[RCU_DONE_TAIL])
+                       rdp->nxttail[count] = &rdp->nxtlist;
+       local_irq_restore(flags);
+
+       /* Invoke callbacks. */
+       count = 0;
+       while (list) {
+               next = list->next;
+               prefetch(next);
+               list->func(list);
+               list = next;
+               if (++count >= rdp->blimit)
+                       break;
+       }
+
+       local_irq_save(flags);
+
+       /* Update count, and requeue any remaining callbacks. */
+       rdp->qlen -= count;
+       if (list != NULL) {
+               *tail = rdp->nxtlist;
+               rdp->nxtlist = list;
+               for (count = 0; count < RCU_NEXT_SIZE; count++)
+                       if (&rdp->nxtlist == rdp->nxttail[count])
+                               rdp->nxttail[count] = tail;
+                       else
+                               break;
+       }
+
+       /* Reinstate batch limit if we have worked down the excess. */
+       if (rdp->blimit == LONG_MAX && rdp->qlen <= qlowmark)
+               rdp->blimit = blimit;
+
+       local_irq_restore(flags);
+
+       /* Re-raise the RCU softirq if there are callbacks remaining. */
+       if (cpu_has_callbacks_ready_to_invoke(rdp))
+               raise_softirq(RCU_SOFTIRQ);
+}
+
+/*
+ * Check to see if this CPU is in a non-context-switch quiescent state
+ * (user mode or idle loop for rcu, non-softirq execution for rcu_bh).
+ * Also schedule the RCU softirq handler.
+ *
+ * This function must be called with hardirqs disabled.  It is normally
+ * invoked from the scheduling-clock interrupt.  If rcu_pending returns
+ * false, there is no point in invoking rcu_check_callbacks().
+ */
+void rcu_check_callbacks(int cpu, int user)
+{
+       if (user ||
+           (idle_cpu(cpu) && !in_softirq() &&
+                               hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
+
+               /*
+                * Get here if this CPU took its interrupt from user
+                * mode or from the idle loop, and if this is not a
+                * nested interrupt.  In this case, the CPU is in
+                * a quiescent state, so count it.
+                *
+                * No memory barrier is required here because both
+                * rcu_qsctr_inc() and rcu_bh_qsctr_inc() reference
+                * only CPU-local variables that other CPUs neither
+                * access nor modify, at least not while the corresponding
+                * CPU is online.
+                */
+
+               rcu_qsctr_inc(cpu);
+               rcu_bh_qsctr_inc(cpu);
+
+       } else if (!in_softirq()) {
+
+               /*
+                * Get here if this CPU did not take its interrupt from
+                * softirq, in other words, if it is not interrupting
+                * a rcu_bh read-side critical section.  This is an _bh
+                * critical section, so count it.
+                */
+
+               rcu_bh_qsctr_inc(cpu);
+       }
+       raise_softirq(RCU_SOFTIRQ);
+}
+
+#ifdef CONFIG_SMP
+
+/*
+ * Scan the leaf rcu_node structures, processing dyntick state for any that
+ * have not yet encountered a quiescent state, using the function specified.
+ * Returns 1 if the current grace period ends while scanning (possibly
+ * because we made it end).
+ */
+static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,
+                              int (*f)(struct rcu_data *))
+{
+       unsigned long bit;
+       int cpu;
+       unsigned long flags;
+       unsigned long mask;
+       struct rcu_node *rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
+       struct rcu_node *rnp_end = &rsp->node[NUM_RCU_NODES];
+
+       for (; rnp_cur < rnp_end; rnp_cur++) {
+               mask = 0;
+               spin_lock_irqsave(&rnp_cur->lock, flags);
+               if (rsp->completed != lastcomp) {
+                       spin_unlock_irqrestore(&rnp_cur->lock, flags);
+                       return 1;
+               }
+               if (rnp_cur->qsmask == 0) {
+                       spin_unlock_irqrestore(&rnp_cur->lock, flags);
+                       continue;
+               }
+               cpu = rnp_cur->grplo;
+               bit = 1;
+               for (; cpu <= rnp_cur->grphi; cpu++, bit <<= 1) {
+                       if ((rnp_cur->qsmask & bit) != 0 && f(rsp->rda[cpu]))
+                               mask |= bit;
+               }
+               if (mask != 0 && rsp->completed == lastcomp) {
+
+                       /* cpu_quiet_msk() releases rnp_cur->lock. */
+                       cpu_quiet_msk(mask, rsp, rnp_cur, flags);
+                       continue;
+               }
+               spin_unlock_irqrestore(&rnp_cur->lock, flags);
+       }
+       return 0;
+}
+
+/*
+ * Force quiescent states on reluctant CPUs, and also detect which
+ * CPUs are in dyntick-idle mode.
+ */
+static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
+{
+       unsigned long flags;
+       long lastcomp;
+       struct rcu_data *rdp = rsp->rda[smp_processor_id()];
+       struct rcu_node *rnp = rcu_get_root(rsp);
+       u8 signaled;
+
+       if (ACCESS_ONCE(rsp->completed) == ACCESS_ONCE(rsp->gpnum))
+               return;  /* No grace period in progress, nothing to force. */
+       if (!spin_trylock_irqsave(&rsp->fqslock, flags)) {
+               rsp->n_force_qs_lh++; /* Inexact, can lose counts.  Tough! */
+               return; /* Someone else is already on the job. */
+       }
+       if (relaxed &&
+           (long)(rsp->jiffies_force_qs - jiffies) >= 0 &&
+           (rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending) >= 0)
+               goto unlock_ret; /* no emergency and done recently. */
+       rsp->n_force_qs++;
+       spin_lock(&rnp->lock);
+       lastcomp = rsp->completed;
+       signaled = rsp->signaled;
+       rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
+       rdp->n_rcu_pending_force_qs = rdp->n_rcu_pending +
+                                     RCU_JIFFIES_TILL_FORCE_QS;
+       if (lastcomp == rsp->gpnum) {
+               rsp->n_force_qs_ngp++;
+               spin_unlock(&rnp->lock);
+               goto unlock_ret;  /* no GP in progress, time updated. */
+       }
+       spin_unlock(&rnp->lock);
+       switch (signaled) {
+       case RCU_GP_INIT:
+
+               break; /* grace period still initializing, ignore. */
+
+       case RCU_SAVE_DYNTICK:
+
+               if (RCU_SIGNAL_INIT != RCU_SAVE_DYNTICK)
+                       break; /* So gcc recognizes the dead code. */
+
+               /* Record dyntick-idle state. */
+               if (rcu_process_dyntick(rsp, lastcomp,
+                                       dyntick_save_progress_counter))
+                       goto unlock_ret;
+
+               /* Update state, record completion counter. */
+               spin_lock(&rnp->lock);
+               if (lastcomp == rsp->completed) {
+                       rsp->signaled = RCU_FORCE_QS;
+                       dyntick_record_completed(rsp, lastcomp);
+               }
+               spin_unlock(&rnp->lock);
+               break;
+
+       case RCU_FORCE_QS:
+
+               /* Check dyntick-idle state, send IPI to laggarts. */
+               if (rcu_process_dyntick(rsp, dyntick_recall_completed(rsp),
+                                       rcu_implicit_dynticks_qs))
+                       goto unlock_ret;
+
+               /* Leave state in case more forcing is required. */
+
+               break;
+       }
+unlock_ret:
+       spin_unlock_irqrestore(&rsp->fqslock, flags);
+}
+
+#else /* #ifdef CONFIG_SMP */
+
+static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
+{
+       set_need_resched();
+}
+
+#endif /* #else #ifdef CONFIG_SMP */
+
+/*
+ * This does the RCU processing work from softirq context for the
+ * specified rcu_state and rcu_data structures.  This may be called
+ * only from the CPU to whom the rdp belongs.
+ */
+static void
+__rcu_process_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       unsigned long flags;
+
+       /*
+        * If an RCU GP has gone long enough, go check for dyntick
+        * idle CPUs and, if needed, send resched IPIs.
+        */
+       if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0 ||
+           (rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending) < 0)
+               force_quiescent_state(rsp, 1);
+
+       /*
+        * Advance callbacks in response to end of earlier grace
+        * period that some other CPU ended.
+        */
+       rcu_process_gp_end(rsp, rdp);
+
+       /* Update RCU state based on any recent quiescent states. */
+       rcu_check_quiescent_state(rsp, rdp);
+
+       /* Does this CPU require a not-yet-started grace period? */
+       if (cpu_needs_another_gp(rsp, rdp)) {
+               spin_lock_irqsave(&rcu_get_root(rsp)->lock, flags);
+               rcu_start_gp(rsp, flags);  /* releases above lock */
+       }
+
+       /* If there are callbacks ready, invoke them. */
+       rcu_do_batch(rdp);
+}
+
+/*
+ * Do softirq processing for the current CPU.
+ */
+static void rcu_process_callbacks(struct softirq_action *unused)
+{
+       /*
+        * Memory references from any prior RCU read-side critical sections
+        * executed by the interrupted code must be seen before any RCU
+        * grace-period manipulations below.
+        */
+       smp_mb(); /* See above block comment. */
+
+       __rcu_process_callbacks(&rcu_state, &__get_cpu_var(rcu_data));
+       __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data));
+
+       /*
+        * Memory references from any later RCU read-side critical sections
+        * executed by the interrupted code must be seen after any RCU
+        * grace-period manipulations above.
+        */
+       smp_mb(); /* See above block comment. */
+}
+
+static void
+__call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
+          struct rcu_state *rsp)
+{
+       unsigned long flags;
+       struct rcu_data *rdp;
+
+       head->func = func;
+       head->next = NULL;
+
+       smp_mb(); /* Ensure RCU update seen before callback registry. */
+
+       /*
+        * Opportunistically note grace-period endings and beginnings.
+        * Note that we might see a beginning right after we see an
+        * end, but never vice versa, since this CPU has to pass through
+        * a quiescent state betweentimes.
+        */
+       local_irq_save(flags);
+       rdp = rsp->rda[smp_processor_id()];
+       rcu_process_gp_end(rsp, rdp);
+       check_for_new_grace_period(rsp, rdp);
+
+       /* Add the callback to our list. */
+       *rdp->nxttail[RCU_NEXT_TAIL] = head;
+       rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
+
+       /* Start a new grace period if one not already started. */
+       if (ACCESS_ONCE(rsp->completed) == ACCESS_ONCE(rsp->gpnum)) {
+               unsigned long nestflag;
+               struct rcu_node *rnp_root = rcu_get_root(rsp);
+
+               spin_lock_irqsave(&rnp_root->lock, nestflag);
+               rcu_start_gp(rsp, nestflag);  /* releases rnp_root->lock. */
+       }
+
+       /* Force the grace period if too many callbacks or too long waiting. */
+       if (unlikely(++rdp->qlen > qhimark)) {
+               rdp->blimit = LONG_MAX;
+               force_quiescent_state(rsp, 0);
+       } else if ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0 ||
+                  (rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending) < 0)
+               force_quiescent_state(rsp, 1);
+       local_irq_restore(flags);
+}
+
+/*
+ * Queue an RCU callback for invocation after a grace period.
+ */
+void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+       __call_rcu(head, func, &rcu_state);
+}
+EXPORT_SYMBOL_GPL(call_rcu);
+
+/*
+ * Queue an RCU for invocation after a quicker grace period.
+ */
+void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+       __call_rcu(head, func, &rcu_bh_state);
+}
+EXPORT_SYMBOL_GPL(call_rcu_bh);
+
+/*
+ * Check to see if there is any immediate RCU-related work to be done
+ * by the current CPU, for the specified type of RCU, returning 1 if so.
+ * The checks are in order of increasing expense: checks that can be
+ * carried out against CPU-local state are performed first.  However,
+ * we must check for CPU stalls first, else we might not get a chance.
+ */
+static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
+{
+       rdp->n_rcu_pending++;
+
+       /* Check for CPU stalls, if enabled. */
+       check_cpu_stall(rsp, rdp);
+
+       /* Is the RCU core waiting for a quiescent state from this CPU? */
+       if (rdp->qs_pending)
+               return 1;
+
+       /* Does this CPU have callbacks ready to invoke? */
+       if (cpu_has_callbacks_ready_to_invoke(rdp))
+               return 1;
+
+       /* Has RCU gone idle with this CPU needing another grace period? */
+       if (cpu_needs_another_gp(rsp, rdp))
+               return 1;
+
+       /* Has another RCU grace period completed?  */
+       if (ACCESS_ONCE(rsp->completed) != rdp->completed) /* outside of lock */
+               return 1;
+
+       /* Has a new RCU grace period started? */
+       if (ACCESS_ONCE(rsp->gpnum) != rdp->gpnum) /* outside of lock */
+               return 1;
+
+       /* Has an RCU GP gone long enough to send resched IPIs &c? */
+       if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) &&
+           ((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0 ||
+            (rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending) < 0))
+               return 1;
+
+       /* nothing to do */
+       return 0;
+}
+
+/*
+ * Check to see if there is any immediate RCU-related work to be done
+ * by the current CPU, returning 1 if so.  This function is part of the
+ * RCU implementation; it is -not- an exported member of the RCU API.
+ */
+int rcu_pending(int cpu)
+{
+       return __rcu_pending(&rcu_state, &per_cpu(rcu_data, cpu)) ||
+              __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu));
+}
+
+/*
+ * Check to see if any future RCU-related work will need to be done
+ * by the current CPU, even if none need be done immediately, returning
+ * 1 if so.  This function is part of the RCU implementation; it is -not-
+ * an exported member of the RCU API.
+ */
+int rcu_needs_cpu(int cpu)
+{
+       /* RCU callbacks either ready or pending? */
+       return per_cpu(rcu_data, cpu).nxtlist ||
+              per_cpu(rcu_bh_data, cpu).nxtlist;
+}
+
+/*
+ * Initialize a CPU's per-CPU RCU data.  We take this "scorched earth"
+ * approach so that we don't have to worry about how long the CPU has
+ * been gone, or whether it ever was online previously.  We do trust the
+ * ->mynode field, as it is constant for a given struct rcu_data and
+ * initialized during early boot.
+ *
+ * Note that only one online or offline event can be happening at a given
+ * time.  Note also that we can accept some slop in the rsp->completed
+ * access due to the fact that this CPU cannot possibly have any RCU
+ * callbacks in flight yet.
+ */
+static void
+rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
+{
+       unsigned long flags;
+       int i;
+       long lastcomp;
+       unsigned long mask;
+       struct rcu_data *rdp = rsp->rda[cpu];
+       struct rcu_node *rnp = rcu_get_root(rsp);
+
+       /* Set up local state, ensuring consistent view of global state. */
+       spin_lock_irqsave(&rnp->lock, flags);
+       lastcomp = rsp->completed;
+       rdp->completed = lastcomp;
+       rdp->gpnum = lastcomp;
+       rdp->passed_quiesc = 0;  /* We could be racing with new GP, */
+       rdp->qs_pending = 1;     /*  so set up to respond to current GP. */
+       rdp->beenonline = 1;     /* We have now been online. */
+       rdp->passed_quiesc_completed = lastcomp - 1;
+       rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
+       rdp->nxtlist = NULL;
+       for (i = 0; i < RCU_NEXT_SIZE; i++)
+               rdp->nxttail[i] = &rdp->nxtlist;
+       rdp->qlen = 0;
+       rdp->blimit = blimit;
+#ifdef CONFIG_NO_HZ
+       rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
+#endif /* #ifdef CONFIG_NO_HZ */
+       rdp->cpu = cpu;
+       spin_unlock(&rnp->lock);                /* irqs remain disabled. */
+
+       /*
+        * A new grace period might start here.  If so, we won't be part
+        * of it, but that is OK, as we are currently in a quiescent state.
+        */
+
+       /* Exclude any attempts to start a new GP on large systems. */
+       spin_lock(&rsp->onofflock);             /* irqs already disabled. */
+
+       /* Add CPU to rcu_node bitmasks. */
+       rnp = rdp->mynode;
+       mask = rdp->grpmask;
+       do {
+               /* Exclude any attempts to start a new GP on small systems. */
+               spin_lock(&rnp->lock);  /* irqs already disabled. */
+               rnp->qsmaskinit |= mask;
+               mask = rnp->grpmask;
+               spin_unlock(&rnp->lock); /* irqs already disabled. */
+               rnp = rnp->parent;
+       } while (rnp != NULL && !(rnp->qsmaskinit & mask));
+
+       spin_unlock(&rsp->onofflock);           /* irqs remain disabled. */
+
+       /*
+        * A new grace period might start here.  If so, we will be part of
+        * it, and its gpnum will be greater than ours, so we will
+        * participate.  It is also possible for the gpnum to have been
+        * incremented before this function was called, and the bitmasks
+        * to not be filled out until now, in which case we will also
+        * participate due to our gpnum being behind.
+        */
+
+       /* Since it is coming online, the CPU is in a quiescent state. */
+       cpu_quiet(cpu, rsp, rdp, lastcomp);
+       local_irq_restore(flags);
+}
+
+static void __cpuinit rcu_online_cpu(int cpu)
+{
+#ifdef CONFIG_NO_HZ
+       struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+
+       rdtp->dynticks_nesting = 1;
+       rdtp->dynticks |= 1;    /* need consecutive #s even for hotplug. */
+       rdtp->dynticks_nmi = (rdtp->dynticks_nmi + 1) & ~0x1;
+#endif /* #ifdef CONFIG_NO_HZ */
+       rcu_init_percpu_data(cpu, &rcu_state);
+       rcu_init_percpu_data(cpu, &rcu_bh_state);
+       open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
+}
+
+/*
+ * Handle CPU online/offline notifcation events.
+ */
+static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
+                               unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               rcu_online_cpu(cpu);
+               break;
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+       case CPU_UP_CANCELED:
+       case CPU_UP_CANCELED_FROZEN:
+               rcu_offline_cpu(cpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+/*
+ * Compute the per-level fanout, either using the exact fanout specified
+ * or balancing the tree, depending on CONFIG_RCU_FANOUT_EXACT.
+ */
+#ifdef CONFIG_RCU_FANOUT_EXACT
+static void __init rcu_init_levelspread(struct rcu_state *rsp)
+{
+       int i;
+
+       for (i = NUM_RCU_LVLS - 1; i >= 0; i--)
+               rsp->levelspread[i] = CONFIG_RCU_FANOUT;
+}
+#else /* #ifdef CONFIG_RCU_FANOUT_EXACT */
+static void __init rcu_init_levelspread(struct rcu_state *rsp)
+{
+       int ccur;
+       int cprv;
+       int i;
+
+       cprv = NR_CPUS;
+       for (i = NUM_RCU_LVLS - 1; i >= 0; i--) {
+               ccur = rsp->levelcnt[i];
+               rsp->levelspread[i] = (cprv + ccur - 1) / ccur;
+               cprv = ccur;
+       }
+}
+#endif /* #else #ifdef CONFIG_RCU_FANOUT_EXACT */
+
+/*
+ * Helper function for rcu_init() that initializes one rcu_state structure.
+ */
+static void __init rcu_init_one(struct rcu_state *rsp)
+{
+       int cpustride = 1;
+       int i;
+       int j;
+       struct rcu_node *rnp;
+
+       /* Initialize the level-tracking arrays. */
+
+       for (i = 1; i < NUM_RCU_LVLS; i++)
+               rsp->level[i] = rsp->level[i - 1] + rsp->levelcnt[i - 1];
+       rcu_init_levelspread(rsp);
+
+       /* Initialize the elements themselves, starting from the leaves. */
+
+       for (i = NUM_RCU_LVLS - 1; i >= 0; i--) {
+               cpustride *= rsp->levelspread[i];
+               rnp = rsp->level[i];
+               for (j = 0; j < rsp->levelcnt[i]; j++, rnp++) {
+                       spin_lock_init(&rnp->lock);
+                       rnp->qsmask = 0;
+                       rnp->qsmaskinit = 0;
+                       rnp->grplo = j * cpustride;
+                       rnp->grphi = (j + 1) * cpustride - 1;
+                       if (rnp->grphi >= NR_CPUS)
+                               rnp->grphi = NR_CPUS - 1;
+                       if (i == 0) {
+                               rnp->grpnum = 0;
+                               rnp->grpmask = 0;
+                               rnp->parent = NULL;
+                       } else {
+                               rnp->grpnum = j % rsp->levelspread[i - 1];
+                               rnp->grpmask = 1UL << rnp->grpnum;
+                               rnp->parent = rsp->level[i - 1] +
+                                             j / rsp->levelspread[i - 1];
+                       }
+                       rnp->level = i;
+               }
+       }
+}
+
+/*
+ * Helper macro for __rcu_init().  To be used nowhere else!
+ * Assigns leaf node pointers into each CPU's rcu_data structure.
+ */
+#define RCU_DATA_PTR_INIT(rsp, rcu_data) \
+do { \
+       rnp = (rsp)->level[NUM_RCU_LVLS - 1]; \
+       j = 0; \
+       for_each_possible_cpu(i) { \
+               if (i > rnp[j].grphi) \
+                       j++; \
+               per_cpu(rcu_data, i).mynode = &rnp[j]; \
+               (rsp)->rda[i] = &per_cpu(rcu_data, i); \
+       } \
+} while (0)
+
+static struct notifier_block __cpuinitdata rcu_nb = {
+       .notifier_call  = rcu_cpu_notify,
+};
+
+void __init __rcu_init(void)
+{
+       int i;                  /* All used by RCU_DATA_PTR_INIT(). */
+       int j;
+       struct rcu_node *rnp;
+
+       printk(KERN_WARNING "Experimental hierarchical RCU implementation.\n");
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+       printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+       rcu_init_one(&rcu_state);
+       RCU_DATA_PTR_INIT(&rcu_state, rcu_data);
+       rcu_init_one(&rcu_bh_state);
+       RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data);
+
+       for_each_online_cpu(i)
+               rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long)i);
+       /* Register notifier for non-boot CPUs */
+       register_cpu_notifier(&rcu_nb);
+       printk(KERN_WARNING "Experimental hierarchical RCU init done.\n");
+}
+
+module_param(blimit, int, 0);
+module_param(qhimark, int, 0);
+module_param(qlowmark, int, 0);
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
new file mode 100644 (file)
index 0000000..d6db3e8
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Read-Copy Update tracing for classic implementation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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.
+ *
+ * Copyright IBM Corporation, 2008
+ *
+ * Papers:  http://www.rdrop.com/users/paulmck/RCU
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ *             Documentation/RCU
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/rcupdate.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/moduleparam.h>
+#include <linux/percpu.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
+{
+       if (!rdp->beenonline)
+               return;
+       seq_printf(m, "%3d%cc=%ld g=%ld pq=%d pqc=%ld qp=%d rpfq=%ld rp=%x",
+                  rdp->cpu,
+                  cpu_is_offline(rdp->cpu) ? '!' : ' ',
+                  rdp->completed, rdp->gpnum,
+                  rdp->passed_quiesc, rdp->passed_quiesc_completed,
+                  rdp->qs_pending,
+                  rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending,
+                  (int)(rdp->n_rcu_pending & 0xffff));
+#ifdef CONFIG_NO_HZ
+       seq_printf(m, " dt=%d/%d dn=%d df=%lu",
+                  rdp->dynticks->dynticks,
+                  rdp->dynticks->dynticks_nesting,
+                  rdp->dynticks->dynticks_nmi,
+                  rdp->dynticks_fqs);
+#endif /* #ifdef CONFIG_NO_HZ */
+       seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
+       seq_printf(m, " ql=%ld b=%ld\n", rdp->qlen, rdp->blimit);
+}
+
+#define PRINT_RCU_DATA(name, func, m) \
+       do { \
+               int _p_r_d_i; \
+               \
+               for_each_possible_cpu(_p_r_d_i) \
+                       func(m, &per_cpu(name, _p_r_d_i)); \
+       } while (0)
+
+static int show_rcudata(struct seq_file *m, void *unused)
+{
+       seq_puts(m, "rcu:\n");
+       PRINT_RCU_DATA(rcu_data, print_one_rcu_data, m);
+       seq_puts(m, "rcu_bh:\n");
+       PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m);
+       return 0;
+}
+
+static int rcudata_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcudata, NULL);
+}
+
+static struct file_operations rcudata_fops = {
+       .owner = THIS_MODULE,
+       .open = rcudata_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
+{
+       if (!rdp->beenonline)
+               return;
+       seq_printf(m, "%d,%s,%ld,%ld,%d,%ld,%d,%ld,%ld",
+                  rdp->cpu,
+                  cpu_is_offline(rdp->cpu) ? "\"Y\"" : "\"N\"",
+                  rdp->completed, rdp->gpnum,
+                  rdp->passed_quiesc, rdp->passed_quiesc_completed,
+                  rdp->qs_pending,
+                  rdp->n_rcu_pending_force_qs - rdp->n_rcu_pending,
+                  rdp->n_rcu_pending);
+#ifdef CONFIG_NO_HZ
+       seq_printf(m, ",%d,%d,%d,%lu",
+                  rdp->dynticks->dynticks,
+                  rdp->dynticks->dynticks_nesting,
+                  rdp->dynticks->dynticks_nmi,
+                  rdp->dynticks_fqs);
+#endif /* #ifdef CONFIG_NO_HZ */
+       seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
+       seq_printf(m, ",%ld,%ld\n", rdp->qlen, rdp->blimit);
+}
+
+static int show_rcudata_csv(struct seq_file *m, void *unused)
+{
+       seq_puts(m, "\"CPU\",\"Online?\",\"c\",\"g\",\"pq\",\"pqc\",\"pq\",\"rpfq\",\"rp\",");
+#ifdef CONFIG_NO_HZ
+       seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
+#endif /* #ifdef CONFIG_NO_HZ */
+       seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\"\n");
+       seq_puts(m, "\"rcu:\"\n");
+       PRINT_RCU_DATA(rcu_data, print_one_rcu_data_csv, m);
+       seq_puts(m, "\"rcu_bh:\"\n");
+       PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m);
+       return 0;
+}
+
+static int rcudata_csv_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcudata_csv, NULL);
+}
+
+static struct file_operations rcudata_csv_fops = {
+       .owner = THIS_MODULE,
+       .open = rcudata_csv_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
+{
+       int level = 0;
+       struct rcu_node *rnp;
+
+       seq_printf(m, "c=%ld g=%ld s=%d jfq=%ld j=%x "
+                     "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu\n",
+                  rsp->completed, rsp->gpnum, rsp->signaled,
+                  (long)(rsp->jiffies_force_qs - jiffies),
+                  (int)(jiffies & 0xffff),
+                  rsp->n_force_qs, rsp->n_force_qs_ngp,
+                  rsp->n_force_qs - rsp->n_force_qs_ngp,
+                  rsp->n_force_qs_lh);
+       for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
+               if (rnp->level != level) {
+                       seq_puts(m, "\n");
+                       level = rnp->level;
+               }
+               seq_printf(m, "%lx/%lx %d:%d ^%d    ",
+                          rnp->qsmask, rnp->qsmaskinit,
+                          rnp->grplo, rnp->grphi, rnp->grpnum);
+       }
+       seq_puts(m, "\n");
+}
+
+static int show_rcuhier(struct seq_file *m, void *unused)
+{
+       seq_puts(m, "rcu:\n");
+       print_one_rcu_state(m, &rcu_state);
+       seq_puts(m, "rcu_bh:\n");
+       print_one_rcu_state(m, &rcu_bh_state);
+       return 0;
+}
+
+static int rcuhier_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcuhier, NULL);
+}
+
+static struct file_operations rcuhier_fops = {
+       .owner = THIS_MODULE,
+       .open = rcuhier_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int show_rcugp(struct seq_file *m, void *unused)
+{
+       seq_printf(m, "rcu: completed=%ld  gpnum=%ld\n",
+                  rcu_state.completed, rcu_state.gpnum);
+       seq_printf(m, "rcu_bh: completed=%ld  gpnum=%ld\n",
+                  rcu_bh_state.completed, rcu_bh_state.gpnum);
+       return 0;
+}
+
+static int rcugp_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_rcugp, NULL);
+}
+
+static struct file_operations rcugp_fops = {
+       .owner = THIS_MODULE,
+       .open = rcugp_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static struct dentry *rcudir, *datadir, *datadir_csv, *hierdir, *gpdir;
+static int __init rcuclassic_trace_init(void)
+{
+       rcudir = debugfs_create_dir("rcu", NULL);
+       if (!rcudir)
+               goto out;
+
+       datadir = debugfs_create_file("rcudata", 0444, rcudir,
+                                               NULL, &rcudata_fops);
+       if (!datadir)
+               goto free_out;
+
+       datadir_csv = debugfs_create_file("rcudata.csv", 0444, rcudir,
+                                               NULL, &rcudata_csv_fops);
+       if (!datadir_csv)
+               goto free_out;
+
+       gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops);
+       if (!gpdir)
+               goto free_out;
+
+       hierdir = debugfs_create_file("rcuhier", 0444, rcudir,
+                                               NULL, &rcuhier_fops);
+       if (!hierdir)
+               goto free_out;
+       return 0;
+free_out:
+       if (datadir)
+               debugfs_remove(datadir);
+       if (datadir_csv)
+               debugfs_remove(datadir_csv);
+       if (gpdir)
+               debugfs_remove(gpdir);
+       debugfs_remove(rcudir);
+out:
+       return 1;
+}
+
+static void __exit rcuclassic_trace_cleanup(void)
+{
+       debugfs_remove(datadir);
+       debugfs_remove(datadir_csv);
+       debugfs_remove(gpdir);
+       debugfs_remove(hierdir);
+       debugfs_remove(rcudir);
+}
+
+
+module_init(rcuclassic_trace_init);
+module_exit(rcuclassic_trace_cleanup);
+
+MODULE_AUTHOR("Paul E. McKenney");
+MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
+MODULE_LICENSE("GPL");
index 4337063663efe39f8de666d16c591c84f66db0f7..e633106b12f6ffe7f8da4fa48c6105582052e411 100644 (file)
@@ -853,6 +853,15 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
                if (PFN_DOWN(p->start) <= PFN_DOWN(addr) &&
                    PFN_DOWN(p->end) >= PFN_DOWN(addr + size - 1))
                        continue;
+               /*
+                * if a resource is "BUSY", it's not a hardware resource
+                * but a driver mapping of such a resource; we don't want
+                * to warn for those; some drivers legitimately map only
+                * partial hardware resources. (example: vesafb)
+                */
+               if (p->flags & IORESOURCE_BUSY)
+                       continue;
+
                printk(KERN_WARNING "resource map sanity check conflict: "
                       "0x%llx 0x%llx 0x%llx 0x%llx %s\n",
                       (unsigned long long)addr,
index 748ff924a29056e57f5c30058ce39ea7e470b23e..fff1c4a20b6538966a0cf2b97a012c045d52b84d 100644 (file)
@@ -209,7 +209,6 @@ void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime)
        hrtimer_init(&rt_b->rt_period_timer,
                        CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        rt_b->rt_period_timer.function = sched_rt_period_timer;
-       rt_b->rt_period_timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
 }
 
 static inline int rt_bandwidth_enabled(void)
@@ -1139,7 +1138,6 @@ static void init_rq_hrtick(struct rq *rq)
 
        hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        rq->hrtick_timer.function = hrtick;
-       rq->hrtick_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
 }
 #else  /* CONFIG_SCHED_HRTICK */
 static inline void hrtick_clear(struct rq *rq)
@@ -4192,7 +4190,6 @@ void account_steal_time(struct task_struct *p, cputime_t steal)
 
        if (p == rq->idle) {
                p->stime = cputime_add(p->stime, steal);
-               account_group_system_time(p, steal);
                if (atomic_read(&rq->nr_iowait) > 0)
                        cpustat->iowait = cputime64_add(cpustat->iowait, tmp);
                else
@@ -4328,7 +4325,7 @@ void __kprobes sub_preempt_count(int val)
        /*
         * Underflow?
         */
-       if (DEBUG_LOCKS_WARN_ON(val > preempt_count()))
+       if (DEBUG_LOCKS_WARN_ON(val > preempt_count() - (!!kernel_locked())))
                return;
        /*
         * Is the spinlock portion underflowing?
index e7c69a720d69a0a7d9166c21883e05d2521cb26a..466e75ce271aa0795ac50266d9d3bc2acdde7261 100644 (file)
@@ -102,20 +102,6 @@ void local_bh_disable(void)
 
 EXPORT_SYMBOL(local_bh_disable);
 
-void __local_bh_enable(void)
-{
-       WARN_ON_ONCE(in_irq());
-
-       /*
-        * softirqs should never be enabled by __local_bh_enable(),
-        * it always nests inside local_bh_enable() sections:
-        */
-       WARN_ON_ONCE(softirq_count() == SOFTIRQ_OFFSET);
-
-       sub_preempt_count(SOFTIRQ_OFFSET);
-}
-EXPORT_SYMBOL_GPL(__local_bh_enable);
-
 /*
  * Special-case - softirqs can safely be enabled in
  * cond_resched_softirq(), or by __do_softirq(),
@@ -269,6 +255,7 @@ void irq_enter(void)
 {
        int cpu = smp_processor_id();
 
+       rcu_irq_enter();
        if (idle_cpu(cpu) && !in_interrupt()) {
                __irq_enter();
                tick_check_idle(cpu);
@@ -295,9 +282,9 @@ void irq_exit(void)
 
 #ifdef CONFIG_NO_HZ
        /* Make sure that timer wheel updates are propagated */
-       if (!in_interrupt() && idle_cpu(smp_processor_id()) && !need_resched())
-               tick_nohz_stop_sched_tick(0);
        rcu_irq_exit();
+       if (idle_cpu(smp_processor_id()) && !in_interrupt() && !need_resched())
+               tick_nohz_stop_sched_tick(0);
 #endif
        preempt_enable_no_resched();
 }
index dc0b3be6b7d52cb98bd84d599bfbb7e7d85b1e85..1ab790c67b174592401712b093bdc56a8aa3d537 100644 (file)
@@ -164,7 +164,7 @@ unsigned long __read_mostly sysctl_hung_task_check_count = 1024;
 /*
  * Zero means infinite timeout - no checking done:
  */
-unsigned long __read_mostly sysctl_hung_task_timeout_secs = 120;
+unsigned long __read_mostly sysctl_hung_task_timeout_secs = 480;
 
 unsigned long __read_mostly sysctl_hung_task_warnings = 10;
 
index 94b527ef1d1e37fe060ab812f13ef7276910549f..eb212f8f8bc801dab1ee7622936ba8caaec4369f 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
  */
 #include <linux/sched.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/stacktrace.h>
@@ -24,3 +25,13 @@ void print_stack_trace(struct stack_trace *trace, int spaces)
 }
 EXPORT_SYMBOL_GPL(print_stack_trace);
 
+/*
+ * Architectures that do not implement save_stack_trace_tsk get this
+ * weak alias and a once-per-bootup warning (whenever this facility
+ * is utilized - for example by procfs):
+ */
+__weak void
+save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.\n");
+}
index ebe65c2c9873382a6017c35fb2954ad5bb54029b..d356d79e84ac5682553e76d1bb7f449e5f808e69 100644 (file)
@@ -907,8 +907,8 @@ void do_sys_times(struct tms *tms)
        struct task_cputime cputime;
        cputime_t cutime, cstime;
 
-       spin_lock_irq(&current->sighand->siglock);
        thread_group_cputime(current, &cputime);
+       spin_lock_irq(&current->sighand->siglock);
        cutime = current->signal->cutime;
        cstime = current->signal->cstime;
        spin_unlock_irq(&current->sighand->siglock);
index 0b627d9c93d89c801c5bca63c4e0cdeb7c463fad..ff6d45c7626f09e183913072f0649d075f028c6a 100644 (file)
@@ -121,6 +121,10 @@ extern int sg_big_buff;
 #include <asm/system.h>
 #endif
 
+#ifdef CONFIG_SPARC64
+extern int sysctl_tsb_ratio;
+#endif
+
 #ifdef __hppa__
 extern int pwrsw_enabled;
 extern int unaligned_enabled;
@@ -451,6 +455,16 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
+#ifdef CONFIG_SPARC64
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "tsb-ratio",
+               .data           = &sysctl_tsb_ratio,
+               .maxlen         = sizeof (int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
 #ifdef __hppa__
        {
                .ctl_name       = KERN_HPPA_PWRSW,
index 8ff15e5d486b137e65f96c64b5a206315bab7ee4..f5f793d924151736d92034ea0accd37fb354eef3 100644 (file)
@@ -131,7 +131,7 @@ static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
 {
        enum hrtimer_restart res = HRTIMER_NORESTART;
 
-       write_seqlock_irq(&xtime_lock);
+       write_seqlock(&xtime_lock);
 
        switch (time_state) {
        case TIME_OK:
@@ -164,7 +164,7 @@ static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
        }
        update_vsyscall(&xtime, clock);
 
-       write_sequnlock_irq(&xtime_lock);
+       write_sequnlock(&xtime_lock);
 
        return res;
 }
index 342fc9ccab46d5132aae1c58b1fbce0d02a2feaf..8f3fc2582d38b7073927e9dc004ef38e16909ab0 100644 (file)
@@ -247,7 +247,7 @@ void tick_nohz_stop_sched_tick(int inidle)
        if (need_resched())
                goto end;
 
-       if (unlikely(local_softirq_pending())) {
+       if (unlikely(local_softirq_pending() && cpu_online(cpu))) {
                static int ratelimit;
 
                if (ratelimit < 10) {
@@ -282,8 +282,31 @@ void tick_nohz_stop_sched_tick(int inidle)
        /* Schedule the tick, if we are at least one jiffie off */
        if ((long)delta_jiffies >= 1) {
 
+               /*
+               * calculate the expiry time for the next timer wheel
+               * timer
+               */
+               expires = ktime_add_ns(last_update, tick_period.tv64 *
+                                  delta_jiffies);
+
+               /*
+                * If this cpu is the one which updates jiffies, then
+                * give up the assignment and let it be taken by the
+                * cpu which runs the tick timer next, which might be
+                * this cpu as well. If we don't drop this here the
+                * jiffies might be stale and do_timer() never
+                * invoked.
+                */
+               if (cpu == tick_do_timer_cpu)
+                       tick_do_timer_cpu = TICK_DO_TIMER_NONE;
+
                if (delta_jiffies > 1)
                        cpu_set(cpu, nohz_cpu_mask);
+
+               /* Skip reprogram of event if its not changed */
+               if (ts->tick_stopped && ktime_equal(expires, dev->next_event))
+                       goto out;
+
                /*
                 * nohz_stop_sched_tick can be called several times before
                 * the nohz_restart_sched_tick is called. This happens when
@@ -306,17 +329,6 @@ void tick_nohz_stop_sched_tick(int inidle)
                        rcu_enter_nohz();
                }
 
-               /*
-                * If this cpu is the one which updates jiffies, then
-                * give up the assignment and let it be taken by the
-                * cpu which runs the tick timer next, which might be
-                * this cpu as well. If we don't drop this here the
-                * jiffies might be stale and do_timer() never
-                * invoked.
-                */
-               if (cpu == tick_do_timer_cpu)
-                       tick_do_timer_cpu = TICK_DO_TIMER_NONE;
-
                ts->idle_sleeps++;
 
                /*
@@ -332,12 +344,7 @@ void tick_nohz_stop_sched_tick(int inidle)
                        goto out;
                }
 
-               /*
-                * calculate the expiry time for the next timer wheel
-                * timer
-                */
-               expires = ktime_add_ns(last_update, tick_period.tv64 *
-                                      delta_jiffies);
+               /* Mark expiries */
                ts->idle_expires = expires;
 
                if (ts->nohz_mode == NOHZ_MODE_HIGHRES) {
@@ -681,7 +688,6 @@ void tick_setup_sched_timer(void)
         */
        hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        ts->sched_timer.function = tick_sched_timer;
-       ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
 
        /* Get the next period (per cpu) */
        hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
index 76f34c0ef29c3aa9ea0123a3933e84c296a3caf9..1d601a7c4587eb075b8fe0100705a6d00ffc9172 100644 (file)
@@ -69,6 +69,7 @@ void tracing_on(void)
 {
        set_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
 }
+EXPORT_SYMBOL_GPL(tracing_on);
 
 /**
  * tracing_off - turn off all tracing buffers
@@ -82,6 +83,7 @@ void tracing_off(void)
 {
        clear_bit(RB_BUFFERS_ON_BIT, &ring_buffer_flags);
 }
+EXPORT_SYMBOL_GPL(tracing_off);
 
 /**
  * tracing_off_permanent - permanently disable ring buffers
@@ -111,12 +113,14 @@ u64 ring_buffer_time_stamp(int cpu)
 
        return time;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_time_stamp);
 
 void ring_buffer_normalize_time_stamp(int cpu, u64 *ts)
 {
        /* Just stupid testing the normalize function and deltas */
        *ts >>= DEBUG_SHIFT;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_normalize_time_stamp);
 
 #define RB_EVNT_HDR_SIZE (sizeof(struct ring_buffer_event))
 #define RB_ALIGNMENT_SHIFT     2
@@ -166,6 +170,7 @@ unsigned ring_buffer_event_length(struct ring_buffer_event *event)
 {
        return rb_event_length(event);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_event_length);
 
 /* inline for ring buffer fast paths */
 static inline void *
@@ -187,6 +192,7 @@ void *ring_buffer_event_data(struct ring_buffer_event *event)
 {
        return rb_event_data(event);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_event_data);
 
 #define for_each_buffer_cpu(buffer, cpu)               \
        for_each_cpu_mask(cpu, buffer->cpumask)
@@ -427,7 +433,7 @@ extern int ring_buffer_page_too_big(void);
 
 /**
  * ring_buffer_alloc - allocate a new ring_buffer
- * @size: the size in bytes that is needed.
+ * @size: the size in bytes per cpu that is needed.
  * @flags: attributes to set for the ring buffer.
  *
  * Currently the only flag that is available is the RB_FL_OVERWRITE
@@ -490,6 +496,7 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
        kfree(buffer);
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_alloc);
 
 /**
  * ring_buffer_free - free a ring buffer.
@@ -505,6 +512,7 @@ ring_buffer_free(struct ring_buffer *buffer)
 
        kfree(buffer);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_free);
 
 static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer);
 
@@ -680,6 +688,7 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
        mutex_unlock(&buffer->mutex);
        return -ENOMEM;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_resize);
 
 static inline int rb_null_event(struct ring_buffer_event *event)
 {
@@ -1304,6 +1313,7 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer,
        ftrace_preempt_enable(resched);
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve);
 
 static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer,
                      struct ring_buffer_event *event)
@@ -1350,6 +1360,7 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit);
 
 /**
  * ring_buffer_write - write data to the buffer without reserving
@@ -1411,6 +1422,7 @@ int ring_buffer_write(struct ring_buffer *buffer,
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_write);
 
 static inline int rb_per_cpu_empty(struct ring_buffer_per_cpu *cpu_buffer)
 {
@@ -1437,6 +1449,7 @@ void ring_buffer_record_disable(struct ring_buffer *buffer)
 {
        atomic_inc(&buffer->record_disabled);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_record_disable);
 
 /**
  * ring_buffer_record_enable - enable writes to the buffer
@@ -1449,6 +1462,7 @@ void ring_buffer_record_enable(struct ring_buffer *buffer)
 {
        atomic_dec(&buffer->record_disabled);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_record_enable);
 
 /**
  * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer
@@ -1470,6 +1484,7 @@ void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu)
        cpu_buffer = buffer->buffers[cpu];
        atomic_inc(&cpu_buffer->record_disabled);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_record_disable_cpu);
 
 /**
  * ring_buffer_record_enable_cpu - enable writes to the buffer
@@ -1489,6 +1504,7 @@ void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu)
        cpu_buffer = buffer->buffers[cpu];
        atomic_dec(&cpu_buffer->record_disabled);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_record_enable_cpu);
 
 /**
  * ring_buffer_entries_cpu - get the number of entries in a cpu buffer
@@ -1505,6 +1521,7 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu)
        cpu_buffer = buffer->buffers[cpu];
        return cpu_buffer->entries;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_entries_cpu);
 
 /**
  * ring_buffer_overrun_cpu - get the number of overruns in a cpu_buffer
@@ -1521,6 +1538,7 @@ unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu)
        cpu_buffer = buffer->buffers[cpu];
        return cpu_buffer->overrun;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu);
 
 /**
  * ring_buffer_entries - get the number of entries in a buffer
@@ -1543,6 +1561,7 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer)
 
        return entries;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_entries);
 
 /**
  * ring_buffer_overrun_cpu - get the number of overruns in buffer
@@ -1565,6 +1584,7 @@ unsigned long ring_buffer_overruns(struct ring_buffer *buffer)
 
        return overruns;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_overruns);
 
 static void rb_iter_reset(struct ring_buffer_iter *iter)
 {
@@ -1600,6 +1620,7 @@ void ring_buffer_iter_reset(struct ring_buffer_iter *iter)
        rb_iter_reset(iter);
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_iter_reset);
 
 /**
  * ring_buffer_iter_empty - check if an iterator has no more to read
@@ -1614,6 +1635,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
        return iter->head_page == cpu_buffer->commit_page &&
                iter->head == rb_commit_index(cpu_buffer);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
 
 static void
 rb_update_read_stamp(struct ring_buffer_per_cpu *cpu_buffer,
@@ -1880,6 +1902,7 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_peek);
 
 static struct ring_buffer_event *
 rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
@@ -1940,6 +1963,7 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_iter_peek);
 
 /**
  * ring_buffer_peek - peek at the next event to be read
@@ -2017,6 +2041,7 @@ ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts)
 
        return event;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_consume);
 
 /**
  * ring_buffer_read_start - start a non consuming read of the buffer
@@ -2059,6 +2084,7 @@ ring_buffer_read_start(struct ring_buffer *buffer, int cpu)
 
        return iter;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_read_start);
 
 /**
  * ring_buffer_finish - finish reading the iterator of the buffer
@@ -2075,6 +2101,7 @@ ring_buffer_read_finish(struct ring_buffer_iter *iter)
        atomic_dec(&cpu_buffer->record_disabled);
        kfree(iter);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_read_finish);
 
 /**
  * ring_buffer_read - read the next item in the ring buffer by the iterator
@@ -2101,6 +2128,7 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts)
 
        return event;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_read);
 
 /**
  * ring_buffer_size - return the size of the ring buffer (in bytes)
@@ -2110,6 +2138,7 @@ unsigned long ring_buffer_size(struct ring_buffer *buffer)
 {
        return BUF_PAGE_SIZE * buffer->pages;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_size);
 
 static void
 rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
@@ -2156,6 +2185,7 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu)
 
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
 
 /**
  * ring_buffer_reset - reset a ring buffer
@@ -2168,6 +2198,7 @@ void ring_buffer_reset(struct ring_buffer *buffer)
        for_each_buffer_cpu(buffer, cpu)
                ring_buffer_reset_cpu(buffer, cpu);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_reset);
 
 /**
  * rind_buffer_empty - is the ring buffer empty?
@@ -2186,6 +2217,7 @@ int ring_buffer_empty(struct ring_buffer *buffer)
        }
        return 1;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_empty);
 
 /**
  * ring_buffer_empty_cpu - is a cpu buffer of a ring buffer empty?
@@ -2202,6 +2234,7 @@ int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu)
        cpu_buffer = buffer->buffers[cpu];
        return rb_per_cpu_empty(cpu_buffer);
 }
+EXPORT_SYMBOL_GPL(ring_buffer_empty_cpu);
 
 /**
  * ring_buffer_swap_cpu - swap a CPU buffer between two ring buffers
@@ -2250,6 +2283,7 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
 
 static void rb_remove_entries(struct ring_buffer_per_cpu *cpu_buffer,
                              struct buffer_data_page *bpage)
index f4bb3800318bd7a777efa47eb4cfc01032f0ba85..4185d5221633f19755efb818a1fb969a69d0d29c 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/gfp.h>
 #include <linux/fs.h>
 #include <linux/kprobes.h>
-#include <linux/seq_file.h>
 #include <linux/writeback.h>
 
 #include <linux/stacktrace.h>
@@ -1310,7 +1309,7 @@ enum trace_file_type {
        TRACE_FILE_ANNOTATE     = 2,
 };
 
-static void trace_iterator_increment(struct trace_iterator *iter, int cpu)
+static void trace_iterator_increment(struct trace_iterator *iter)
 {
        /* Don't allow ftrace to trace into the ring buffers */
        ftrace_disable_cpu();
@@ -1389,7 +1388,7 @@ static void *find_next_entry_inc(struct trace_iterator *iter)
        iter->ent = __find_next_entry(iter, &iter->cpu, &iter->ts);
 
        if (iter->ent)
-               trace_iterator_increment(iter, iter->cpu);
+               trace_iterator_increment(iter);
 
        return iter->ent ? iter : NULL;
 }
index 01becf1f19ff78fad129aa6474ec550c428519ae..a5779bd975db0a386cd67d67629a2bf53e72764e 100644 (file)
@@ -202,7 +202,6 @@ static void start_stack_timer(int cpu)
 
        hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        hrtimer->function = stack_trace_timer_fn;
-       hrtimer->cb_mode = HRTIMER_CB_IRQSAFE_PERCPU;
 
        hrtimer_start(hrtimer, ns_to_ktime(sample_period), HRTIMER_MODE_REL);
 }
index b0f239e443bc0fbb11a27ee98dbaf4e641d21971..2e75478e9c696bc6933ca8952c0a013dd30eb78a 100644 (file)
@@ -252,6 +252,14 @@ config DEBUG_OBJECTS_TIMERS
          timer routines to track the life time of timer objects and
          validate the timer operations.
 
+config DEBUG_OBJECTS_ENABLE_DEFAULT
+       int "debug_objects bootup default value (0-1)"
+        range 0 1
+        default "1"
+        depends on DEBUG_OBJECTS
+        help
+          Debug objects boot parameter default value
+
 config DEBUG_SLAB
        bool "Debug slab memory allocations"
        depends on DEBUG_KERNEL && SLAB
@@ -545,6 +553,16 @@ config DEBUG_SG
 
          If unsure, say N.
 
+config DEBUG_NOTIFIERS
+       bool "Debug notifier call chains"
+       depends on DEBUG_KERNEL
+       help
+         Enable this to turn on sanity checking for notifier call chains.
+         This is most useful for kernel developers to make sure that
+         modules properly unregister themselves from notifier chains.
+         This is a relatively cheap check but if you care about maximum
+         performance, say N.
+
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
        depends on DEBUG_KERNEL && \
@@ -619,6 +637,19 @@ config RCU_CPU_STALL_DETECTOR
 
          Say N if you are unsure.
 
+config RCU_CPU_STALL_DETECTOR
+       bool "Check for stalled CPUs delaying RCU grace periods"
+       depends on CLASSIC_RCU || TREE_RCU
+       default n
+       help
+         This option causes RCU to printk information on which
+         CPUs are delaying the current grace period, but only when
+         the grace period extends for excessive time periods.
+
+         Say Y if you want RCU to perform such checks.
+
+         Say N if you are unsure.
+
 config KPROBES_SANITY_TEST
        bool "Kprobes sanity tests"
        depends on DEBUG_KERNEL
@@ -699,6 +730,7 @@ config FAULT_INJECTION
 config FAILSLAB
        bool "Fault-injection capability for kmalloc"
        depends on FAULT_INJECTION
+       depends on SLAB || SLUB
        help
          Provide fault-injection capability for kmalloc.
 
index e3ab374e1334ab80fc172c3d256d2eb4fddd665e..5d99be1fd988bbd3df0f73f07fbee5e079d4cb53 100644 (file)
@@ -45,7 +45,9 @@ static struct kmem_cache      *obj_cache;
 static int                     debug_objects_maxchain __read_mostly;
 static int                     debug_objects_fixups __read_mostly;
 static int                     debug_objects_warnings __read_mostly;
-static int                     debug_objects_enabled __read_mostly;
+static int                     debug_objects_enabled __read_mostly
+                               = CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT;
+
 static struct debug_obj_descr  *descr_test  __read_mostly;
 
 static int __init enable_object_debug(char *str)
index 5f6c629a924d8da3a5e126b6fa76e12e562fe768..fa2dc4e5f9baca6a9ae5c71534c8b4caa16557d6 100644 (file)
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/swiotlb.h>
 #include <linux/string.h>
+#include <linux/swiotlb.h>
 #include <linux/types.h>
 #include <linux/ctype.h>
+#include <linux/highmem.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 #define OFFSET(val,align) ((unsigned long)     \
                           ( (val) & ( (align) - 1)))
 
-#define SG_ENT_VIRT_ADDRESS(sg)        (sg_virt((sg)))
-#define SG_ENT_PHYS_ADDRESS(sg)        virt_to_bus(SG_ENT_VIRT_ADDRESS(sg))
-
-/*
- * Maximum allowable number of contiguous slabs to map,
- * must be a power of 2.  What is the appropriate value ?
- * The complexity of {map,unmap}_single is linearly dependent on this value.
- */
-#define IO_TLB_SEGSIZE 128
-
-/*
- * log of the size of each IO TLB slab.  The number of slabs is command line
- * controllable.
- */
-#define IO_TLB_SHIFT 11
-
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 
 /*
@@ -102,7 +89,10 @@ static unsigned int io_tlb_index;
  * We need to save away the original address corresponding to a mapped entry
  * for the sync operations.
  */
-static unsigned char **io_tlb_orig_addr;
+static struct swiotlb_phys_addr {
+       struct page *page;
+       unsigned int offset;
+} *io_tlb_orig_addr;
 
 /*
  * Protect the above data structures in the map and unmap calls
@@ -126,6 +116,72 @@ setup_io_tlb_npages(char *str)
 __setup("swiotlb=", setup_io_tlb_npages);
 /* make io_tlb_overflow tunable too? */
 
+void * __weak swiotlb_alloc_boot(size_t size, unsigned long nslabs)
+{
+       return alloc_bootmem_low_pages(size);
+}
+
+void * __weak swiotlb_alloc(unsigned order, unsigned long nslabs)
+{
+       return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
+}
+
+dma_addr_t __weak swiotlb_phys_to_bus(phys_addr_t paddr)
+{
+       return paddr;
+}
+
+phys_addr_t __weak swiotlb_bus_to_phys(dma_addr_t baddr)
+{
+       return baddr;
+}
+
+static dma_addr_t swiotlb_virt_to_bus(volatile void *address)
+{
+       return swiotlb_phys_to_bus(virt_to_phys(address));
+}
+
+static void *swiotlb_bus_to_virt(dma_addr_t address)
+{
+       return phys_to_virt(swiotlb_bus_to_phys(address));
+}
+
+int __weak swiotlb_arch_range_needs_mapping(void *ptr, size_t size)
+{
+       return 0;
+}
+
+static dma_addr_t swiotlb_sg_to_bus(struct scatterlist *sg)
+{
+       return swiotlb_phys_to_bus(page_to_phys(sg_page(sg)) + sg->offset);
+}
+
+static void swiotlb_print_info(unsigned long bytes)
+{
+       phys_addr_t pstart, pend;
+       dma_addr_t bstart, bend;
+
+       pstart = virt_to_phys(io_tlb_start);
+       pend = virt_to_phys(io_tlb_end);
+
+       bstart = swiotlb_phys_to_bus(pstart);
+       bend = swiotlb_phys_to_bus(pend);
+
+       printk(KERN_INFO "Placing %luMB software IO TLB between %p - %p\n",
+              bytes >> 20, io_tlb_start, io_tlb_end);
+       if (pstart != bstart || pend != bend)
+               printk(KERN_INFO "software IO TLB at phys %#llx - %#llx"
+                      " bus %#llx - %#llx\n",
+                      (unsigned long long)pstart,
+                      (unsigned long long)pend,
+                      (unsigned long long)bstart,
+                      (unsigned long long)bend);
+       else
+               printk(KERN_INFO "software IO TLB at phys %#llx - %#llx\n",
+                      (unsigned long long)pstart,
+                      (unsigned long long)pend);
+}
+
 /*
  * Statically reserve bounce buffer space and initialize bounce buffer data
  * structures for the software IO TLB used to implement the DMA API.
@@ -145,7 +201,7 @@ swiotlb_init_with_default_size(size_t default_size)
        /*
         * Get IO TLB memory from the low pages
         */
-       io_tlb_start = alloc_bootmem_low_pages(bytes);
+       io_tlb_start = swiotlb_alloc_boot(bytes, io_tlb_nslabs);
        if (!io_tlb_start)
                panic("Cannot allocate SWIOTLB buffer");
        io_tlb_end = io_tlb_start + bytes;
@@ -159,7 +215,7 @@ swiotlb_init_with_default_size(size_t default_size)
        for (i = 0; i < io_tlb_nslabs; i++)
                io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
        io_tlb_index = 0;
-       io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
+       io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(struct swiotlb_phys_addr));
 
        /*
         * Get the overflow emergency buffer
@@ -168,8 +224,7 @@ swiotlb_init_with_default_size(size_t default_size)
        if (!io_tlb_overflow_buffer)
                panic("Cannot allocate SWIOTLB overflow buffer!\n");
 
-       printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n",
-              virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end));
+       swiotlb_print_info(bytes);
 }
 
 void __init
@@ -202,8 +257,7 @@ swiotlb_late_init_with_default_size(size_t default_size)
        bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
        while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
-               io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
-                                                       order);
+               io_tlb_start = swiotlb_alloc(order, io_tlb_nslabs);
                if (io_tlb_start)
                        break;
                order--;
@@ -235,12 +289,12 @@ swiotlb_late_init_with_default_size(size_t default_size)
                io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
        io_tlb_index = 0;
 
-       io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL,
-                                  get_order(io_tlb_nslabs * sizeof(char *)));
+       io_tlb_orig_addr = (struct swiotlb_phys_addr *)__get_free_pages(GFP_KERNEL,
+                                  get_order(io_tlb_nslabs * sizeof(struct swiotlb_phys_addr)));
        if (!io_tlb_orig_addr)
                goto cleanup3;
 
-       memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *));
+       memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(struct swiotlb_phys_addr));
 
        /*
         * Get the overflow emergency buffer
@@ -250,9 +304,7 @@ swiotlb_late_init_with_default_size(size_t default_size)
        if (!io_tlb_overflow_buffer)
                goto cleanup4;
 
-       printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - "
-              "0x%lx\n", bytes >> 20,
-              virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end));
+       swiotlb_print_info(bytes);
 
        return 0;
 
@@ -279,16 +331,69 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr, size_t size)
        return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
 }
 
+static inline int range_needs_mapping(void *ptr, size_t size)
+{
+       return swiotlb_force || swiotlb_arch_range_needs_mapping(ptr, size);
+}
+
 static int is_swiotlb_buffer(char *addr)
 {
        return addr >= io_tlb_start && addr < io_tlb_end;
 }
 
+static struct swiotlb_phys_addr swiotlb_bus_to_phys_addr(char *dma_addr)
+{
+       int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
+       struct swiotlb_phys_addr buffer = io_tlb_orig_addr[index];
+       buffer.offset += (long)dma_addr & ((1 << IO_TLB_SHIFT) - 1);
+       buffer.page += buffer.offset >> PAGE_SHIFT;
+       buffer.offset &= PAGE_SIZE - 1;
+       return buffer;
+}
+
+static void
+__sync_single(struct swiotlb_phys_addr buffer, char *dma_addr, size_t size, int dir)
+{
+       if (PageHighMem(buffer.page)) {
+               size_t len, bytes;
+               char *dev, *host, *kmp;
+
+               len = size;
+               while (len != 0) {
+                       unsigned long flags;
+
+                       bytes = len;
+                       if ((bytes + buffer.offset) > PAGE_SIZE)
+                               bytes = PAGE_SIZE - buffer.offset;
+                       local_irq_save(flags); /* protects KM_BOUNCE_READ */
+                       kmp  = kmap_atomic(buffer.page, KM_BOUNCE_READ);
+                       dev  = dma_addr + size - len;
+                       host = kmp + buffer.offset;
+                       if (dir == DMA_FROM_DEVICE)
+                               memcpy(host, dev, bytes);
+                       else
+                               memcpy(dev, host, bytes);
+                       kunmap_atomic(kmp, KM_BOUNCE_READ);
+                       local_irq_restore(flags);
+                       len -= bytes;
+                       buffer.page++;
+                       buffer.offset = 0;
+               }
+       } else {
+               void *v = page_address(buffer.page) + buffer.offset;
+
+               if (dir == DMA_TO_DEVICE)
+                       memcpy(dma_addr, v, size);
+               else
+                       memcpy(v, dma_addr, size);
+       }
+}
+
 /*
  * Allocates bounce buffer and returns its kernel virtual address.
  */
 static void *
-map_single(struct device *hwdev, char *buffer, size_t size, int dir)
+map_single(struct device *hwdev, struct swiotlb_phys_addr buffer, size_t size, int dir)
 {
        unsigned long flags;
        char *dma_addr;
@@ -298,11 +403,16 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
        unsigned long mask;
        unsigned long offset_slots;
        unsigned long max_slots;
+       struct swiotlb_phys_addr slot_buf;
 
        mask = dma_get_seg_boundary(hwdev);
-       start_dma_addr = virt_to_bus(io_tlb_start) & mask;
+       start_dma_addr = swiotlb_virt_to_bus(io_tlb_start) & mask;
 
        offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+
+       /*
+        * Carefully handle integer overflow which can occur when mask == ~0UL.
+        */
        max_slots = mask + 1
                    ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
                    : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
@@ -378,10 +488,15 @@ found:
         * This is needed when we sync the memory.  Then we sync the buffer if
         * needed.
         */
-       for (i = 0; i < nslots; i++)
-               io_tlb_orig_addr[index+i] = buffer + (i << IO_TLB_SHIFT);
+       slot_buf = buffer;
+       for (i = 0; i < nslots; i++) {
+               slot_buf.page += slot_buf.offset >> PAGE_SHIFT;
+               slot_buf.offset &= PAGE_SIZE - 1;
+               io_tlb_orig_addr[index+i] = slot_buf;
+               slot_buf.offset += 1 << IO_TLB_SHIFT;
+       }
        if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
-               memcpy(dma_addr, buffer, size);
+               __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
 
        return dma_addr;
 }
@@ -395,17 +510,17 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
        unsigned long flags;
        int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
        int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
-       char *buffer = io_tlb_orig_addr[index];
+       struct swiotlb_phys_addr buffer = swiotlb_bus_to_phys_addr(dma_addr);
 
        /*
         * First, sync the memory before unmapping the entry
         */
-       if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
+       if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))
                /*
                 * bounce... copy the data back into the original buffer * and
                 * delete the bounce buffer.
                 */
-               memcpy(buffer, dma_addr, size);
+               __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
 
        /*
         * Return the buffer to the free list by setting the corresponding
@@ -437,21 +552,18 @@ static void
 sync_single(struct device *hwdev, char *dma_addr, size_t size,
            int dir, int target)
 {
-       int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
-       char *buffer = io_tlb_orig_addr[index];
-
-       buffer += ((unsigned long)dma_addr & ((1 << IO_TLB_SHIFT) - 1));
+       struct swiotlb_phys_addr buffer = swiotlb_bus_to_phys_addr(dma_addr);
 
        switch (target) {
        case SYNC_FOR_CPU:
                if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
-                       memcpy(buffer, dma_addr, size);
+                       __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
                else
                        BUG_ON(dir != DMA_TO_DEVICE);
                break;
        case SYNC_FOR_DEVICE:
                if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
-                       memcpy(dma_addr, buffer, size);
+                       __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
                else
                        BUG_ON(dir != DMA_FROM_DEVICE);
                break;
@@ -473,7 +585,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                dma_mask = hwdev->coherent_dma_mask;
 
        ret = (void *)__get_free_pages(flags, order);
-       if (ret && !is_buffer_dma_capable(dma_mask, virt_to_bus(ret), size)) {
+       if (ret && !is_buffer_dma_capable(dma_mask, swiotlb_virt_to_bus(ret), size)) {
                /*
                 * The allocated memory isn't reachable by the device.
                 * Fall back on swiotlb_map_single().
@@ -488,13 +600,16 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                 * swiotlb_map_single(), which will grab memory from
                 * the lowest available address range.
                 */
-               ret = map_single(hwdev, NULL, size, DMA_FROM_DEVICE);
+               struct swiotlb_phys_addr buffer;
+               buffer.page = virt_to_page(NULL);
+               buffer.offset = 0;
+               ret = map_single(hwdev, buffer, size, DMA_FROM_DEVICE);
                if (!ret)
                        return NULL;
        }
 
        memset(ret, 0, size);
-       dev_addr = virt_to_bus(ret);
+       dev_addr = swiotlb_virt_to_bus(ret);
 
        /* Confirm address can be DMA'd by device */
        if (!is_buffer_dma_capable(dma_mask, dev_addr, size)) {
@@ -554,8 +669,9 @@ dma_addr_t
 swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
                         int dir, struct dma_attrs *attrs)
 {
-       dma_addr_t dev_addr = virt_to_bus(ptr);
+       dma_addr_t dev_addr = swiotlb_virt_to_bus(ptr);
        void *map;
+       struct swiotlb_phys_addr buffer;
 
        BUG_ON(dir == DMA_NONE);
        /*
@@ -563,19 +679,22 @@ swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
         * we can safely return the device addr and not worry about bounce
         * buffering it.
         */
-       if (!address_needs_mapping(hwdev, dev_addr, size) && !swiotlb_force)
+       if (!address_needs_mapping(hwdev, dev_addr, size) &&
+           !range_needs_mapping(ptr, size))
                return dev_addr;
 
        /*
         * Oh well, have to allocate and map a bounce buffer.
         */
-       map = map_single(hwdev, ptr, size, dir);
+       buffer.page   = virt_to_page(ptr);
+       buffer.offset = (unsigned long)ptr & ~PAGE_MASK;
+       map = map_single(hwdev, buffer, size, dir);
        if (!map) {
                swiotlb_full(hwdev, size, dir, 1);
                map = io_tlb_overflow_buffer;
        }
 
-       dev_addr = virt_to_bus(map);
+       dev_addr = swiotlb_virt_to_bus(map);
 
        /*
         * Ensure that the address returned is DMA'ble
@@ -605,7 +724,7 @@ void
 swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
                           size_t size, int dir, struct dma_attrs *attrs)
 {
-       char *dma_addr = bus_to_virt(dev_addr);
+       char *dma_addr = swiotlb_bus_to_virt(dev_addr);
 
        BUG_ON(dir == DMA_NONE);
        if (is_swiotlb_buffer(dma_addr))
@@ -635,7 +754,7 @@ static void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
                    size_t size, int dir, int target)
 {
-       char *dma_addr = bus_to_virt(dev_addr);
+       char *dma_addr = swiotlb_bus_to_virt(dev_addr);
 
        BUG_ON(dir == DMA_NONE);
        if (is_swiotlb_buffer(dma_addr))
@@ -666,7 +785,7 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
                          unsigned long offset, size_t size,
                          int dir, int target)
 {
-       char *dma_addr = bus_to_virt(dev_addr) + offset;
+       char *dma_addr = swiotlb_bus_to_virt(dev_addr) + offset;
 
        BUG_ON(dir == DMA_NONE);
        if (is_swiotlb_buffer(dma_addr))
@@ -714,18 +833,20 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
                     int dir, struct dma_attrs *attrs)
 {
        struct scatterlist *sg;
-       void *addr;
+       struct swiotlb_phys_addr buffer;
        dma_addr_t dev_addr;
        int i;
 
        BUG_ON(dir == DMA_NONE);
 
        for_each_sg(sgl, sg, nelems, i) {
-               addr = SG_ENT_VIRT_ADDRESS(sg);
-               dev_addr = virt_to_bus(addr);
-               if (swiotlb_force ||
+               dev_addr = swiotlb_sg_to_bus(sg);
+               if (range_needs_mapping(sg_virt(sg), sg->length) ||
                    address_needs_mapping(hwdev, dev_addr, sg->length)) {
-                       void *map = map_single(hwdev, addr, sg->length, dir);
+                       void *map;
+                       buffer.page   = sg_page(sg);
+                       buffer.offset = sg->offset;
+                       map = map_single(hwdev, buffer, sg->length, dir);
                        if (!map) {
                                /* Don't panic here, we expect map_sg users
                                   to do proper error handling. */
@@ -735,7 +856,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
                                sgl[0].dma_length = 0;
                                return 0;
                        }
-                       sg->dma_address = virt_to_bus(map);
+                       sg->dma_address = swiotlb_virt_to_bus(map);
                } else
                        sg->dma_address = dev_addr;
                sg->dma_length = sg->length;
@@ -765,11 +886,11 @@ swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
        BUG_ON(dir == DMA_NONE);
 
        for_each_sg(sgl, sg, nelems, i) {
-               if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-                       unmap_single(hwdev, bus_to_virt(sg->dma_address),
+               if (sg->dma_address != swiotlb_sg_to_bus(sg))
+                       unmap_single(hwdev, swiotlb_bus_to_virt(sg->dma_address),
                                     sg->dma_length, dir);
                else if (dir == DMA_FROM_DEVICE)
-                       dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
+                       dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length);
        }
 }
 EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
@@ -798,11 +919,11 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
        BUG_ON(dir == DMA_NONE);
 
        for_each_sg(sgl, sg, nelems, i) {
-               if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-                       sync_single(hwdev, bus_to_virt(sg->dma_address),
+               if (sg->dma_address != swiotlb_sg_to_bus(sg))
+                       sync_single(hwdev, swiotlb_bus_to_virt(sg->dma_address),
                                    sg->dma_length, dir, target);
                else if (dir == DMA_FROM_DEVICE)
-                       dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
+                       dma_mark_clean(swiotlb_bus_to_virt(sg->dma_address), sg->dma_length);
        }
 }
 
@@ -823,7 +944,7 @@ swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
 int
 swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
 {
-       return (dma_addr == virt_to_bus(io_tlb_overflow_buffer));
+       return (dma_addr == swiotlb_virt_to_bus(io_tlb_overflow_buffer));
 }
 
 /*
@@ -835,7 +956,7 @@ swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
 int
 swiotlb_dma_supported(struct device *hwdev, u64 mask)
 {
-       return virt_to_bus(io_tlb_end - 1) <= mask;
+       return swiotlb_virt_to_bus(io_tlb_end - 1) <= mask;
 }
 
 EXPORT_SYMBOL(swiotlb_map_single);
index c06b45a1ff5f64cf2e007258bfdaf9af5c280d98..51c27709cc7c0b6d15e682bbb6e9c07f63acabaa 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_SLOB) += slob.o
 obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
 obj-$(CONFIG_SLAB) += slab.o
 obj-$(CONFIG_SLUB) += slub.o
+obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
 obj-$(CONFIG_MIGRATION) += migrate.o
index bf0cf7c8387b8d92c93dfb18436a7f2cf424cb00..e590272fe7a8f3e40acb21059bb0082f74354f26 100644 (file)
@@ -198,8 +198,13 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
                /*
                 * irk, bounce it
                 */
-               if (!bio)
-                       bio = bio_alloc(GFP_NOIO, (*bio_orig)->bi_vcnt);
+               if (!bio) {
+                       unsigned int cnt = (*bio_orig)->bi_vcnt;
+
+                       bio = bio_alloc(GFP_NOIO, cnt);
+                       memset(bio->bi_io_vec, 0, cnt * sizeof(struct bio_vec));
+               }
+                       
 
                to = bio->bi_io_vec + i;
 
diff --git a/mm/failslab.c b/mm/failslab.c
new file mode 100644 (file)
index 0000000..7c6ea64
--- /dev/null
@@ -0,0 +1,59 @@
+#include <linux/fault-inject.h>
+
+static struct {
+       struct fault_attr attr;
+       u32 ignore_gfp_wait;
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+       struct dentry *ignore_gfp_wait_file;
+#endif
+} failslab = {
+       .attr = FAULT_ATTR_INITIALIZER,
+       .ignore_gfp_wait = 1,
+};
+
+bool should_failslab(size_t size, gfp_t gfpflags)
+{
+       if (gfpflags & __GFP_NOFAIL)
+               return false;
+
+        if (failslab.ignore_gfp_wait && (gfpflags & __GFP_WAIT))
+               return false;
+
+       return should_fail(&failslab.attr, size);
+}
+
+static int __init setup_failslab(char *str)
+{
+       return setup_fault_attr(&failslab.attr, str);
+}
+__setup("failslab=", setup_failslab);
+
+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
+
+static int __init failslab_debugfs_init(void)
+{
+       mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
+       struct dentry *dir;
+       int err;
+
+       err = init_fault_attr_dentries(&failslab.attr, "failslab");
+       if (err)
+               return err;
+       dir = failslab.attr.dentries.dir;
+
+       failslab.ignore_gfp_wait_file =
+               debugfs_create_bool("ignore-gfp-wait", mode, dir,
+                                     &failslab.ignore_gfp_wait);
+
+       if (!failslab.ignore_gfp_wait_file) {
+               err = -ENOMEM;
+               debugfs_remove(failslab.ignore_gfp_wait_file);
+               cleanup_fault_attr_dentries(&failslab.attr);
+       }
+
+       return err;
+}
+
+late_initcall(failslab_debugfs_init);
+
+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
index f01b7eed6e16c4e3f32e039b7f2223ca598f40aa..0a2010a9518c499efe694c9ed0d42f5bd18e459b 100644 (file)
@@ -3075,3 +3075,18 @@ void print_vma_addr(char *prefix, unsigned long ip)
        }
        up_read(&current->mm->mmap_sem);
 }
+
+#ifdef CONFIG_PROVE_LOCKING
+void might_fault(void)
+{
+       might_sleep();
+       /*
+        * it would be nicer only to annotate paths which are not under
+        * pagefault_disable, however that requires a larger audit and
+        * providing helpers like get_user_atomic.
+        */
+       if (!in_atomic() && current->mm)
+               might_lock_read(&current->mm->mmap_sem);
+}
+EXPORT_SYMBOL(might_fault);
+#endif
index 09187517f9dc64804cc80453db0be0a72bcbf922..f97e564bdf118f140e66fb8ad1978d20abf2c939 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2123,6 +2123,8 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
  *
  * @name must be valid until the cache is destroyed. This implies that
  * the module calling this has to destroy the cache before getting unloaded.
+ * Note that kmem_cache_name() is not guaranteed to return the same pointer,
+ * therefore applications must manage it themselves.
  *
  * The flags are
  *
@@ -2609,7 +2611,7 @@ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp,
        if (OFF_SLAB(cachep)) {
                /* Slab management obj is off-slab. */
                slabp = kmem_cache_alloc_node(cachep->slabp_cache,
-                                             local_flags & ~GFP_THISNODE, nodeid);
+                                             local_flags, nodeid);
                if (!slabp)
                        return NULL;
        } else {
@@ -2997,7 +2999,7 @@ retry:
                 * there must be at least one object available for
                 * allocation.
                 */
-               BUG_ON(slabp->inuse < 0 || slabp->inuse >= cachep->num);
+               BUG_ON(slabp->inuse >= cachep->num);
 
                while (slabp->inuse < cachep->num && batchcount--) {
                        STATS_INC_ALLOCED(cachep);
@@ -3106,79 +3108,14 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
 #define cache_alloc_debugcheck_after(a,b,objp,d) (objp)
 #endif
 
-#ifdef CONFIG_FAILSLAB
-
-static struct failslab_attr {
-
-       struct fault_attr attr;
-
-       u32 ignore_gfp_wait;
-#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
-       struct dentry *ignore_gfp_wait_file;
-#endif
-
-} failslab = {
-       .attr = FAULT_ATTR_INITIALIZER,
-       .ignore_gfp_wait = 1,
-};
-
-static int __init setup_failslab(char *str)
-{
-       return setup_fault_attr(&failslab.attr, str);
-}
-__setup("failslab=", setup_failslab);
-
-static int should_failslab(struct kmem_cache *cachep, gfp_t flags)
+static bool slab_should_failslab(struct kmem_cache *cachep, gfp_t flags)
 {
        if (cachep == &cache_cache)
-               return 0;
-       if (flags & __GFP_NOFAIL)
-               return 0;
-       if (failslab.ignore_gfp_wait && (flags & __GFP_WAIT))
-               return 0;
+               return false;
 
-       return should_fail(&failslab.attr, obj_size(cachep));
+       return should_failslab(obj_size(cachep), flags);
 }
 
-#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
-
-static int __init failslab_debugfs(void)
-{
-       mode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
-       struct dentry *dir;
-       int err;
-
-       err = init_fault_attr_dentries(&failslab.attr, "failslab");
-       if (err)
-               return err;
-       dir = failslab.attr.dentries.dir;
-
-       failslab.ignore_gfp_wait_file =
-               debugfs_create_bool("ignore-gfp-wait", mode, dir,
-                                     &failslab.ignore_gfp_wait);
-
-       if (!failslab.ignore_gfp_wait_file) {
-               err = -ENOMEM;
-               debugfs_remove(failslab.ignore_gfp_wait_file);
-               cleanup_fault_attr_dentries(&failslab.attr);
-       }
-
-       return err;
-}
-
-late_initcall(failslab_debugfs);
-
-#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
-
-#else /* CONFIG_FAILSLAB */
-
-static inline int should_failslab(struct kmem_cache *cachep, gfp_t flags)
-{
-       return 0;
-}
-
-#endif /* CONFIG_FAILSLAB */
-
 static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
 {
        void *objp;
@@ -3381,7 +3318,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        unsigned long save_flags;
        void *ptr;
 
-       if (should_failslab(cachep, flags))
+       if (slab_should_failslab(cachep, flags))
                return NULL;
 
        cache_alloc_debugcheck_before(cachep, flags);
@@ -3457,7 +3394,7 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
        unsigned long save_flags;
        void *objp;
 
-       if (should_failslab(cachep, flags))
+       if (slab_should_failslab(cachep, flags))
                return NULL;
 
        cache_alloc_debugcheck_before(cachep, flags);
@@ -3686,9 +3623,9 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
 EXPORT_SYMBOL(__kmalloc_node);
 
 void *__kmalloc_node_track_caller(size_t size, gfp_t flags,
-               int node, void *caller)
+               int node, unsigned long caller)
 {
-       return __do_kmalloc_node(size, flags, node, caller);
+       return __do_kmalloc_node(size, flags, node, (void *)caller);
 }
 EXPORT_SYMBOL(__kmalloc_node_track_caller);
 #else
@@ -3730,9 +3667,9 @@ void *__kmalloc(size_t size, gfp_t flags)
 }
 EXPORT_SYMBOL(__kmalloc);
 
-void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
+void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
 {
-       return __do_kmalloc(size, flags, caller);
+       return __do_kmalloc(size, flags, (void *)caller);
 }
 EXPORT_SYMBOL(__kmalloc_track_caller);
 
index a2cd47d89e0aa1f159d8e9e6ed2dcee32969068f..6cb7ad10785227f2b889bcff96d6610ddeabe37a 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -24,6 +24,7 @@
 #include <linux/kallsyms.h>
 #include <linux/memory.h>
 #include <linux/math64.h>
+#include <linux/fault-inject.h>
 
 /*
  * Lock order:
 #define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
 #endif
 
+#define OO_SHIFT       16
+#define OO_MASK                ((1 << OO_SHIFT) - 1)
+#define MAX_OBJS_PER_PAGE      65535 /* since page.objects is u16 */
+
 /* Internal SLUB flags */
 #define __OBJECT_POISON                0x80000000 /* Poison object */
 #define __SYSFS_ADD_DEFERRED   0x40000000 /* Not yet visible via sysfs */
@@ -178,7 +183,7 @@ static LIST_HEAD(slab_caches);
  * Tracking user of a slab.
  */
 struct track {
-       void *addr;             /* Called from address */
+       unsigned long addr;     /* Called from address */
        int cpu;                /* Was running on cpu */
        int pid;                /* Pid context */
        unsigned long when;     /* When did the operation occur */
@@ -290,7 +295,7 @@ static inline struct kmem_cache_order_objects oo_make(int order,
                                                unsigned long size)
 {
        struct kmem_cache_order_objects x = {
-               (order << 16) + (PAGE_SIZE << order) / size
+               (order << OO_SHIFT) + (PAGE_SIZE << order) / size
        };
 
        return x;
@@ -298,12 +303,12 @@ static inline struct kmem_cache_order_objects oo_make(int order,
 
 static inline int oo_order(struct kmem_cache_order_objects x)
 {
-       return x.x >> 16;
+       return x.x >> OO_SHIFT;
 }
 
 static inline int oo_objects(struct kmem_cache_order_objects x)
 {
-       return x.x & ((1 << 16) - 1);
+       return x.x & OO_MASK;
 }
 
 #ifdef CONFIG_SLUB_DEBUG
@@ -367,7 +372,7 @@ static struct track *get_track(struct kmem_cache *s, void *object,
 }
 
 static void set_track(struct kmem_cache *s, void *object,
-                               enum track_item alloc, void *addr)
+                       enum track_item alloc, unsigned long addr)
 {
        struct track *p;
 
@@ -391,8 +396,8 @@ static void init_tracking(struct kmem_cache *s, void *object)
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
-       set_track(s, object, TRACK_FREE, NULL);
-       set_track(s, object, TRACK_ALLOC, NULL);
+       set_track(s, object, TRACK_FREE, 0UL);
+       set_track(s, object, TRACK_ALLOC, 0UL);
 }
 
 static void print_track(const char *s, struct track *t)
@@ -401,7 +406,7 @@ static void print_track(const char *s, struct track *t)
                return;
 
        printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n",
-               s, t->addr, jiffies - t->when, t->cpu, t->pid);
+               s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid);
 }
 
 static void print_tracking(struct kmem_cache *s, void *object)
@@ -692,7 +697,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
        if (!check_valid_pointer(s, page, get_freepointer(s, p))) {
                object_err(s, page, p, "Freepointer corrupt");
                /*
-                * No choice but to zap it and thus loose the remainder
+                * No choice but to zap it and thus lose the remainder
                 * of the free objects in this slab. May cause
                 * another error because the object count is now wrong.
                 */
@@ -764,8 +769,8 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
        }
 
        max_objects = (PAGE_SIZE << compound_order(page)) / s->size;
-       if (max_objects > 65535)
-               max_objects = 65535;
+       if (max_objects > MAX_OBJS_PER_PAGE)
+               max_objects = MAX_OBJS_PER_PAGE;
 
        if (page->objects != max_objects) {
                slab_err(s, page, "Wrong number of objects. Found %d but "
@@ -866,7 +871,7 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
 }
 
 static int alloc_debug_processing(struct kmem_cache *s, struct page *page,
-                                               void *object, void *addr)
+                                       void *object, unsigned long addr)
 {
        if (!check_slab(s, page))
                goto bad;
@@ -906,7 +911,7 @@ bad:
 }
 
 static int free_debug_processing(struct kmem_cache *s, struct page *page,
-                                               void *object, void *addr)
+                                       void *object, unsigned long addr)
 {
        if (!check_slab(s, page))
                goto fail;
@@ -1029,10 +1034,10 @@ static inline void setup_object_debug(struct kmem_cache *s,
                        struct page *page, void *object) {}
 
 static inline int alloc_debug_processing(struct kmem_cache *s,
-       struct page *page, void *object, void *addr) { return 0; }
+       struct page *page, void *object, unsigned long addr) { return 0; }
 
 static inline int free_debug_processing(struct kmem_cache *s,
-       struct page *page, void *object, void *addr) { return 0; }
+       struct page *page, void *object, unsigned long addr) { return 0; }
 
 static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
                        { return 1; }
@@ -1499,8 +1504,8 @@ static inline int node_match(struct kmem_cache_cpu *c, int node)
  * we need to allocate a new slab. This is the slowest path since it involves
  * a call to the page allocator and the setup of a new slab.
  */
-static void *__slab_alloc(struct kmem_cache *s,
-               gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c)
+static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
+                         unsigned long addr, struct kmem_cache_cpu *c)
 {
        void **object;
        struct page *new;
@@ -1584,13 +1589,18 @@ debug:
  * Otherwise we can simply pick the next object from the lockless free list.
  */
 static __always_inline void *slab_alloc(struct kmem_cache *s,
-               gfp_t gfpflags, int node, void *addr)
+               gfp_t gfpflags, int node, unsigned long addr)
 {
        void **object;
        struct kmem_cache_cpu *c;
        unsigned long flags;
        unsigned int objsize;
 
+       might_sleep_if(gfpflags & __GFP_WAIT);
+
+       if (should_failslab(s->objsize, gfpflags))
+               return NULL;
+
        local_irq_save(flags);
        c = get_cpu_slab(s, smp_processor_id());
        objsize = c->objsize;
@@ -1613,14 +1623,14 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
 
 void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 {
-       return slab_alloc(s, gfpflags, -1, __builtin_return_address(0));
+       return slab_alloc(s, gfpflags, -1, _RET_IP_);
 }
 EXPORT_SYMBOL(kmem_cache_alloc);
 
 #ifdef CONFIG_NUMA
 void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
 {
-       return slab_alloc(s, gfpflags, node, __builtin_return_address(0));
+       return slab_alloc(s, gfpflags, node, _RET_IP_);
 }
 EXPORT_SYMBOL(kmem_cache_alloc_node);
 #endif
@@ -1634,7 +1644,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_node);
  * handling required then we can return immediately.
  */
 static void __slab_free(struct kmem_cache *s, struct page *page,
-                               void *x, void *addr, unsigned int offset)
+                       void *x, unsigned long addr, unsigned int offset)
 {
        void *prior;
        void **object = (void *)x;
@@ -1704,7 +1714,7 @@ debug:
  * with all sorts of special processing.
  */
 static __always_inline void slab_free(struct kmem_cache *s,
-                       struct page *page, void *x, void *addr)
+                       struct page *page, void *x, unsigned long addr)
 {
        void **object = (void *)x;
        struct kmem_cache_cpu *c;
@@ -1731,11 +1741,11 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
 
        page = virt_to_head_page(x);
 
-       slab_free(s, page, x, __builtin_return_address(0));
+       slab_free(s, page, x, _RET_IP_);
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
-/* Figure out on which slab object the object resides */
+/* Figure out on which slab page the object resides */
 static struct page *get_object_page(const void *x)
 {
        struct page *page = virt_to_head_page(x);
@@ -1807,8 +1817,8 @@ static inline int slab_order(int size, int min_objects,
        int rem;
        int min_order = slub_min_order;
 
-       if ((PAGE_SIZE << min_order) / size > 65535)
-               return get_order(size * 65535) - 1;
+       if ((PAGE_SIZE << min_order) / size > MAX_OBJS_PER_PAGE)
+               return get_order(size * MAX_OBJS_PER_PAGE) - 1;
 
        for (order = max(min_order,
                                fls(min_objects * size - 1) - PAGE_SHIFT);
@@ -2073,8 +2083,7 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s, gfp_t flags)
  * when allocating for the kmalloc_node_cache. This is used for bootstrapping
  * memory on a fresh node that has no slab structures yet.
  */
-static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags,
-                                                          int node)
+static void early_kmem_cache_node_alloc(gfp_t gfpflags, int node)
 {
        struct page *page;
        struct kmem_cache_node *n;
@@ -2112,7 +2121,6 @@ static struct kmem_cache_node *early_kmem_cache_node_alloc(gfp_t gfpflags,
        local_irq_save(flags);
        add_partial(n, page, 0);
        local_irq_restore(flags);
-       return n;
 }
 
 static void free_kmem_cache_nodes(struct kmem_cache *s)
@@ -2144,8 +2152,7 @@ static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
                        n = &s->local_node;
                else {
                        if (slab_state == DOWN) {
-                               n = early_kmem_cache_node_alloc(gfpflags,
-                                                               node);
+                               early_kmem_cache_node_alloc(gfpflags, node);
                                continue;
                        }
                        n = kmem_cache_alloc_node(kmalloc_caches,
@@ -2659,7 +2666,7 @@ void *__kmalloc(size_t size, gfp_t flags)
        if (unlikely(ZERO_OR_NULL_PTR(s)))
                return s;
 
-       return slab_alloc(s, flags, -1, __builtin_return_address(0));
+       return slab_alloc(s, flags, -1, _RET_IP_);
 }
 EXPORT_SYMBOL(__kmalloc);
 
@@ -2687,7 +2694,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
        if (unlikely(ZERO_OR_NULL_PTR(s)))
                return s;
 
-       return slab_alloc(s, flags, node, __builtin_return_address(0));
+       return slab_alloc(s, flags, node, _RET_IP_);
 }
 EXPORT_SYMBOL(__kmalloc_node);
 #endif
@@ -2744,7 +2751,7 @@ void kfree(const void *x)
                put_page(page);
                return;
        }
-       slab_free(page->slab, page, object, __builtin_return_address(0));
+       slab_free(page->slab, page, object, _RET_IP_);
 }
 EXPORT_SYMBOL(kfree);
 
@@ -3123,8 +3130,12 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
                up_write(&slub_lock);
 
-               if (sysfs_slab_alias(s, name))
+               if (sysfs_slab_alias(s, name)) {
+                       down_write(&slub_lock);
+                       s->refcount--;
+                       up_write(&slub_lock);
                        goto err;
+               }
                return s;
        }
 
@@ -3134,8 +3145,13 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                                size, align, flags, ctor)) {
                        list_add(&s->list, &slab_caches);
                        up_write(&slub_lock);
-                       if (sysfs_slab_add(s))
+                       if (sysfs_slab_add(s)) {
+                               down_write(&slub_lock);
+                               list_del(&s->list);
+                               up_write(&slub_lock);
+                               kfree(s);
                                goto err;
+                       }
                        return s;
                }
                kfree(s);
@@ -3202,7 +3218,7 @@ static struct notifier_block __cpuinitdata slab_notifier = {
 
 #endif
 
-void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
+void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
 {
        struct kmem_cache *s;
 
@@ -3218,7 +3234,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
 }
 
 void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
-                                       int node, void *caller)
+                                       int node, unsigned long caller)
 {
        struct kmem_cache *s;
 
@@ -3429,7 +3445,7 @@ static void resiliency_test(void) {};
 
 struct location {
        unsigned long count;
-       void *addr;
+       unsigned long addr;
        long long sum_time;
        long min_time;
        long max_time;
@@ -3477,7 +3493,7 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
 {
        long start, end, pos;
        struct location *l;
-       void *caddr;
+       unsigned long caddr;
        unsigned long age = jiffies - track->when;
 
        start = -1;
@@ -4345,7 +4361,7 @@ static void sysfs_slab_remove(struct kmem_cache *s)
 
 /*
  * Need to buffer aliases during bootup until sysfs becomes
- * available lest we loose that information.
+ * available lest we lose that information.
  */
 struct saved_alias {
        struct kmem_cache *s;
index 446424027d245d6a9583e0da918e09e3d3241d3a..09c66a449da6c7c72c1bca4bfb8e392281d84bbb 100644 (file)
@@ -5066,13 +5066,14 @@ static struct pernet_operations __net_initdata netdev_net_ops = {
 
 static void __net_exit default_device_exit(struct net *net)
 {
-       struct net_device *dev, *next;
+       struct net_device *dev;
        /*
         * Push all migratable of the network devices back to the
         * initial network namespace
         */
        rtnl_lock();
-       for_each_netdev_safe(net, dev, next) {
+restart:
+       for_each_netdev(net, dev) {
                int err;
                char fb_name[IFNAMSIZ];
 
@@ -5083,7 +5084,7 @@ static void __net_exit default_device_exit(struct net *net)
                /* Delete virtual devices */
                if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) {
                        dev->rtnl_link_ops->dellink(dev);
-                       continue;
+                       goto restart;
                }
 
                /* Push remaing network devices to init_net */
@@ -5094,6 +5095,7 @@ static void __net_exit default_device_exit(struct net *net)
                                __func__, dev->name, err);
                        BUG();
                }
+               goto restart;
        }
        rtnl_unlock();
 }
index 9c3717a23cf76648bd17452bb422f32b91b26ce1..f66c58df8953e8b3f642830aae5f88230eb3aeec 100644 (file)
@@ -2414,7 +2414,7 @@ static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
@@ -2429,7 +2429,7 @@ static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct neigh_table *tbl = pde->data;
        int cpu;
 
-       for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
index d5c2bacb713c6055ffb9a3ca9cb8975ebb907a9a..1747ccae8e8d098f50232253e7be60a40867848f 100644 (file)
@@ -964,7 +964,6 @@ adjudge_to_death:
        state = sk->sk_state;
        sock_hold(sk);
        sock_orphan(sk);
-       percpu_counter_inc(sk->sk_prot->orphan_count);
 
        /*
         * It is the last release_sock in its life. It will remove backlog.
@@ -978,6 +977,8 @@ adjudge_to_death:
        bh_lock_sock(sk);
        WARN_ON(sock_owned_by_user(sk));
 
+       percpu_counter_inc(sk->sk_prot->orphan_count);
+
        /* Have we already been destroyed by a softirq or backlog? */
        if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
                goto out;
index c7cda1ca8e6571232d1cf22c576a2c998983a08a..f26ab38680de00a5b77c303e34774a078022d499 100644 (file)
@@ -633,8 +633,6 @@ void inet_csk_listen_stop(struct sock *sk)
 
                acc_req = req->dl_next;
 
-               percpu_counter_inc(sk->sk_prot->orphan_count);
-
                local_bh_disable();
                bh_lock_sock(child);
                WARN_ON(sock_owned_by_user(child));
@@ -644,6 +642,8 @@ void inet_csk_listen_stop(struct sock *sk)
 
                sock_orphan(child);
 
+               percpu_counter_inc(sk->sk_prot->orphan_count);
+
                inet_csk_destroy_sock(child);
 
                bh_unlock_sock(child);
index 313ebf00ee36a0fe1d42a20a87c20e508af4fa52..6ba5c557690c439f55f44013da1f6e50a985db07 100644 (file)
@@ -291,7 +291,7 @@ static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
@@ -306,7 +306,7 @@ static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct net *net = seq_file_net(seq);
        int cpu;
 
-       for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
index 614958b7c27695aa6ed2a60822dd759b64648214..eb62e58bff7922b0e62d8f883da79fc0a8bee53b 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/udplite.h>
+#include <linux/bottom_half.h>
 #include <linux/inetdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 static int sockstat_seq_show(struct seq_file *seq, void *v)
 {
        struct net *net = seq->private;
+       int orphans, sockets;
+
+       local_bh_disable();
+       orphans = percpu_counter_sum_positive(&tcp_orphan_count),
+       sockets = percpu_counter_sum_positive(&tcp_sockets_allocated),
+       local_bh_enable();
 
        socket_seq_show(seq);
        seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
-                  sock_prot_inuse_get(net, &tcp_prot),
-                  (int)percpu_counter_sum_positive(&tcp_orphan_count),
-                  tcp_death_row.tw_count,
-                  (int)percpu_counter_sum_positive(&tcp_sockets_allocated),
+                  sock_prot_inuse_get(net, &tcp_prot), orphans,
+                  tcp_death_row.tw_count, sockets,
                   atomic_read(&tcp_memory_allocated));
        seq_printf(seq, "UDP: inuse %d mem %d\n",
                   sock_prot_inuse_get(net, &udp_prot),
index 77bfba975959efcd52047656281101adaa185ffc..97f71153584faa6bf379235f0db151e17a5ed4e9 100644 (file)
@@ -429,7 +429,7 @@ static void *rt_cpu_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
@@ -442,7 +442,7 @@ static void *rt_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        int cpu;
 
-       for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu+1;
index 1f3d52946b3b84f604385fb5542390bb6b593ce1..f28acf11fc67d419bc0ccab57510c8bcedee1c3e 100644 (file)
@@ -1836,7 +1836,6 @@ adjudge_to_death:
        state = sk->sk_state;
        sock_hold(sk);
        sock_orphan(sk);
-       percpu_counter_inc(sk->sk_prot->orphan_count);
 
        /* It is the last release_sock in its life. It will remove backlog. */
        release_sock(sk);
@@ -1849,6 +1848,8 @@ adjudge_to_death:
        bh_lock_sock(sk);
        WARN_ON(sock_owned_by_user(sk));
 
+       percpu_counter_inc(sk->sk_prot->orphan_count);
+
        /* Have we already been destroyed by a softirq or backlog? */
        if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE)
                goto out;
index 10172487921b944d3f82b1d527b4674a9af449a4..9d839fa9331e5845c39b22d07d9d3a93f39634d3 100644 (file)
@@ -51,6 +51,7 @@
  */
 
 
+#include <linux/bottom_half.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/module.h>
@@ -1797,7 +1798,9 @@ static int tcp_v4_init_sock(struct sock *sk)
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
        sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
+       local_bh_disable();
        percpu_counter_inc(&tcp_sockets_allocated);
+       local_bh_enable();
 
        return 0;
 }
index 8702b06cb60a9dbe6b1d7490bd30656ed79e141c..e8b8337a83107d8a2ccafeac7a6539c1a7621d38 100644 (file)
@@ -23,6 +23,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#include <linux/bottom_half.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -1830,7 +1831,9 @@ static int tcp_v6_init_sock(struct sock *sk)
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
        sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
+       local_bh_disable();
        percpu_counter_inc(&tcp_sockets_allocated);
+       local_bh_enable();
 
        return 0;
 }
index 9394f539966aea9f91dd37a6165969d31b5a8ee8..3eb5e2660c49265cf3bd1dc3533c263f53c5c650 100644 (file)
@@ -507,7 +507,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
        /* No cache entry or it is invalid, time to schedule */
        dest = __ip_vs_lblc_schedule(svc);
        if (!dest) {
-               IP_VS_DBG(1, "no destination available\n");
+               IP_VS_ERR_RL("LBLC: no destination available\n");
                return NULL;
        }
 
index 92dc76a6842cc101a1f14afed07ae65841d10440..c04ce56c7f0fca0d9e257cd5bef6d59b16d45655 100644 (file)
@@ -690,7 +690,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                /* The cache entry is invalid, time to schedule */
                dest = __ip_vs_lblcr_schedule(svc);
                if (!dest) {
-                       IP_VS_DBG(1, "no destination available\n");
+                       IP_VS_ERR_RL("LBLCR: no destination available\n");
                        read_unlock(&svc->sched_lock);
                        return NULL;
                }
index 51912cab777bb5349012709639c1efa1ff774005..d0dadc8a65fda50d8b26d1e64f66d8c1a854baa0 100644 (file)
@@ -66,11 +66,15 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                }
        }
 
-       if (least)
-       IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d inactconns %d\n",
-                     IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port),
-                     atomic_read(&least->activeconns),
-                     atomic_read(&least->inactconns));
+       if (!least)
+               IP_VS_ERR_RL("LC: no destination available\n");
+       else
+               IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d "
+                             "inactconns %d\n",
+                             IP_VS_DBG_ADDR(svc->af, &least->addr),
+                             ntohs(least->port),
+                             atomic_read(&least->activeconns),
+                             atomic_read(&least->inactconns));
 
        return least;
 }
index 6758ad2ceaaf66130f881ff672cc0d9444d1416a..694952db502601156dbcd0ca8b02c72034b0ecbf 100644 (file)
@@ -95,8 +95,10 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                }
        }
 
-       if (!least)
+       if (!least) {
+               IP_VS_ERR_RL("NQ: no destination available\n");
                return NULL;
+       }
 
   out:
        IP_VS_DBG_BUF(6, "NQ: server %s:%u "
index 8fb51c169eb852daeb9e1117fde96f07a9d2b595..2d16ab7f8c1ec11ea2b284829036e57c2cbac8a8 100644 (file)
@@ -69,6 +69,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                q = q->next;
        } while (q != p);
        write_unlock(&svc->sched_lock);
+       IP_VS_ERR_RL("RR: no destination available\n");
        return NULL;
 
   out:
index 691a6a0086e18c90f2b0548951b1218fc9a4958f..20e4657d2f3bb0e3ae2d902669baaf322f4d1b7d 100644 (file)
@@ -84,6 +84,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                        goto nextstage;
                }
        }
+       IP_VS_ERR_RL("SED: no destination available\n");
        return NULL;
 
        /*
index 0e53955ef1396ec0d157163eb66ab00f2e590506..75709ebeb630384893fb56ef4c22d4df9b3a3eb0 100644 (file)
@@ -219,6 +219,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
            || !(dest->flags & IP_VS_DEST_F_AVAILABLE)
            || atomic_read(&dest->weight) <= 0
            || is_overloaded(dest)) {
+               IP_VS_ERR_RL("SH: no destination available\n");
                return NULL;
        }
 
index 57b452bbb4eab71f106e5e56f23259b3df7b18d8..8e942565b47de8ad75e994dac1525be4ccf617a1 100644 (file)
@@ -72,6 +72,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                        goto nextstage;
                }
        }
+       IP_VS_ERR_RL("WLC: no destination available\n");
        return NULL;
 
        /*
index 2f618dc29c5b69468b21ded446b13f18c1efebab..f7d74ef1ecf99a9735b2bfce87f00e2458a457b6 100644 (file)
@@ -155,6 +155,8 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
 
                        if (mark->cl == mark->cl->next) {
                                /* no dest entry */
+                               IP_VS_ERR_RL("WRR: no destination available: "
+                                            "no destinations present\n");
                                dest = NULL;
                                goto out;
                        }
@@ -168,8 +170,8 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                                 */
                                if (mark->cw == 0) {
                                        mark->cl = &svc->destinations;
-                                       IP_VS_ERR_RL("ip_vs_wrr_schedule(): "
-                                                  "no available servers\n");
+                                       IP_VS_ERR_RL("WRR: no destination "
+                                                    "available\n");
                                        dest = NULL;
                                        goto out;
                                }
@@ -191,6 +193,8 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
                        /* back to the start, and no dest is found.
                           It is only possible when all dests are OVERLOADED */
                        dest = NULL;
+                       IP_VS_ERR_RL("WRR: no destination available: "
+                                    "all destinations are overloaded\n");
                        goto out;
                }
        }
index f37b9b74c6a8c78ea372569d4ffba09f69be9f9d..4da54b0b92339b61b242b51fdcab4bc1db32233c 100644 (file)
@@ -200,7 +200,7 @@ static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu + 1;
@@ -215,7 +215,7 @@ static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct net *net = seq_file_net(seq);
        int cpu;
 
-       for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
+       for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
                if (!cpu_possible(cpu))
                        continue;
                *pos = cpu + 1;
index 4f7ef0db302b56eaf1e32c2d7ce90c84d686be51..929218a4762060ee2052370eb70fe955c418211a 100644 (file)
@@ -335,9 +335,6 @@ config NET_CLS_CGROUP
          Say Y here if you want to classify packets based on the control
          cgroup of their process.
 
-         To compile this code as a module, choose M here: the
-         module will be called cls_cgroup.
-
 config NET_EMATCH
        bool "Extended Matches"
        select NET_CLS
index 0d68b1975983a323775b5c4deef4f2ae1ae8ae5d..91a3db4a76f837ae88d28d65012c073f5049ac61 100644 (file)
@@ -24,10 +24,16 @@ struct cgroup_cls_state
        u32 classid;
 };
 
-static inline struct cgroup_cls_state *net_cls_state(struct cgroup *cgrp)
+static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp)
 {
-       return (struct cgroup_cls_state *)
-               cgroup_subsys_state(cgrp, net_cls_subsys_id);
+       return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id),
+                           struct cgroup_cls_state, css);
+}
+
+static inline struct cgroup_cls_state *task_cls_state(struct task_struct *p)
+{
+       return container_of(task_subsys_state(p, net_cls_subsys_id),
+                           struct cgroup_cls_state, css);
 }
 
 static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
@@ -39,19 +45,19 @@ static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss,
                return ERR_PTR(-ENOMEM);
 
        if (cgrp->parent)
-               cs->classid = net_cls_state(cgrp->parent)->classid;
+               cs->classid = cgrp_cls_state(cgrp->parent)->classid;
 
        return &cs->css;
 }
 
 static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp)
 {
-       kfree(ss);
+       kfree(cgrp_cls_state(cgrp));
 }
 
 static u64 read_classid(struct cgroup *cgrp, struct cftype *cft)
 {
-       return net_cls_state(cgrp)->classid;
+       return cgrp_cls_state(cgrp)->classid;
 }
 
 static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value)
@@ -59,7 +65,7 @@ static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value)
        if (!cgroup_lock_live_group(cgrp))
                return -ENODEV;
 
-       net_cls_state(cgrp)->classid = (u32) value;
+       cgrp_cls_state(cgrp)->classid = (u32) value;
 
        cgroup_unlock();
 
@@ -115,8 +121,7 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
                return -1;
 
        rcu_read_lock();
-       cs = (struct cgroup_cls_state *) task_subsys_state(current,
-                                                          net_cls_subsys_id);
+       cs = task_cls_state(current);
        if (cs->classid && tcf_em_tree_match(skb, &head->ematches, NULL)) {
                res->classid = cs->classid;
                res->class = 0;
index 284eaef1dbf22f49babc1d76f2e35814a874cedc..a2adb51849a96c44940303af878bf6a1316b716a 100644 (file)
@@ -44,27 +44,14 @@ static struct snmp_mib xfrm_mib_list[] = {
        SNMP_MIB_SENTINEL
 };
 
-static unsigned long
-fold_field(void *mib[], int offt)
-{
-        unsigned long res = 0;
-        int i;
-
-        for_each_possible_cpu(i) {
-                res += *(((unsigned long *)per_cpu_ptr(mib[0], i)) + offt);
-                res += *(((unsigned long *)per_cpu_ptr(mib[1], i)) + offt);
-        }
-        return res;
-}
-
 static int xfrm_statistics_seq_show(struct seq_file *seq, void *v)
 {
        struct net *net = seq->private;
        int i;
        for (i=0; xfrm_mib_list[i].name; i++)
                seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name,
-                          fold_field((void **)net->mib.xfrm_statistics,
-                                     xfrm_mib_list[i].entry));
+                          snmp_fold_field((void **)net->mib.xfrm_statistics,
+                                          xfrm_mib_list[i].entry));
        return 0;
 }
 
index 7c72baa02f2e93ff09c76be260201da3315e32e5..6688765bd8b96fcf927db7590a7e1fb5ab3bed1a 100644 (file)
@@ -838,11 +838,11 @@ static long get_instantiation_keyring(key_serial_t ringid,
 {
        key_ref_t dkref;
 
+       *_dest_keyring = NULL;
+
        /* just return a NULL pointer if we weren't asked to make a link */
-       if (ringid == 0) {
-               *_dest_keyring = NULL;
+       if (ringid == 0)
                return 0;
-       }
 
        /* if a specific keyring is nominated by ID, then use that */
        if (ringid > 0) {
index 34c1d94f921e1285238cbcbfae13ab9eab10f04f..ef6539eea5793c94b98b2072c0059efc31f9903f 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
-#include <mach/pxa-regs.h>
+#include <mach/regs-ac97.h>
 #include <mach/pxa2xx-gpio.h>
 #include <mach/audio.h>
 
index c2635beb4c8897e01d5aa9f2a3213f58717cbfc4..85cf591d4e11d594d96ac970ec1bed41d473bbb2 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
+#include <mach/regs-ac97.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
index 5c4a4d38a08399c1df3a60ea3bf02e78c70998cf..65f86b56ba422a2c28c6d0c70c731c6250df7c63 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 struct pxa2xx_runtime_data {
        int dma_ch;
index c1d285921f807cc6ce1b626a87d2cf6684ecf89d..34c7d48f5061b9fd2025a23e78ac63c4bcd3fd55 100644 (file)
@@ -57,7 +57,6 @@ static int snd_hrtimer_open(struct snd_timer *t)
                return -ENOMEM;
        hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        stime->timer = t;
-       stime->hrt.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
        stime->hrt.function = snd_hrtimer_callback;
        t->private_data = stime;
        return 0;
index 2a02f704f366b31c58947e3d409cf5fd5212d06c..a4049eb94d35a28bafa41072e6e44af726d6f251 100644 (file)
@@ -96,7 +96,6 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
                return -EINVAL;
 
        hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
        pcsp_chip.timer.function = pcsp_do_timer;
 
        card = snd_card_new(index, id, THIS_MODULE, 0);
index c13a178383ba0215e3edf14fca8d902973c88cc6..549b4eba14963d3b624acac71fad8fc8ce491957 100644 (file)
@@ -18,7 +18,7 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- */      
+ */
 
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -89,7 +89,7 @@ static int snd_tea575x_ioctl(struct inode *inode, struct file *file,
 {
        struct snd_tea575x *tea = video_drvdata(file);
        void __user *arg = (void __user *)data;
-       
+
        switch(cmd) {
                case VIDIOCGCAP:
                {
@@ -110,9 +110,9 @@ static int snd_tea575x_ioctl(struct inode *inode, struct file *file,
                case VIDIOCGTUNER:
                {
                        struct video_tuner v;
-                       if (copy_from_user(&v, arg,sizeof(v))!=0) 
+                       if (copy_from_user(&v, arg,sizeof(v))!=0)
                                return -EFAULT;
-                       if (v.tuner)    /* Only 1 tuner */ 
+                       if (v.tuner)    /* Only 1 tuner */
                                return -EINVAL;
                        v.rangelow = (87*16000);
                        v.rangehigh = (108*16000);
@@ -144,24 +144,24 @@ static int snd_tea575x_ioctl(struct inode *inode, struct file *file,
                        snd_tea575x_set_freq(tea);
                        return 0;
                case VIDIOCGAUDIO:
-               {       
+               {
                        struct video_audio v;
                        memset(&v, 0, sizeof(v));
                        strcpy(v.name, "Radio");
                        if(copy_to_user(arg,&v, sizeof(v)))
                                return -EFAULT;
-                       return 0;                       
+                       return 0;
                }
                case VIDIOCSAUDIO:
                {
                        struct video_audio v;
-                       if(copy_from_user(&v, arg, sizeof(v))) 
-                               return -EFAULT; 
+                       if(copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
                        if (tea->ops->mute)
                                tea->ops->mute(tea,
                                               (v.flags &
                                                VIDEO_AUDIO_MUTE) ? 1 : 0);
-                       if(v.audio) 
+                       if(v.audio)
                                return -EINVAL;
                        return 0;
                }
@@ -240,11 +240,11 @@ static int __init alsa_tea575x_module_init(void)
 {
        return 0;
 }
-        
+
 static void __exit alsa_tea575x_module_exit(void)
 {
 }
-        
+
 module_init(alsa_tea575x_module_init)
 module_exit(alsa_tea575x_module_exit)
 
index c47842fad6575852a769bcb4ecf5f3c657d8455d..2c63bb9da74a019a5df655e7960aa0c4b893b670 100644 (file)
@@ -1483,16 +1483,14 @@ static void __exit unload_waveartist(struct address_info *hw)
 #define VNC_HANDSET_DETECT     0x40
 #define VNC_DISABLE_AUTOSWITCH 0x80
 
-extern spinlock_t gpio_lock;
-
 static inline void
 vnc_mute_spkr(wavnc_info *devc)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&gpio_lock, flags);
-       cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE);
-       spin_unlock_irqrestore(&gpio_lock, flags);
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       nw_cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
 }
 
 static void
index 780db6757ad2ee4990887a78cc4485493ecab2b6..812c2b4d3e070d3357d06ce599a3e8025fba4211 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
+#include <mach/regs-ac97.h>
 
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-ac97.h"
index 1bfce40bb2e457a56eea42ec6d78a2ad15cffd6a..5822d2dd49ba9c1d2acbc6dee0c4c9b6c6777247 100644 (file)
@@ -28,7 +28,7 @@
 #include <sound/soc.h>
 
 #include <mach/hardware.h>
-#include <asm/plat-s3c/regs-ac97.h>
+#include <plat/regs-ac97.h>
 #include <mach/regs-gpio.h>
 #include <mach/regs-clock.h>
 #include <mach/audio.h>